diff --git a/src/vnsw/agent/oper/vm_interface.cc b/src/vnsw/agent/oper/vm_interface.cc index bb21d14448f..6bc3658c942 100644 --- a/src/vnsw/agent/oper/vm_interface.cc +++ b/src/vnsw/agent/oper/vm_interface.cc @@ -60,8 +60,8 @@ VmInterface::VmInterface(const boost::uuids::uuid &uuid) : primary_ip6_addr_(), vm_mac_(MacAddress::kZeroMac), policy_enabled_(false), mirror_entry_(NULL), mirror_direction_(MIRROR_RX_TX), cfg_name_(""), fabric_port_(true), need_linklocal_ip_(false), drop_new_flows_(false), - dhcp_enable_(true), do_dhcp_relay_(false), vm_name_(), - vm_project_uuid_(nil_uuid()), vxlan_id_(0), bridging_(false), + dhcp_enable_(true), do_dhcp_relay_(false), proxy_arp_mode_(PROXY_ARP_NONE), + vm_name_(), vm_project_uuid_(nil_uuid()), vxlan_id_(0), bridging_(false), layer3_forwarding_(true), flood_unknown_unicast_(false), mac_set_(false), ecmp_(false), ecmp6_(false), disable_policy_(false), tx_vlan_id_(kInvalidVlanId), rx_vlan_id_(kInvalidVlanId), parent_(NULL), @@ -99,8 +99,8 @@ VmInterface::VmInterface(const boost::uuids::uuid &uuid, primary_ip6_addr_(a6), vm_mac_(mac), policy_enabled_(false), mirror_entry_(NULL), mirror_direction_(MIRROR_RX_TX), cfg_name_(""), fabric_port_(true), need_linklocal_ip_(false), drop_new_flows_(false), - dhcp_enable_(true), do_dhcp_relay_(false), vm_name_(vm_name), - vm_project_uuid_(vm_project_uuid), vxlan_id_(0), + dhcp_enable_(true), do_dhcp_relay_(false), proxy_arp_mode_(PROXY_ARP_NONE), + vm_name_(vm_name), vm_project_uuid_(vm_project_uuid), vxlan_id_(0), bridging_(false), layer3_forwarding_(true), flood_unknown_unicast_(false), mac_set_(false), ecmp_(false), ecmp6_(false), disable_policy_(false), @@ -536,6 +536,33 @@ static void BuildVrfAndServiceVlanInfo(Agent *agent, return; } +// Build proxy-arp flag on VMI +// In future, we expect a proxy-arp flag on VMI. In the meanwhile, we want +// to enable proxy-arp on following, +// 1. Left and right interface of transparent service-chain +// 2. Left and right interface of in-network service-chain +// 3. Left interface of in-network-nat service-chain +// +// The common attribute for all these interface are, +// - They have vrf-assign rules +// - They have service-interface-type attribute +// +// Note: Right interface of in-network-nat will not have vrf-assign +static void BuildProxyArpFlags(Agent *agent, VmInterfaceConfigData *data, + VirtualMachineInterface *cfg) { + data->proxy_arp_mode_ = VmInterface::PROXY_ARP_NONE; + if (cfg->vrf_assign_table().size() == 0) + return; + + // Proxy-mode valid only on left or right interface os SI + if (cfg->properties().service_interface_type != "left" && + cfg->properties().service_interface_type != "right") { + return; + } + + data->proxy_arp_mode_ = VmInterface::PROXY_ARP_UNRESTRICTED; +} + static void BuildFatFlowTable(Agent *agent, VmInterfaceConfigData *data, IFMapNode *node) { VirtualMachineInterface *cfg = static_cast @@ -964,6 +991,7 @@ static void BuildAttributes(Agent *agent, IFMapNode *node, data->vm_mac_ = cfg->mac_addresses().at(0); } data->disable_policy_ = cfg->disable_policy(); + BuildProxyArpFlags(agent, data, cfg); } static void UpdateAttributes(Agent *agent, VmInterfaceConfigData *data) { @@ -1913,7 +1941,8 @@ VmInterfaceConfigData::VmInterfaceConfigData(Agent *agent, IFMapNode *node) : cfg_name_(""), vm_uuid_(), vm_name_(), vn_uuid_(), vrf_name_(""), fabric_port_(true), need_linklocal_ip_(false), bridging_(true), layer3_forwarding_(true), mirror_enable_(false), ecmp_(false), - ecmp6_(false), dhcp_enable_(true), admin_state_(true), + ecmp6_(false), dhcp_enable_(true), + proxy_arp_mode_(VmInterface::PROXY_ARP_NONE), admin_state_(true), disable_policy_(false), analyzer_name_(""), local_preference_(VmInterface::INVALID), oper_dhcp_options_(), mirror_direction_(Interface::UNKNOWN), sg_list_(), @@ -2150,6 +2179,11 @@ bool VmInterface::CopyConfig(const InterfaceTable *table, ret = true; } + if (proxy_arp_mode_ != data->proxy_arp_mode_) { + proxy_arp_mode_ = data->proxy_arp_mode_; + ret = true; + } + if (disable_policy_ != data->disable_policy_) { disable_policy_ = data->disable_policy_; ret = true; diff --git a/src/vnsw/agent/oper/vm_interface.h b/src/vnsw/agent/oper/vm_interface.h index 61330e28ec6..804422a19df 100644 --- a/src/vnsw/agent/oper/vm_interface.h +++ b/src/vnsw/agent/oper/vm_interface.h @@ -93,6 +93,12 @@ class VmInterface : public Interface { SRIOV }; + enum ProxyArpMode { + PROXY_ARP_NONE, + PROXY_ARP_UNRESTRICTED, + PROXY_ARP_INVALID + }; + struct ListEntry { ListEntry() : installed_(false), del_pending_(false) { } ListEntry(bool installed, bool del_pending) : @@ -528,6 +534,10 @@ class VmInterface : public Interface { dhcp_enable_= dhcp_enable; } bool do_dhcp_relay() const { return do_dhcp_relay_; } + ProxyArpMode proxy_arp_mode() const { return proxy_arp_mode_; } + bool IsUnrestrictedProxyArp() const { + return proxy_arp_mode_ == PROXY_ARP_UNRESTRICTED; + } int vxlan_id() const { return vxlan_id_; } bool bridging() const { return bridging_; } bool layer3_forwarding() const { return layer3_forwarding_; } @@ -907,6 +917,8 @@ class VmInterface : public Interface { bool dhcp_enable_; // true if IP is to be obtained from DHCP Relay and not learnt from fabric bool do_dhcp_relay_; + // Proxy ARP mode for interface + ProxyArpMode proxy_arp_mode_; // VM-Name. Used by DNS std::string vm_name_; // project uuid of the vm to which the interface belongs @@ -1103,6 +1115,7 @@ struct VmInterfaceConfigData : public VmInterfaceData { bool ecmp_; bool ecmp6_; bool dhcp_enable_; // is DHCP enabled for the interface (from subnet config) + VmInterface::ProxyArpMode proxy_arp_mode_; bool admin_state_; bool disable_policy_; std::string analyzer_name_; diff --git a/src/vnsw/agent/pkt/test/test_vrf_assign_acl.cc b/src/vnsw/agent/pkt/test/test_vrf_assign_acl.cc index dde135fea14..4fdc15a2dcc 100644 --- a/src/vnsw/agent/pkt/test/test_vrf_assign_acl.cc +++ b/src/vnsw/agent/pkt/test/test_vrf_assign_acl.cc @@ -548,6 +548,28 @@ TEST_F(TestVrfAssignAclFlow, VrfAssignAclWithMirror2) { client->WaitForIdle(); } +TEST_F(TestVrfAssignAclFlow, Vmi_Proxy_Arp_1) { + AddAddressVrfAssignAcl("intf1", 1, "1.1.1.0", "2.1.1.0", 6, 1, 65535, + 1, 65535, "default-project:vn2:vn2", "true"); + const VmInterface *vmi = static_cast(VmPortGet(1)); + EXPECT_EQ(vmi->proxy_arp_mode(), VmInterface::PROXY_ARP_NONE); + + AddAddressVrfAssignAcl("intf1", 1, "1.1.1.0", "2.1.1.0", 6, 1, 65535, + 1, 65535, "default-project:vn2:vn2", "true", "left"); + EXPECT_EQ(vmi->proxy_arp_mode(), VmInterface::PROXY_ARP_UNRESTRICTED); + + AddAddressVrfAssignAcl("intf1", 1, "1.1.1.0", "2.1.1.0", 6, 1, 65535, + 1, 65535, "default-project:vn2:vn2", "true", "right"); + EXPECT_EQ(vmi->proxy_arp_mode(), VmInterface::PROXY_ARP_UNRESTRICTED); + + AddAddressVrfAssignAcl("intf1", 1, "1.1.1.0", "2.1.1.0", 6, 1, 65535, + 1, 65535, "default-project:vn2:vn2", "true", "management"); + EXPECT_EQ(vmi->proxy_arp_mode(), VmInterface::PROXY_ARP_NONE); + + CreateVmportFIpEnv(input, 2); + EXPECT_EQ(vmi->proxy_arp_mode(), VmInterface::PROXY_ARP_NONE); +} + int main(int argc, char *argv[]) { GETUSERARGS(); client = TestInit(init_file, ksync_init); diff --git a/src/vnsw/agent/test/test_cmn_util.h b/src/vnsw/agent/test/test_cmn_util.h index 1786b3176f3..2f54fc41fc0 100644 --- a/src/vnsw/agent/test/test_cmn_util.h +++ b/src/vnsw/agent/test/test_cmn_util.h @@ -570,7 +570,8 @@ void SendBgpServiceConfig(const std::string &ip, void AddAddressVrfAssignAcl(const char *intf_name, int intf_id, const char *sip, const char *dip, int proto, int sport_start, int sport_end, int dport_start, - int dport_end, const char *vrf, const char *ignore_acl); + int dport_end, const char *vrf, const char *ignore_acl, + const char *svc_intf_type = NULL); void SendBgpServiceConfig(const std::string &ip, uint32_t source_port, uint32_t id, diff --git a/src/vnsw/agent/test/test_util.cc b/src/vnsw/agent/test/test_util.cc index f3294e33569..af20358126a 100644 --- a/src/vnsw/agent/test/test_util.cc +++ b/src/vnsw/agent/test/test_util.cc @@ -4097,9 +4097,17 @@ bool VnMatch(VnListType &vn_list, std::string &vn) { void AddAddressVrfAssignAcl(const char *intf_name, int intf_id, const char *sip, const char *dip, int proto, int sport_start, int sport_end, int dport_start, - int dport_end, const char *vrf, const char *ignore_acl) { + int dport_end, const char *vrf, + const char *ignore_acl, const char *svc_intf_type) { + + if (svc_intf_type == NULL) + svc_intf_type = "management"; + char buf[3000]; sprintf(buf, + " \n" + " %s\n" + " \n" " \n" " \n" " \n" @@ -4148,8 +4156,8 @@ void AddAddressVrfAssignAcl(const char *intf_name, int intf_id, " %s\n" " \n" " \n", - proto, sip, sport_start, sport_end, dip, dport_start, dport_end, vrf, - ignore_acl); + svc_intf_type, proto, sip, sport_start, sport_end, dip, dport_start, + dport_end, vrf, ignore_acl); AddNode("virtual-machine-interface", intf_name, intf_id, buf); client->WaitForIdle(); } diff --git a/src/vnsw/agent/vrouter/ksync/interface_ksync.cc b/src/vnsw/agent/vrouter/ksync/interface_ksync.cc index 5455f8eadde..6916a1e76a1 100644 --- a/src/vnsw/agent/vrouter/ksync/interface_ksync.cc +++ b/src/vnsw/agent/vrouter/ksync/interface_ksync.cc @@ -54,6 +54,7 @@ InterfaceKSyncEntry::InterfaceKSyncEntry(InterfaceKSyncObject *obj, metadata_l2_active_(entry->metadata_l2_active_), metadata_ip_active_(entry->metadata_ip_active_), bridging_(entry->bridging_), + proxy_arp_mode_(VmInterface::PROXY_ARP_NONE), mac_(entry->mac_), smac_(entry->smac_), mirror_direction_(entry->mirror_direction_), @@ -98,6 +99,7 @@ InterfaceKSyncEntry::InterfaceKSyncEntry(InterfaceKSyncObject *obj, metadata_l2_active_(false), metadata_ip_active_(false), bridging_(true), + proxy_arp_mode_(VmInterface::PROXY_ARP_NONE), mac_(), smac_(), mirror_direction_(Interface::UNKNOWN), @@ -252,6 +254,11 @@ bool InterfaceKSyncEntry::Sync(DBEntry *e) { ret = true; } + if (proxy_arp_mode_ != vm_port->proxy_arp_mode()) { + proxy_arp_mode_ = vm_port->proxy_arp_mode(); + ret = true; + } + if (rx_vlan_id_ != vm_port->rx_vlan_id()) { rx_vlan_id_ = vm_port->rx_vlan_id(); ret = true; @@ -567,6 +574,9 @@ int InterfaceKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) { if (flood_unknown_unicast_) { flags |= VIF_FLAG_UNKNOWN_UC_FLOOD; } + if (proxy_arp_mode_ == VmInterface::PROXY_ARP_UNRESTRICTED) { + flags |= VIF_FLAG_MAC_PROXY; + } MacAddress mac; if (parent_.get() != NULL) { encoder.set_vifr_type(VIF_TYPE_VIRTUAL_VLAN); diff --git a/src/vnsw/agent/vrouter/ksync/interface_ksync.h b/src/vnsw/agent/vrouter/ksync/interface_ksync.h index 4e25bd6da1e..31d5ce3f0a4 100644 --- a/src/vnsw/agent/vrouter/ksync/interface_ksync.h +++ b/src/vnsw/agent/vrouter/ksync/interface_ksync.h @@ -94,6 +94,7 @@ class InterfaceKSyncEntry : public KSyncNetlinkDBEntry { bool metadata_l2_active_; bool metadata_ip_active_; bool bridging_; + VmInterface::ProxyArpMode proxy_arp_mode_; MacAddress mac_; MacAddress smac_; Interface::MirrorDirection mirror_direction_;