From ca8ba6dfb1e4a2ae407a03cead2bda3783750e1f Mon Sep 17 00:00:00 2001 From: Volodymyr Samotiy Date: Thu, 8 Apr 2021 18:30:14 +0300 Subject: [PATCH] [vlan] Add support of VLAN host interface (#1645) * [vlan] Add support of VLAN host interface * Infrastructure needed for the VNET ping tool Signed-off-by: Volodymyr Samotiy --- cfgmgr/vlanmgr.cpp | 8 +++++ orchagent/port.h | 1 + orchagent/portsorch.cpp | 71 ++++++++++++++++++++++++++++++++++++++++ orchagent/portsorch.h | 3 ++ tests/dvslib/dvs_vlan.py | 24 ++++++++++++++ tests/test_vlan.py | 16 +++++++++ 6 files changed, 123 insertions(+) diff --git a/cfgmgr/vlanmgr.cpp b/cfgmgr/vlanmgr.cpp index a79aa844f2a8..48a12becd915 100644 --- a/cfgmgr/vlanmgr.cpp +++ b/cfgmgr/vlanmgr.cpp @@ -306,6 +306,7 @@ void VlanMgr::doVlanTask(Consumer &consumer) string admin_status; string mtu = DEFAULT_MTU_STR; string mac = gMacAddress.to_string(); + string hostif_name = ""; vector fvVector; string members; @@ -362,6 +363,10 @@ void VlanMgr::doVlanTask(Consumer &consumer) mac = fvValue(i); setHostVlanMac(vlan_id, mac); } + else if (fvField(i) == "hostif_name") + { + hostif_name = fvValue(i); + } } /* fvVector should not be empty */ if (fvVector.empty()) @@ -376,6 +381,9 @@ void VlanMgr::doVlanTask(Consumer &consumer) FieldValueTuple mc("mac", mac); fvVector.push_back(mc); + FieldValueTuple hostif_name_fvt("hostif_name", hostif_name); + fvVector.push_back(hostif_name_fvt); + m_appVlanTableProducer.set(key, fvVector); m_vlans.insert(key); diff --git a/orchagent/port.h b/orchagent/port.h index 86e84a16361f..2155764c31d8 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -36,6 +36,7 @@ struct VlanInfo { sai_object_id_t vlan_oid = 0; sai_vlan_id_t vlan_id = 0; + sai_object_id_t host_intf_id = SAI_NULL_OBJECT_ID; }; struct SystemPortInfo diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index d776ee84e7e4..e01710f2ec6c 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -1932,6 +1932,55 @@ bool PortsOrch::setHostIntfsOperStatus(const Port& port, bool isUp) const return true; } +bool PortsOrch::createVlanHostIntf(Port& vl, string hostif_name) +{ + SWSS_LOG_ENTER(); + + if (vl.m_vlan_info.host_intf_id != SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("Host interface already assigned to VLAN %d", vl.m_vlan_info.vlan_id); + return false; + } + + vector attrs; + sai_attribute_t attr; + + attr.id = SAI_HOSTIF_ATTR_TYPE; + attr.value.s32 = SAI_HOSTIF_TYPE_NETDEV; + attrs.push_back(attr); + + attr.id = SAI_HOSTIF_ATTR_OBJ_ID; + attr.value.oid = vl.m_vlan_info.vlan_oid; + attrs.push_back(attr); + + attr.id = SAI_HOSTIF_ATTR_NAME; + strncpy(attr.value.chardata, hostif_name.c_str(), sizeof(attr.value.chardata)); + attrs.push_back(attr); + + sai_status_t status = sai_hostif_api->create_hostif(&vl.m_vlan_info.host_intf_id, gSwitchId, (uint32_t)attrs.size(), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create host interface %s for VLAN %d", hostif_name.c_str(), vl.m_vlan_info.vlan_id); + return false; + } + + m_portList[vl.m_alias] = vl; + + return true; +} + +bool PortsOrch::removeVlanHostIntf(Port vl) +{ + sai_status_t status = sai_hostif_api->remove_hostif(vl.m_vlan_info.host_intf_id); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove VLAN %d host interface", vl.m_vlan_info.vlan_id); + return false; + } + + return true; +} + void PortsOrch::updateDbPortOperStatus(const Port& port, sai_port_oper_status_t status) const { SWSS_LOG_ENTER(); @@ -2870,6 +2919,7 @@ void PortsOrch::doVlanTask(Consumer &consumer) // Retrieve attributes uint32_t mtu = 0; MacAddress mac; + string hostif_name = ""; for (auto i : kfvFieldsValues(t)) { if (fvField(i) == "mtu") @@ -2880,6 +2930,10 @@ void PortsOrch::doVlanTask(Consumer &consumer) { mac = MacAddress(fvValue(i)); } + if (fvField(i) == "hostif_name") + { + hostif_name = fvValue(i); + } } /* @@ -2922,6 +2976,16 @@ void PortsOrch::doVlanTask(Consumer &consumer) gIntfsOrch->setRouterIntfsMac(vl); } } + if (!hostif_name.empty()) + { + if (!createVlanHostIntf(vl, hostif_name)) + { + // No need to fail in case of error as this is for monitoring VLAN. + // Error message is printed by "createVlanHostIntf" so just handle failure gracefully. + it = consumer.m_toSync.erase(it); + continue; + } + } } it = consumer.m_toSync.erase(it); @@ -3914,6 +3978,13 @@ bool PortsOrch::removeVlan(Port vlan) return false; } + + if (vlan.m_vlan_info.host_intf_id && !removeVlanHostIntf(vlan)) + { + SWSS_LOG_ERROR("Failed to remove VLAN %d host interface", vlan.m_vlan_info.vlan_id); + return false; + } + sai_status_t status = sai_vlan_api->remove_vlan(vlan.m_vlan_info.vlan_oid); if (status != SAI_STATUS_SUCCESS) { diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index bcd5b5d38d56..a2d669c26384 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -99,6 +99,9 @@ class PortsOrch : public Orch, public Subject bool setHostIntfsOperStatus(const Port& port, bool up) const; void updateDbPortOperStatus(const Port& port, sai_port_oper_status_t status) const; + bool createVlanHostIntf(Port& vl, string hostif_name); + bool removeVlanHostIntf(Port vl); + bool createBindAclTableGroup(sai_object_id_t port_oid, sai_object_id_t acl_table_oid, sai_object_id_t &group_oid, diff --git a/tests/dvslib/dvs_vlan.py b/tests/dvslib/dvs_vlan.py index ecb71ad98a0d..bf4acd31787b 100644 --- a/tests/dvslib/dvs_vlan.py +++ b/tests/dvslib/dvs_vlan.py @@ -13,6 +13,11 @@ def create_vlan(self, vlan): vlan_entry = {"vlanid": vlan} self.config_db.create_entry("VLAN", vlan, vlan_entry) + def create_vlan_hostif(self, vlan, hostif_name): + vlan = "Vlan{}".format(vlan) + vlan_entry = {"vlanid": vlan, "hostif_name": hostif_name} + self.config_db.update_entry("VLAN", vlan, vlan_entry) + def remove_vlan(self, vlan): vlan = "Vlan{}".format(vlan) self.config_db.delete_entry("VLAN", vlan) @@ -53,6 +58,7 @@ def get_and_verify_vlan_ids(self, vlan_entries = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_VLAN", expected_num + 1, polling_config) + return [v for v in vlan_entries if v != self.asic_db.default_vlan_id] def verify_vlan_member(self, vlan_oid, iface, tagging_mode="SAI_VLAN_TAGGING_MODE_UNTAGGED"): @@ -74,3 +80,21 @@ def get_bridge_port_id(self, expected_iface): assert self.asic_db.port_to_id_map[bridge_port["SAI_BRIDGE_PORT_ATTR_PORT_ID"]] == expected_iface return bridge_port_id + def verify_vlan_hostif(self, hostif_name, hostifs_oid, vlan_oid): + hostif = {} + + for hostif_oid in hostifs_oid: + hostif = self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF", hostif_oid) + if hostif.get("SAI_HOSTIF_ATTR_NAME") == hostif_name: + break + + assert hostif.get("SAI_HOSTIF_ATTR_TYPE") == "SAI_HOSTIF_TYPE_NETDEV" + assert hostif.get("SAI_HOSTIF_ATTR_OBJ_ID") == vlan_oid + assert hostif.get("SAI_HOSTIF_ATTR_NAME") == hostif_name + + def get_and_verify_vlan_hostif_ids(self, expected_num, polling_config=PollingConfig()): + hostif_entries = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF", + expected_num + 1, + polling_config) + return hostif_entries + diff --git a/tests/test_vlan.py b/tests/test_vlan.py index 90044e69dd82..6e43227a5655 100644 --- a/tests/test_vlan.py +++ b/tests/test_vlan.py @@ -419,6 +419,22 @@ def test_VlanMemberDbData(self, dvs, test_input, expected): self.dvs_vlan.remove_vlan(vlan) self.dvs_vlan.get_and_verify_vlan_ids(0) + def test_VlanHostIf(self, dvs): + + vlan = "2" + hostif_name = "MonVlan2" + + self.dvs_vlan.create_vlan(vlan) + vlan_oid = self.dvs_vlan.get_and_verify_vlan_ids(1)[0] + self.dvs_vlan.verify_vlan(vlan_oid, vlan) + + self.dvs_vlan.create_vlan_hostif(vlan, hostif_name) + hostif_oid = self.dvs_vlan.get_and_verify_vlan_hostif_ids(len(dvs.asic_db.hostif_name_map)) + self.dvs_vlan.verify_vlan_hostif(hostif_name, hostif_oid, vlan_oid) + + self.dvs_vlan.remove_vlan(vlan) + self.dvs_vlan.get_and_verify_vlan_ids(0) + self.dvs_vlan.get_and_verify_vlan_hostif_ids(len(dvs.asic_db.hostif_name_map) - 1) # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying