From 278770de3298bd3080abdb94b8bfb7b5c2afb9f7 Mon Sep 17 00:00:00 2001 From: Wenda Ni Date: Mon, 24 May 2021 13:38:41 -0700 Subject: [PATCH] [sub intf] Fix kernel side processing to enslave sub interface to non-default vrf (#1521) Signed-off-by: Wenda Ni What I did Change in IntfMgr: Use alias (instead of subIntfAlias before the change) to hold complete sub interface name; use parentAlias (instead of alias before the change) to hold parent port name. Move sub interface creation to the first place before processing fields vrf, proxy arp, and garp. In doing above, a sub interface can receive the same treatment as other types of interfaces (interface type port, type vlan) on vrf, proxy arp, and garp fields, while maintaining an indicator (parentAlias not empty) to receive treatment specific to a sub interface (creation, deletion). Why I did it Fix #1277, #1510 How I verified it vs test. Extended all test cases to test a sub interface ingress linked to a non-default vrf. --- cfgmgr/intfmgr.cpp | 134 ++++----- orchagent/intfsorch.cpp | 1 + tests/conftest.py | 9 +- tests/test_sub_port_intf.py | 535 ++++++++++++++++++++++++++++++------ 4 files changed, 521 insertions(+), 158 deletions(-) diff --git a/cfgmgr/intfmgr.cpp b/cfgmgr/intfmgr.cpp index a5bc092df9ba..836f8acf9218 100644 --- a/cfgmgr/intfmgr.cpp +++ b/cfgmgr/intfmgr.cpp @@ -428,16 +428,15 @@ bool IntfMgr::doIntfGeneralTask(const vector& keys, string alias(keys[0]); string vlanId; - string subIntfAlias; + string parentAlias; size_t found = alias.find(VLAN_SUB_INTERFACE_SEPARATOR); if (found != string::npos) { // This is a sub interface - // subIntfAlias holds the complete sub interface name - // while alias becomes the parent interface - subIntfAlias = alias; + // alias holds the complete sub interface name + // while parentAlias holds the parent port name vlanId = alias.substr(found + 1); - alias = alias.substr(0, found); + parentAlias = alias.substr(0, found); } bool is_lo = !alias.compare(0, strlen(LOOPBACK_PREFIX), LOOPBACK_PREFIX); string mac = ""; @@ -482,7 +481,7 @@ bool IntfMgr::doIntfGeneralTask(const vector& keys, if (op == SET_COMMAND) { - if (!isIntfStateOk(alias)) + if (!isIntfStateOk(parentAlias.empty() ? alias : parentAlias)) { SWSS_LOG_DEBUG("Interface is not ready, skipping %s", alias.c_str()); return false; @@ -520,59 +519,13 @@ bool IntfMgr::doIntfGeneralTask(const vector& keys, } } - if (!vrf_name.empty()) - { - setIntfVrf(alias, vrf_name); - } - - /*Set the mac of interface*/ - if (!mac.empty()) - { - setIntfMac(alias, mac); - } - else - { - FieldValueTuple fvTuple("mac_addr", MacAddress().to_string()); - data.push_back(fvTuple); - } - - if (!proxy_arp.empty()) + if (!parentAlias.empty()) { - if (!setIntfProxyArp(alias, proxy_arp)) - { - SWSS_LOG_ERROR("Failed to set proxy ARP to \"%s\" state for the \"%s\" interface", proxy_arp.c_str(), alias.c_str()); - return false; - } - - if (!alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX)) - { - FieldValueTuple fvTuple("proxy_arp", proxy_arp); - data.push_back(fvTuple); - } - } - - if (!grat_arp.empty()) - { - if (!setIntfGratArp(alias, grat_arp)) - { - SWSS_LOG_ERROR("Failed to set ARP accept to \"%s\" state for the \"%s\" interface", grat_arp.c_str(), alias.c_str()); - return false; - } - - if (!alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX)) - { - FieldValueTuple fvTuple("grat_arp", grat_arp); - data.push_back(fvTuple); - } - } - - if (!subIntfAlias.empty()) - { - if (m_subIntfList.find(subIntfAlias) == m_subIntfList.end()) + if (m_subIntfList.find(alias) == m_subIntfList.end()) { try { - addHostSubIntf(alias, subIntfAlias, vlanId); + addHostSubIntf(parentAlias, alias, vlanId); } catch (const std::runtime_error &e) { @@ -580,14 +533,14 @@ bool IntfMgr::doIntfGeneralTask(const vector& keys, return false; } - m_subIntfList.insert(subIntfAlias); + m_subIntfList.insert(alias); } if (!mtu.empty()) { try { - setHostSubIntfMtu(subIntfAlias, mtu); + setHostSubIntfMtu(alias, mtu); } catch (const std::runtime_error &e) { @@ -609,7 +562,7 @@ bool IntfMgr::doIntfGeneralTask(const vector& keys, } try { - setHostSubIntfAdminStatus(subIntfAlias, adminStatus); + setHostSubIntfAdminStatus(alias, adminStatus); } catch (const std::runtime_error &e) { @@ -618,10 +571,57 @@ bool IntfMgr::doIntfGeneralTask(const vector& keys, } // set STATE_DB port state - setSubIntfStateOk(subIntfAlias); + setSubIntfStateOk(alias); } - m_appIntfTableProducer.set(subIntfAlias.empty() ? alias : subIntfAlias, data); - m_stateIntfTable.hset(subIntfAlias.empty() ? alias : subIntfAlias, "vrf", vrf_name); + + if (!vrf_name.empty()) + { + setIntfVrf(alias, vrf_name); + } + + /*Set the mac of interface*/ + if (!mac.empty()) + { + setIntfMac(alias, mac); + } + else + { + FieldValueTuple fvTuple("mac_addr", MacAddress().to_string()); + data.push_back(fvTuple); + } + + if (!proxy_arp.empty()) + { + if (!setIntfProxyArp(alias, proxy_arp)) + { + SWSS_LOG_ERROR("Failed to set proxy ARP to \"%s\" state for the \"%s\" interface", proxy_arp.c_str(), alias.c_str()); + return false; + } + + if (!alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX)) + { + FieldValueTuple fvTuple("proxy_arp", proxy_arp); + data.push_back(fvTuple); + } + } + + if (!grat_arp.empty()) + { + if (!setIntfGratArp(alias, grat_arp)) + { + SWSS_LOG_ERROR("Failed to set ARP accept to \"%s\" state for the \"%s\" interface", grat_arp.c_str(), alias.c_str()); + return false; + } + + if (!alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX)) + { + FieldValueTuple fvTuple("grat_arp", grat_arp); + data.push_back(fvTuple); + } + } + + m_appIntfTableProducer.set(alias, data); + m_stateIntfTable.hset(alias, "vrf", vrf_name); } else if (op == DEL_COMMAND) { @@ -640,16 +640,16 @@ bool IntfMgr::doIntfGeneralTask(const vector& keys, m_loopbackIntfList.erase(alias); } - if (!subIntfAlias.empty()) + if (!parentAlias.empty()) { - removeHostSubIntf(subIntfAlias); - m_subIntfList.erase(subIntfAlias); + removeHostSubIntf(alias); + m_subIntfList.erase(alias); - removeSubIntfState(subIntfAlias); + removeSubIntfState(alias); } - m_appIntfTableProducer.del(subIntfAlias.empty() ? alias : subIntfAlias); - m_stateIntfTable.del(subIntfAlias.empty() ? alias : subIntfAlias); + m_appIntfTableProducer.del(alias); + m_stateIntfTable.del(alias); } else { diff --git a/orchagent/intfsorch.cpp b/orchagent/intfsorch.cpp index ffae3decacda..f3fab3cc61e1 100644 --- a/orchagent/intfsorch.cpp +++ b/orchagent/intfsorch.cpp @@ -731,6 +731,7 @@ void IntfsOrch::doTask(Consumer &consumer) { IntfsEntry intfs_entry; intfs_entry.ref_count = 0; + intfs_entry.proxy_arp = false; intfs_entry.vrf_id = vrf_id; m_syncdIntfses[alias] = intfs_entry; m_vrfOrch->increaseVrfRefCount(vrf_id); diff --git a/tests/conftest.py b/tests/conftest.py index d707a3d08ab8..a303c5f17e1a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1003,8 +1003,8 @@ def set_interface_status(self, interface, admin_status): tbl.set(interface, fvs) time.sleep(1) - # deps: acl, fdb_update, fdb, mirror_port_erspan, vlan - def add_ip_address(self, interface, ip): + # deps: acl, fdb_update, fdb, mirror_port_erspan, vlan, sub port intf + def add_ip_address(self, interface, ip, vrf_name=None): if interface.startswith("PortChannel"): tbl_name = "PORTCHANNEL_INTERFACE" elif interface.startswith("Vlan"): @@ -1012,7 +1012,10 @@ def add_ip_address(self, interface, ip): else: tbl_name = "INTERFACE" tbl = swsscommon.Table(self.cdb, tbl_name) - fvs = swsscommon.FieldValuePairs([("NULL", "NULL")]) + pairs = [("NULL", "NULL")] + if vrf_name: + pairs = [("vrf_name", vrf_name)] + fvs = swsscommon.FieldValuePairs(pairs) tbl.set(interface, fvs) tbl.set(interface + "|" + ip, fvs) time.sleep(1) diff --git a/tests/test_sub_port_intf.py b/tests/test_sub_port_intf.py index 50745995451d..56efb320b74f 100644 --- a/tests/test_sub_port_intf.py +++ b/tests/test_sub_port_intf.py @@ -10,6 +10,7 @@ CFG_PORT_TABLE_NAME = "PORT" CFG_LAG_TABLE_NAME = "PORTCHANNEL" CFG_LAG_MEMBER_TABLE_NAME = "PORTCHANNEL_MEMBER" +CFG_VRF_TABLE_NAME = "VRF" STATE_PORT_TABLE_NAME = "PORT_TABLE" STATE_LAG_TABLE_NAME = "LAG_TABLE" @@ -27,8 +28,11 @@ ASIC_NEXT_HOP_GROUP_MEMBER_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER" ASIC_LAG_MEMBER_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER" ASIC_HOSTIF_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF" +ASIC_VIRTUAL_ROUTER_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER" +ASIC_LAG_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_LAG" ADMIN_STATUS = "admin_status" +VRF_NAME = "vrf_name" ETHERNET_PREFIX = "Ethernet" LAG_PREFIX = "PortChannel" @@ -50,6 +54,8 @@ class TestSubPortIntf(object): IPV6_TOME_UNDER_TEST = "fc00::41/128" IPV6_SUBNET_UNDER_TEST = "fc00::40/126" + VRF_UNDER_TEST = "Vrf0" + def connect_dbs(self, dvs): self.app_db = dvs.get_app_db() self.asic_db = dvs.get_asic_db() @@ -57,6 +63,8 @@ def connect_dbs(self, dvs): self.state_db = dvs.get_state_db() dvs.setup_db() + self.default_vrf_oid = self.get_default_vrf_oid() + def get_parent_port_index(self, port_name): if port_name.startswith(ETHERNET_PREFIX): idx = int(port_name[len(ETHERNET_PREFIX):]) @@ -71,8 +79,8 @@ def set_parent_port_oper_status(self, dvs, port_name, status): dvs.servers[srv_idx].runcmd("ip link set dev eth0 " + status) else: assert port_name.startswith(LAG_PREFIX) - dvs.runcmd("bash -c 'echo " + ("1" if status == "up" else "0") + \ - " > /sys/class/net/" + port_name + "/carrier'") + dvs.runcmd("bash -c 'echo " + ("1" if status == "up" else "0") + + " > /sys/class/net/" + port_name + "/carrier'") time.sleep(1) def set_parent_port_admin_status(self, dvs, port_name, status): @@ -84,6 +92,7 @@ def set_parent_port_admin_status(self, dvs, port_name, status): assert port_name.startswith(LAG_PREFIX) tbl_name = CFG_LAG_TABLE_NAME self.config_db.create_entry(tbl_name, port_name, fvs) + time.sleep(1) if port_name.startswith(ETHERNET_PREFIX): self.set_parent_port_oper_status(dvs, port_name, "down") @@ -91,8 +100,13 @@ def set_parent_port_admin_status(self, dvs, port_name, status): else: self.set_parent_port_oper_status(dvs, port_name, "up") - def create_sub_port_intf_profile(self, sub_port_intf_name): + def create_vrf(self, vrf_name): + self.config_db.create_entry(CFG_VRF_TABLE_NAME, vrf_name, {"NULL": "NULL"}) + + def create_sub_port_intf_profile(self, sub_port_intf_name, vrf_name=None): fvs = {ADMIN_STATUS: "up"} + if vrf_name: + fvs[VRF_NAME] = vrf_name self.config_db.create_entry(CFG_VLAN_SUB_INTF_TABLE_NAME, sub_port_intf_name, fvs) @@ -103,11 +117,13 @@ def add_lag_members(self, lag, members): key = "{}|{}".format(lag, member) self.config_db.create_entry(CFG_LAG_MEMBER_TABLE_NAME, key, fvs) - def create_sub_port_intf_profile_appl_db(self, sub_port_intf_name, admin_status): + def create_sub_port_intf_profile_appl_db(self, sub_port_intf_name, admin_status, vrf_name=None): pairs = [ (ADMIN_STATUS, admin_status), ("mtu", "0"), ] + if vrf_name: + pairs.append((VRF_NAME, vrf_name)) fvs = swsscommon.FieldValuePairs(pairs) tbl = swsscommon.ProducerStateTable(self.app_db.db_connection, APP_INTF_TABLE_NAME) @@ -129,11 +145,29 @@ def add_sub_port_intf_ip_addr_appl_db(self, sub_port_intf_name, ip_addr): tbl = swsscommon.ProducerStateTable(self.app_db.db_connection, APP_INTF_TABLE_NAME) tbl.set(sub_port_intf_name + APPL_DB_SEPARATOR + ip_addr, fvs) + def add_route_appl_db(self, ip_prefix, nhop_ips, ifnames, vrf_name=None): + fvs = swsscommon.FieldValuePairs([("nexthop", ",".join(nhop_ips)), ("ifname", ",".join(ifnames))]) + + tbl = swsscommon.ProducerStateTable(self.app_db.db_connection, APP_ROUTE_TABLE_NAME) + tbl.set(vrf_name + APPL_DB_SEPARATOR + ip_prefix if vrf_name else ip_prefix, fvs) + def set_sub_port_intf_admin_status(self, sub_port_intf_name, status): fvs = {ADMIN_STATUS: status} self.config_db.create_entry(CFG_VLAN_SUB_INTF_TABLE_NAME, sub_port_intf_name, fvs) + def remove_vrf(self, vrf_name): + self.config_db.delete_entry(CFG_VRF_TABLE_NAME, vrf_name) + + def check_vrf_removal(self, vrf_oid): + self.asic_db.wait_for_deleted_keys(ASIC_VIRTUAL_ROUTER_TABLE, [vrf_oid]) + + def remove_lag(self, lag): + self.config_db.delete_entry(CFG_LAG_TABLE_NAME, lag) + + def check_lag_removal(self, lag_oid): + self.asic_db.wait_for_deleted_keys(ASIC_LAG_TABLE, [lag_oid]) + def remove_lag_members(self, lag, members): for member in members: key = "{}|{}".format(lag, member) @@ -161,6 +195,10 @@ def remove_sub_port_intf_ip_addr_appl_db(self, sub_port_intf_name, ip_addr): tbl = swsscommon.ProducerStateTable(self.app_db.db_connection, APP_INTF_TABLE_NAME) tbl._del(sub_port_intf_name + APPL_DB_SEPARATOR + ip_addr) + def remove_route_appl_db(self, ip_prefix, vrf_name=None): + tbl = swsscommon.ProducerStateTable(self.app_db.db_connection, APP_ROUTE_TABLE_NAME) + tbl._del(vrf_name + APPL_DB_SEPARATOR + ip_prefix if vrf_name else ip_prefix) + def get_oids(self, table): return self.asic_db.get_keys(table) @@ -169,7 +207,15 @@ def get_newly_created_oid(self, table, old_oids): oid = [ids for ids in new_oids if ids not in old_oids] return oid[0] - def get_ip_prefix_nhg_oid(self, ip_prefix): + def get_default_vrf_oid(self): + oids = self.get_oids(ASIC_VIRTUAL_ROUTER_TABLE) + assert len(oids) == 1, "Wrong # of default vrfs: %d, expected #: 1." % (len(oids)) + return oids[0] + + def get_ip_prefix_nhg_oid(self, ip_prefix, vrf_oid=None): + if vrf_oid is None: + vrf_oid = self.default_vrf_oid + def _access_function(): route_entry_found = False @@ -178,6 +224,7 @@ def _access_function(): route_entry_key = json.loads(raw_route_entry_key) if route_entry_key["dest"] == ip_prefix: route_entry_found = True + assert route_entry_key["vr"] == vrf_oid break return (route_entry_found, raw_route_entry_key) @@ -186,7 +233,7 @@ def _access_function(): fvs = self.asic_db.get_entry(ASIC_ROUTE_ENTRY_TABLE, raw_route_entry_key) - nhg_oid = fvs.get( "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", "") + nhg_oid = fvs.get("SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", "") assert nhg_oid != "" assert nhg_oid != "oid:0x0" @@ -198,20 +245,47 @@ def check_sub_port_intf_key_existence(self, db, table_name, key): def check_sub_port_intf_fvs(self, db, table_name, key, fv_dict): db.wait_for_field_match(table_name, key, fv_dict) - def check_sub_port_intf_route_entries(self): - expected_destinations = [self.IPV4_TOME_UNDER_TEST, - self.IPV4_SUBNET_UNDER_TEST, - self.IPV6_TOME_UNDER_TEST, - self.IPV6_SUBNET_UNDER_TEST] + def check_sub_port_intf_route_entries(self, vrf_oid=None): + expected_dests = [self.IPV4_TOME_UNDER_TEST, + self.IPV4_SUBNET_UNDER_TEST, + self.IPV6_TOME_UNDER_TEST, + self.IPV6_SUBNET_UNDER_TEST] + if vrf_oid is None: + vrf_oid = self.default_vrf_oid + expected_vrf_oids = [vrf_oid, + vrf_oid, + vrf_oid, + vrf_oid] def _access_function(): raw_route_entries = self.asic_db.get_keys(ASIC_ROUTE_ENTRY_TABLE) - route_destinations = [str(json.loads(raw_route_entry)["dest"]) - for raw_route_entry in raw_route_entries] - return (all(dest in route_destinations for dest in expected_destinations), None) + route_dest_vrf_oids = [(json.loads(raw_route_entry)["dest"], json.loads(raw_route_entry)["vr"]) + for raw_route_entry in raw_route_entries] + return (all((dest, vrf_oid) in route_dest_vrf_oids for dest, vrf_oid in zip(expected_dests, expected_vrf_oids)), None) wait_for_result(_access_function) + def check_sub_port_intf_vrf_bind_kernel(self, dvs, port_name, vrf_name): + (ec, out) = dvs.runcmd(['bash', '-c', "ip link show {} | grep {}".format(port_name, vrf_name)]) + assert ec == 0 + assert vrf_name in out + + def check_sub_port_intf_vrf_nobind_kernel(self, dvs, port_name, vrf_name=None): + if vrf_name is not None: + (ec, out) = dvs.runcmd(['bash', '-c', "ip link show {} | grep {}".format(port_name, vrf_name)]) + assert ec == 1 + assert vrf_name not in out + + (ec, out) = dvs.runcmd(['bash', '-c', "ip link show {} | grep master".format(port_name)]) + assert ec == 1 + assert "master" not in out + + def check_sub_port_intf_removal_kernel(self, dvs, port_name): + (ec, out) = dvs.runcmd(['bash', '-c', "ip link show {}".format(port_name)]) + assert ec == 1 + assert port_name in out + assert "does not exist" in out + def check_sub_port_intf_key_removal(self, db, table_name, key): db.wait_for_deleted_keys(table_name, [key]) @@ -225,26 +299,33 @@ def _access_function(): wait_for_result(_access_function) - def _test_sub_port_intf_creation(self, dvs, sub_port_intf_name): + def _test_sub_port_intf_creation(self, dvs, sub_port_intf_name, vrf_name=None): substrs = sub_port_intf_name.split(VLAN_SUB_INTERFACE_SEPARATOR) parent_port = substrs[0] vlan_id = substrs[1] if parent_port.startswith(ETHERNET_PREFIX): state_tbl_name = STATE_PORT_TABLE_NAME phy_ports = [parent_port] + parent_port_oid = dvs.asicdb.portnamemap[parent_port] else: assert parent_port.startswith(LAG_PREFIX) state_tbl_name = STATE_LAG_TABLE_NAME phy_ports = self.LAG_MEMBERS_UNDER_TEST + old_lag_oids = self.get_oids(ASIC_LAG_TABLE) + vrf_oid = self.default_vrf_oid old_rif_oids = self.get_oids(ASIC_RIF_TABLE) self.set_parent_port_admin_status(dvs, parent_port, "up") - # Add lag members to test physical port host interface vlan tag attribute if parent_port.startswith(LAG_PREFIX): + parent_port_oid = self.get_newly_created_oid(ASIC_LAG_TABLE, old_lag_oids) + # Add lag members to test physical port host interface vlan tag attribute self.add_lag_members(parent_port, self.LAG_MEMBERS_UNDER_TEST) self.asic_db.wait_for_n_keys(ASIC_LAG_MEMBER_TABLE, len(self.LAG_MEMBERS_UNDER_TEST)) - self.create_sub_port_intf_profile(sub_port_intf_name) + if vrf_name: + self.create_vrf(vrf_name) + vrf_oid = self.get_newly_created_oid(ASIC_VIRTUAL_ROUTER_TABLE, [vrf_oid]) + self.create_sub_port_intf_profile(sub_port_intf_name, vrf_name) # Verify that sub port interface state ok is pushed to STATE_DB by Intfmgrd fv_dict = { @@ -252,10 +333,24 @@ def _test_sub_port_intf_creation(self, dvs, sub_port_intf_name): } self.check_sub_port_intf_fvs(self.state_db, state_tbl_name, sub_port_intf_name, fv_dict) + # Verify vrf name sub port interface bound to in STATE_DB INTERFACE_TABLE + fv_dict = { + "vrf": vrf_name if vrf_name else "", + } + self.check_sub_port_intf_fvs(self.state_db, STATE_INTERFACE_TABLE_NAME, sub_port_intf_name, fv_dict) + + # If bound to non-default vrf, verify sub port interface vrf binding in linux kernel, + # and parent port not bound to vrf + if vrf_name: + self.check_sub_port_intf_vrf_bind_kernel(dvs, sub_port_intf_name, vrf_name) + self.check_sub_port_intf_vrf_nobind_kernel(dvs, parent_port, vrf_name) + # Verify that sub port interface configuration is synced to APPL_DB INTF_TABLE by Intfmgrd fv_dict = { ADMIN_STATUS: "up", } + if vrf_name: + fv_dict[VRF_NAME] = vrf_name self.check_sub_port_intf_fvs(self.app_db, APP_INTF_TABLE_NAME, sub_port_intf_name, fv_dict) # Verify that a sub port router interface entry is created in ASIC_DB @@ -265,6 +360,8 @@ def _test_sub_port_intf_creation(self, dvs, sub_port_intf_name): "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V4_STATE": "true", "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V6_STATE": "true", "SAI_ROUTER_INTERFACE_ATTR_MTU": DEFAULT_MTU, + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": vrf_oid, + "SAI_ROUTER_INTERFACE_ATTR_PORT_ID": parent_port_oid, } rif_oid = self.get_newly_created_oid(ASIC_RIF_TABLE, old_rif_oids) self.check_sub_port_intf_fvs(self.asic_db, ASIC_RIF_TABLE, rif_oid, fv_dict) @@ -281,25 +378,41 @@ def _test_sub_port_intf_creation(self, dvs, sub_port_intf_name): self.remove_sub_port_intf_profile(sub_port_intf_name) self.check_sub_port_intf_profile_removal(rif_oid) - # Remove lag members from lag parent port + # Remove vrf if created + if vrf_name: + self.remove_vrf(vrf_name) + self.check_vrf_removal(vrf_oid) + if parent_port.startswith(LAG_PREFIX): + # Remove lag members from lag parent port self.remove_lag_members(parent_port, self.LAG_MEMBERS_UNDER_TEST) self.asic_db.wait_for_n_keys(ASIC_LAG_MEMBER_TABLE, 0) + # Remove lag + self.remove_lag(parent_port) + self.check_lag_removal(parent_port_oid) + def test_sub_port_intf_creation(self, dvs): self.connect_dbs(dvs) self._test_sub_port_intf_creation(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST) self._test_sub_port_intf_creation(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST) - def _test_sub_port_intf_add_ip_addrs(self, dvs, sub_port_intf_name): + self._test_sub_port_intf_creation(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, self.VRF_UNDER_TEST) + self._test_sub_port_intf_creation(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, self.VRF_UNDER_TEST) + + def _test_sub_port_intf_add_ip_addrs(self, dvs, sub_port_intf_name, vrf_name=None): substrs = sub_port_intf_name.split(VLAN_SUB_INTERFACE_SEPARATOR) parent_port = substrs[0] + vrf_oid = self.default_vrf_oid old_rif_oids = self.get_oids(ASIC_RIF_TABLE) self.set_parent_port_admin_status(dvs, parent_port, "up") - self.create_sub_port_intf_profile(sub_port_intf_name) + if vrf_name: + self.create_vrf(vrf_name) + vrf_oid = self.get_newly_created_oid(ASIC_VIRTUAL_ROUTER_TABLE, [vrf_oid]) + self.create_sub_port_intf_profile(sub_port_intf_name, vrf_name) self.add_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV4_ADDR_UNDER_TEST) self.add_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV6_ADDR_UNDER_TEST) @@ -310,27 +423,27 @@ def _test_sub_port_intf_add_ip_addrs(self, dvs, sub_port_intf_name): fv_dict = { "state": "ok", } - self.check_sub_port_intf_fvs(self.state_db, STATE_INTERFACE_TABLE_NAME, \ - sub_port_intf_name + "|" + self.IPV4_ADDR_UNDER_TEST, fv_dict) - self.check_sub_port_intf_fvs(self.state_db, STATE_INTERFACE_TABLE_NAME, \ - sub_port_intf_name + "|" + self.IPV6_ADDR_UNDER_TEST, fv_dict) + self.check_sub_port_intf_fvs(self.state_db, STATE_INTERFACE_TABLE_NAME, + sub_port_intf_name + "|" + self.IPV4_ADDR_UNDER_TEST, fv_dict) + self.check_sub_port_intf_fvs(self.state_db, STATE_INTERFACE_TABLE_NAME, + sub_port_intf_name + "|" + self.IPV6_ADDR_UNDER_TEST, fv_dict) # Verify that ip address configuration is synced to APPL_DB INTF_TABLE by Intfmgrd fv_dict = { "scope": "global", "family": "IPv4", } - self.check_sub_port_intf_fvs(self.app_db, APP_INTF_TABLE_NAME, \ - sub_port_intf_name + ":" + self.IPV4_ADDR_UNDER_TEST, fv_dict) + self.check_sub_port_intf_fvs(self.app_db, APP_INTF_TABLE_NAME, + sub_port_intf_name + ":" + self.IPV4_ADDR_UNDER_TEST, fv_dict) fv_dict["family"] = "IPv6" - self.check_sub_port_intf_fvs(self.app_db, APP_INTF_TABLE_NAME, \ - sub_port_intf_name + ":" + self.IPV6_ADDR_UNDER_TEST, fv_dict) + self.check_sub_port_intf_fvs(self.app_db, APP_INTF_TABLE_NAME, + sub_port_intf_name + ":" + self.IPV6_ADDR_UNDER_TEST, fv_dict) # Verify that an IPv4 ip2me route entry is created in ASIC_DB # Verify that an IPv4 subnet route entry is created in ASIC_DB # Verify that an IPv6 ip2me route entry is created in ASIC_DB # Verify that an IPv6 subnet route entry is created in ASIC_DB - self.check_sub_port_intf_route_entries() + self.check_sub_port_intf_route_entries(vrf_oid) # Remove IP addresses self.remove_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV4_ADDR_UNDER_TEST) @@ -343,20 +456,43 @@ def _test_sub_port_intf_add_ip_addrs(self, dvs, sub_port_intf_name): self.remove_sub_port_intf_profile(sub_port_intf_name) self.check_sub_port_intf_profile_removal(rif_oid) + # Remove vrf if created + if vrf_name: + self.remove_vrf(vrf_name) + self.check_vrf_removal(vrf_oid) + + # Remove lag + if parent_port.startswith(LAG_PREFIX): + self.remove_lag(parent_port) + self.asic_db.wait_for_n_keys(ASIC_LAG_TABLE, 0) + def test_sub_port_intf_add_ip_addrs(self, dvs): self.connect_dbs(dvs) self._test_sub_port_intf_add_ip_addrs(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST) self._test_sub_port_intf_add_ip_addrs(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST) - def _test_sub_port_intf_appl_db_proc_seq(self, dvs, sub_port_intf_name, admin_up): + self._test_sub_port_intf_add_ip_addrs(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, self.VRF_UNDER_TEST) + self._test_sub_port_intf_add_ip_addrs(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, self.VRF_UNDER_TEST) + + def _test_sub_port_intf_appl_db_proc_seq(self, dvs, sub_port_intf_name, admin_up, vrf_name=None): substrs = sub_port_intf_name.split(VLAN_SUB_INTERFACE_SEPARATOR) parent_port = substrs[0] vlan_id = substrs[1] + vrf_oid = self.default_vrf_oid old_rif_oids = self.get_oids(ASIC_RIF_TABLE) + old_lag_oids = self.get_oids(ASIC_LAG_TABLE) self.set_parent_port_admin_status(dvs, parent_port, "up") + if parent_port.startswith(ETHERNET_PREFIX): + parent_port_oid = dvs.asicdb.portnamemap[parent_port] + else: + assert parent_port.startswith(LAG_PREFIX) + parent_port_oid = self.get_newly_created_oid(ASIC_LAG_TABLE, old_lag_oids) + if vrf_name: + self.create_vrf(vrf_name) + vrf_oid = self.get_newly_created_oid(ASIC_VIRTUAL_ROUTER_TABLE, [vrf_oid]) # Create ip address configuration in APPL_DB before creating configuration for sub port interface itself self.add_sub_port_intf_ip_addr_appl_db(sub_port_intf_name, self.IPV4_ADDR_UNDER_TEST) @@ -364,7 +500,7 @@ def _test_sub_port_intf_appl_db_proc_seq(self, dvs, sub_port_intf_name, admin_up time.sleep(2) # Create sub port interface configuration in APPL_DB - self.create_sub_port_intf_profile_appl_db(sub_port_intf_name, "up" if admin_up == True else "down") + self.create_sub_port_intf_profile_appl_db(sub_port_intf_name, "up" if admin_up == True else "down", vrf_name) # Verify that a sub port router interface entry is created in ASIC_DB fv_dict = { @@ -373,6 +509,8 @@ def _test_sub_port_intf_appl_db_proc_seq(self, dvs, sub_port_intf_name, admin_up "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V4_STATE": "true" if admin_up == True else "false", "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V6_STATE": "true" if admin_up == True else "false", "SAI_ROUTER_INTERFACE_ATTR_MTU": DEFAULT_MTU, + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": vrf_oid, + "SAI_ROUTER_INTERFACE_ATTR_PORT_ID": parent_port_oid, } rif_oid = self.get_newly_created_oid(ASIC_RIF_TABLE, old_rif_oids) self.check_sub_port_intf_fvs(self.asic_db, ASIC_RIF_TABLE, rif_oid, fv_dict) @@ -384,6 +522,16 @@ def _test_sub_port_intf_appl_db_proc_seq(self, dvs, sub_port_intf_name, admin_up self.remove_sub_port_intf_profile_appl_db(sub_port_intf_name) self.check_sub_port_intf_profile_removal(rif_oid) + # Remove vrf if created + if vrf_name: + self.remove_vrf(vrf_name) + self.check_vrf_removal(vrf_oid) + + # Remove lag + if parent_port.startswith(LAG_PREFIX): + self.remove_lag(parent_port) + self.check_lag_removal(parent_port_oid) + def test_sub_port_intf_appl_db_proc_seq(self, dvs): self.connect_dbs(dvs) @@ -393,14 +541,24 @@ def test_sub_port_intf_appl_db_proc_seq(self, dvs): self._test_sub_port_intf_appl_db_proc_seq(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, admin_up=True) self._test_sub_port_intf_appl_db_proc_seq(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, admin_up=False) - def _test_sub_port_intf_admin_status_change(self, dvs, sub_port_intf_name): + self._test_sub_port_intf_appl_db_proc_seq(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, admin_up=True, vrf_name=self.VRF_UNDER_TEST) + self._test_sub_port_intf_appl_db_proc_seq(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, admin_up=False, vrf_name=self.VRF_UNDER_TEST) + + self._test_sub_port_intf_appl_db_proc_seq(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, admin_up=True, vrf_name=self.VRF_UNDER_TEST) + self._test_sub_port_intf_appl_db_proc_seq(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, admin_up=False, vrf_name=self.VRF_UNDER_TEST) + + def _test_sub_port_intf_admin_status_change(self, dvs, sub_port_intf_name, vrf_name=None): substrs = sub_port_intf_name.split(VLAN_SUB_INTERFACE_SEPARATOR) parent_port = substrs[0] + vrf_oid = self.default_vrf_oid old_rif_oids = self.get_oids(ASIC_RIF_TABLE) self.set_parent_port_admin_status(dvs, parent_port, "up") - self.create_sub_port_intf_profile(sub_port_intf_name) + if vrf_name: + self.create_vrf(vrf_name) + vrf_oid = self.get_newly_created_oid(ASIC_VIRTUAL_ROUTER_TABLE, [vrf_oid]) + self.create_sub_port_intf_profile(sub_port_intf_name, vrf_name) self.add_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV4_ADDR_UNDER_TEST) self.add_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV6_ADDR_UNDER_TEST) @@ -408,12 +566,15 @@ def _test_sub_port_intf_admin_status_change(self, dvs, sub_port_intf_name): fv_dict = { ADMIN_STATUS: "up", } + if vrf_name: + fv_dict[VRF_NAME] = vrf_name self.check_sub_port_intf_fvs(self.app_db, APP_INTF_TABLE_NAME, sub_port_intf_name, fv_dict) fv_dict = { "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V4_STATE": "true", "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V6_STATE": "true", "SAI_ROUTER_INTERFACE_ATTR_MTU": DEFAULT_MTU, + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": vrf_oid, } rif_oid = self.get_newly_created_oid(ASIC_RIF_TABLE, old_rif_oids) self.check_sub_port_intf_fvs(self.asic_db, ASIC_RIF_TABLE, rif_oid, fv_dict) @@ -425,6 +586,8 @@ def _test_sub_port_intf_admin_status_change(self, dvs, sub_port_intf_name): fv_dict = { ADMIN_STATUS: "down", } + if vrf_name: + fv_dict[VRF_NAME] = vrf_name self.check_sub_port_intf_fvs(self.app_db, APP_INTF_TABLE_NAME, sub_port_intf_name, fv_dict) # Verify that sub port router interface entry in ASIC_DB has the updated admin status @@ -432,6 +595,7 @@ def _test_sub_port_intf_admin_status_change(self, dvs, sub_port_intf_name): "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V4_STATE": "false", "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V6_STATE": "false", "SAI_ROUTER_INTERFACE_ATTR_MTU": DEFAULT_MTU, + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": vrf_oid, } rif_oid = self.get_newly_created_oid(ASIC_RIF_TABLE, old_rif_oids) self.check_sub_port_intf_fvs(self.asic_db, ASIC_RIF_TABLE, rif_oid, fv_dict) @@ -443,6 +607,8 @@ def _test_sub_port_intf_admin_status_change(self, dvs, sub_port_intf_name): fv_dict = { ADMIN_STATUS: "up", } + if vrf_name: + fv_dict[VRF_NAME] = vrf_name self.check_sub_port_intf_fvs(self.app_db, APP_INTF_TABLE_NAME, sub_port_intf_name, fv_dict) # Verify that sub port router interface entry in ASIC_DB has the updated admin status @@ -450,6 +616,7 @@ def _test_sub_port_intf_admin_status_change(self, dvs, sub_port_intf_name): "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V4_STATE": "true", "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V6_STATE": "true", "SAI_ROUTER_INTERFACE_ATTR_MTU": DEFAULT_MTU, + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": vrf_oid, } rif_oid = self.get_newly_created_oid(ASIC_RIF_TABLE, old_rif_oids) self.check_sub_port_intf_fvs(self.asic_db, ASIC_RIF_TABLE, rif_oid, fv_dict) @@ -465,20 +632,36 @@ def _test_sub_port_intf_admin_status_change(self, dvs, sub_port_intf_name): self.remove_sub_port_intf_profile(sub_port_intf_name) self.check_sub_port_intf_profile_removal(rif_oid) + # Remove vrf if created + if vrf_name: + self.remove_vrf(vrf_name) + self.check_vrf_removal(vrf_oid) + + # Remove lag + if parent_port.startswith(LAG_PREFIX): + self.remove_lag(parent_port) + self.asic_db.wait_for_n_keys(ASIC_LAG_TABLE, 0) + def test_sub_port_intf_admin_status_change(self, dvs): self.connect_dbs(dvs) self._test_sub_port_intf_admin_status_change(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST) self._test_sub_port_intf_admin_status_change(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST) - def _test_sub_port_intf_remove_ip_addrs(self, dvs, sub_port_intf_name): + self._test_sub_port_intf_admin_status_change(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, self.VRF_UNDER_TEST) + self._test_sub_port_intf_admin_status_change(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, self.VRF_UNDER_TEST) + + def _test_sub_port_intf_remove_ip_addrs(self, dvs, sub_port_intf_name, vrf_name=None): substrs = sub_port_intf_name.split(VLAN_SUB_INTERFACE_SEPARATOR) parent_port = substrs[0] old_rif_oids = self.get_oids(ASIC_RIF_TABLE) self.set_parent_port_admin_status(dvs, parent_port, "up") - self.create_sub_port_intf_profile(sub_port_intf_name) + if vrf_name: + self.create_vrf(vrf_name) + self.asic_db.wait_for_n_keys(ASIC_VIRTUAL_ROUTER_TABLE, 2) + self.create_sub_port_intf_profile(sub_port_intf_name, vrf_name) self.add_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV4_ADDR_UNDER_TEST) self.add_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV6_ADDR_UNDER_TEST) @@ -489,12 +672,12 @@ def _test_sub_port_intf_remove_ip_addrs(self, dvs, sub_port_intf_name): self.remove_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV4_ADDR_UNDER_TEST) # Verify that IPv4 address state ok is removed from STATE_DB INTERFACE_TABLE by Intfmgrd - self.check_sub_port_intf_key_removal(self.state_db, STATE_INTERFACE_TABLE_NAME, \ - sub_port_intf_name + "|" + self.IPV4_ADDR_UNDER_TEST) + self.check_sub_port_intf_key_removal(self.state_db, STATE_INTERFACE_TABLE_NAME, + sub_port_intf_name + "|" + self.IPV4_ADDR_UNDER_TEST) # Verify that IPv4 address configuration is removed from APPL_DB INTF_TABLE by Intfmgrd - self.check_sub_port_intf_key_removal(self.app_db, APP_INTF_TABLE_NAME, \ - sub_port_intf_name + ":" + self.IPV4_ADDR_UNDER_TEST) + self.check_sub_port_intf_key_removal(self.app_db, APP_INTF_TABLE_NAME, + sub_port_intf_name + ":" + self.IPV4_ADDR_UNDER_TEST) # Verify that IPv4 subnet route entry is removed from ASIC_DB # Verify that IPv4 ip2me route entry is removed from ASIC_DB @@ -505,12 +688,12 @@ def _test_sub_port_intf_remove_ip_addrs(self, dvs, sub_port_intf_name): self.remove_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV6_ADDR_UNDER_TEST) # Verify that IPv6 address state ok is removed from STATE_DB INTERFACE_TABLE by Intfmgrd - self.check_sub_port_intf_key_removal(self.state_db, STATE_INTERFACE_TABLE_NAME, \ - sub_port_intf_name + "|" + self.IPV6_ADDR_UNDER_TEST) + self.check_sub_port_intf_key_removal(self.state_db, STATE_INTERFACE_TABLE_NAME, + sub_port_intf_name + "|" + self.IPV6_ADDR_UNDER_TEST) # Verify that IPv6 address configuration is removed from APPL_DB INTF_TABLE by Intfmgrd - self.check_sub_port_intf_key_removal(self.app_db, APP_INTF_TABLE_NAME, \ - sub_port_intf_name + ":" + self.IPV6_ADDR_UNDER_TEST) + self.check_sub_port_intf_key_removal(self.app_db, APP_INTF_TABLE_NAME, + sub_port_intf_name + ":" + self.IPV6_ADDR_UNDER_TEST) # Verify that IPv6 subnet route entry is removed from ASIC_DB # Verify that IPv6 ip2me route entry is removed from ASIC_DB @@ -524,47 +707,120 @@ def _test_sub_port_intf_remove_ip_addrs(self, dvs, sub_port_intf_name): self.remove_sub_port_intf_profile(sub_port_intf_name) self.check_sub_port_intf_profile_removal(rif_oid) + # Remove vrf if created + if vrf_name: + self.remove_vrf(vrf_name) + self.asic_db.wait_for_n_keys(ASIC_VIRTUAL_ROUTER_TABLE, 1) + + # Remove lag + if parent_port.startswith(LAG_PREFIX): + self.remove_lag(parent_port) + self.asic_db.wait_for_n_keys(ASIC_LAG_TABLE, 0) + def test_sub_port_intf_remove_ip_addrs(self, dvs): self.connect_dbs(dvs) self._test_sub_port_intf_remove_ip_addrs(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST) self._test_sub_port_intf_remove_ip_addrs(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST) - def _test_sub_port_intf_removal(self, dvs, sub_port_intf_name): + self._test_sub_port_intf_remove_ip_addrs(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, self.VRF_UNDER_TEST) + self._test_sub_port_intf_remove_ip_addrs(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, self.VRF_UNDER_TEST) + + def _test_sub_port_intf_removal(self, dvs, sub_port_intf_name, removal_seq_test=False, vrf_name=None): substrs = sub_port_intf_name.split(VLAN_SUB_INTERFACE_SEPARATOR) parent_port = substrs[0] + vlan_id = substrs[1] if parent_port.startswith(ETHERNET_PREFIX): state_tbl_name = STATE_PORT_TABLE_NAME phy_ports = [parent_port] + parent_port_oid = dvs.asicdb.portnamemap[parent_port] else: assert parent_port.startswith(LAG_PREFIX) state_tbl_name = STATE_LAG_TABLE_NAME phy_ports = self.LAG_MEMBERS_UNDER_TEST + old_lag_oids = self.get_oids(ASIC_LAG_TABLE) + vrf_oid = self.default_vrf_oid old_rif_oids = self.get_oids(ASIC_RIF_TABLE) self.set_parent_port_admin_status(dvs, parent_port, "up") - # Add lag members to test physical port host interface vlan tag attribute if parent_port.startswith(LAG_PREFIX): + parent_port_oid = self.get_newly_created_oid(ASIC_LAG_TABLE, old_lag_oids) + # Add lag members to test physical port host interface vlan tag attribute self.add_lag_members(parent_port, self.LAG_MEMBERS_UNDER_TEST) self.asic_db.wait_for_n_keys(ASIC_LAG_MEMBER_TABLE, len(self.LAG_MEMBERS_UNDER_TEST)) - self.create_sub_port_intf_profile(sub_port_intf_name) + if vrf_name: + self.create_vrf(vrf_name) + vrf_oid = self.get_newly_created_oid(ASIC_VIRTUAL_ROUTER_TABLE, [vrf_oid]) + self.create_sub_port_intf_profile(sub_port_intf_name, vrf_name) self.add_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV4_ADDR_UNDER_TEST) self.add_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV6_ADDR_UNDER_TEST) - rif_oid = self.get_newly_created_oid(ASIC_RIF_TABLE, old_rif_oids) - fv_dict = { "state": "ok", } self.check_sub_port_intf_fvs(self.state_db, state_tbl_name, sub_port_intf_name, fv_dict) + fv_dict = { + "vrf": vrf_name if vrf_name else "", + } + self.check_sub_port_intf_fvs(self.state_db, STATE_INTERFACE_TABLE_NAME, sub_port_intf_name, fv_dict) + + if vrf_name: + self.check_sub_port_intf_vrf_bind_kernel(dvs, sub_port_intf_name, vrf_name) + self.check_sub_port_intf_vrf_nobind_kernel(dvs, parent_port, vrf_name) + fv_dict = { ADMIN_STATUS: "up", } + if vrf_name: + fv_dict[VRF_NAME] = vrf_name self.check_sub_port_intf_fvs(self.app_db, APP_INTF_TABLE_NAME, sub_port_intf_name, fv_dict) + if removal_seq_test == True: + # Remove a sub port interface before removing sub port interface IP addresses + self.remove_sub_port_intf_profile(sub_port_intf_name) + time.sleep(2) + + # Verify that sub port interface state ok persists in STATE_DB + fv_dict = { + "state": "ok", + } + self.check_sub_port_intf_fvs(self.state_db, state_tbl_name, sub_port_intf_name, fv_dict) + # Verify vrf name sub port interface bound to persists in STATE_DB INTERFACE_TABLE + fv_dict = { + "vrf": vrf_name if vrf_name else "", + } + self.check_sub_port_intf_fvs(self.state_db, STATE_INTERFACE_TABLE_NAME, sub_port_intf_name, fv_dict) + # If bound to non-default vrf, verify sub port interface vrf binding in linux kernel, + # and parent port not bound to vrf + if vrf_name: + self.check_sub_port_intf_vrf_bind_kernel(dvs, sub_port_intf_name, vrf_name) + self.check_sub_port_intf_vrf_nobind_kernel(dvs, parent_port, vrf_name) + # Verify that sub port interface configuration persists in APPL_DB INTF_TABLE + fv_dict = { + ADMIN_STATUS: "up", + } + if vrf_name: + fv_dict[VRF_NAME] = vrf_name + self.check_sub_port_intf_fvs(self.app_db, APP_INTF_TABLE_NAME, sub_port_intf_name, fv_dict) + + # Verify that a sub port router interface entry persists in ASIC_DB + fv_dict = { + "SAI_ROUTER_INTERFACE_ATTR_TYPE": "SAI_ROUTER_INTERFACE_TYPE_SUB_PORT", + "SAI_ROUTER_INTERFACE_ATTR_OUTER_VLAN_ID": "{}".format(vlan_id), + "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V4_STATE": "true", + "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V6_STATE": "true", + "SAI_ROUTER_INTERFACE_ATTR_MTU": DEFAULT_MTU, + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": vrf_oid, + "SAI_ROUTER_INTERFACE_ATTR_PORT_ID": parent_port_oid, + } + rif_oid = self.get_newly_created_oid(ASIC_RIF_TABLE, old_rif_oids) + self.check_sub_port_intf_fvs(self.asic_db, ASIC_RIF_TABLE, rif_oid, fv_dict) + else: + rif_oid = self.get_newly_created_oid(ASIC_RIF_TABLE, old_rif_oids) + # Remove IP addresses self.remove_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV4_ADDR_UNDER_TEST) self.remove_sub_port_intf_ip_addr(sub_port_intf_name, self.IPV6_ADDR_UNDER_TEST) @@ -572,13 +828,23 @@ def _test_sub_port_intf_removal(self, dvs, sub_port_intf_name): [self.IPV4_ADDR_UNDER_TEST, self.IPV6_ADDR_UNDER_TEST]) - # Remove a sub port interface - self.remove_sub_port_intf_profile(sub_port_intf_name) + if removal_seq_test == False: + # Remove a sub port interface + self.remove_sub_port_intf_profile(sub_port_intf_name) self.check_sub_port_intf_profile_removal(rif_oid) # Verify that sub port interface state ok is removed from STATE_DB by Intfmgrd self.check_sub_port_intf_key_removal(self.state_db, state_tbl_name, sub_port_intf_name) + # Verify sub port interface not exist in linux kernel + self.check_sub_port_intf_removal_kernel(dvs, sub_port_intf_name) + # If bound to non-default vrf, verify parent port not bound to vrf + if vrf_name: + self.check_sub_port_intf_vrf_nobind_kernel(dvs, parent_port, vrf_name) + + # Verify vrf name sub port interface bound to is removed from STATE_DB INTERFACE_TABLE + self.check_sub_port_intf_key_removal(self.state_db, STATE_INTERFACE_TABLE_NAME, sub_port_intf_name) + # Verify that sub port interface configuration is removed from APP_DB by Intfmgrd self.check_sub_port_intf_key_removal(self.app_db, APP_INTF_TABLE_NAME, sub_port_intf_name) @@ -593,25 +859,47 @@ def _test_sub_port_intf_removal(self, dvs, sub_port_intf_name): hostif_oid = dvs.asicdb.hostifnamemap[phy_port] self.check_sub_port_intf_fvs(self.asic_db, ASIC_HOSTIF_TABLE, hostif_oid, fv_dict) - # Remove lag members from lag parent port + # Remove vrf if created + if vrf_name: + self.remove_vrf(vrf_name) + self.asic_db.wait_for_n_keys(ASIC_VIRTUAL_ROUTER_TABLE, 1) + if parent_port.startswith(LAG_PREFIX): + # Remove lag members from lag parent port self.remove_lag_members(parent_port, self.LAG_MEMBERS_UNDER_TEST) self.asic_db.wait_for_n_keys(ASIC_LAG_MEMBER_TABLE, 0) + # Remove lag + self.remove_lag(parent_port) + self.check_lag_removal(parent_port_oid) + def test_sub_port_intf_removal(self, dvs): self.connect_dbs(dvs) self._test_sub_port_intf_removal(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST) self._test_sub_port_intf_removal(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST) - def _test_sub_port_intf_mtu(self, dvs, sub_port_intf_name): + self._test_sub_port_intf_removal(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, vrf_name=self.VRF_UNDER_TEST) + self._test_sub_port_intf_removal(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, vrf_name=self.VRF_UNDER_TEST) + + self._test_sub_port_intf_removal(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, removal_seq_test=True) + self._test_sub_port_intf_removal(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, removal_seq_test=True) + + self._test_sub_port_intf_removal(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, removal_seq_test=True, vrf_name=self.VRF_UNDER_TEST) + self._test_sub_port_intf_removal(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, removal_seq_test=True, vrf_name=self.VRF_UNDER_TEST) + + def _test_sub_port_intf_mtu(self, dvs, sub_port_intf_name, vrf_name=None): substrs = sub_port_intf_name.split(VLAN_SUB_INTERFACE_SEPARATOR) parent_port = substrs[0] + vrf_oid = self.default_vrf_oid old_rif_oids = self.get_oids(ASIC_RIF_TABLE) self.set_parent_port_admin_status(dvs, parent_port, "up") - self.create_sub_port_intf_profile(sub_port_intf_name) + if vrf_name: + self.create_vrf(vrf_name) + vrf_oid = self.get_newly_created_oid(ASIC_VIRTUAL_ROUTER_TABLE, [vrf_oid]) + self.create_sub_port_intf_profile(sub_port_intf_name, vrf_name) rif_oid = self.get_newly_created_oid(ASIC_RIF_TABLE, old_rif_oids) @@ -622,6 +910,7 @@ def _test_sub_port_intf_mtu(self, dvs, sub_port_intf_name): # Verify that sub port router interface entry in ASIC_DB has the updated mtu fv_dict = { "SAI_ROUTER_INTERFACE_ATTR_MTU": mtu, + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": vrf_oid, } self.check_sub_port_intf_fvs(self.asic_db, ASIC_RIF_TABLE, rif_oid, fv_dict) @@ -631,6 +920,7 @@ def _test_sub_port_intf_mtu(self, dvs, sub_port_intf_name): # Verify that sub port router interface entry in ASIC_DB has the default mtu fv_dict = { "SAI_ROUTER_INTERFACE_ATTR_MTU": DEFAULT_MTU, + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": vrf_oid, } self.check_sub_port_intf_fvs(self.asic_db, ASIC_RIF_TABLE, rif_oid, fv_dict) @@ -638,13 +928,26 @@ def _test_sub_port_intf_mtu(self, dvs, sub_port_intf_name): self.remove_sub_port_intf_profile(sub_port_intf_name) self.check_sub_port_intf_profile_removal(rif_oid) + # Remove vrf if created + if vrf_name: + self.remove_vrf(vrf_name) + self.check_vrf_removal(vrf_oid) + + # Remove lag + if parent_port.startswith(LAG_PREFIX): + self.remove_lag(parent_port) + self.asic_db.wait_for_n_keys(ASIC_LAG_TABLE, 0) + def test_sub_port_intf_mtu(self, dvs): self.connect_dbs(dvs) self._test_sub_port_intf_mtu(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST) self._test_sub_port_intf_mtu(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST) - def create_nhg_router_intfs(self, dvs, parent_port_prefix, parent_port_idx_base, vlan_id, nhop_num): + self._test_sub_port_intf_mtu(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, self.VRF_UNDER_TEST) + self._test_sub_port_intf_mtu(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, self.VRF_UNDER_TEST) + + def create_nhg_router_intfs(self, dvs, parent_port_prefix, parent_port_idx_base, vlan_id, nhop_num, vrf_name=None): ifnames = [] parent_port_idx = parent_port_idx_base for i in range(0, nhop_num): @@ -654,10 +957,10 @@ def create_nhg_router_intfs(self, dvs, parent_port_prefix, parent_port_idx_base, port_name = "{}{}".format(parent_port_prefix, parent_port_idx) ip_addr = "10.{}.{}.0/31".format(parent_port_idx, vlan_id) if vlan_id != 0: - self.create_sub_port_intf_profile(port_name) + self.create_sub_port_intf_profile(port_name, vrf_name) self.add_sub_port_intf_ip_addr(port_name, ip_addr) else: - dvs.add_ip_address(port_name, ip_addr) + dvs.add_ip_address(port_name, ip_addr, vrf_name) ifnames.append(port_name) @@ -668,9 +971,13 @@ def create_nhg_next_hop_objs(self, dvs, parent_port_prefix, parent_port_idx_base nhop_ips = [] parent_port_idx = parent_port_idx_base for i in range(0, nhop_num): + if vlan_id != 0: + port_name = "{}{}.{}".format(parent_port_prefix, parent_port_idx, vlan_id) + else: + port_name = "{}{}".format(parent_port_prefix, parent_port_idx) nhop_ip = "10.{}.{}.1".format(parent_port_idx, vlan_id) nhop_mac = "00:00:00:{:02d}:{}:01".format(parent_port_idx, vlan_id) - dvs.runcmd("arp -s " + nhop_ip + " " + nhop_mac) + dvs.runcmd("ip neigh add " + nhop_ip + " lladdr " + nhop_mac + " dev " + port_name) nhop_ips.append(nhop_ip) @@ -698,12 +1005,16 @@ def remove_nhg_router_intfs(self, dvs, parent_port_prefix, parent_port_idx_base, def remove_nhg_next_hop_objs(self, dvs, parent_port_prefix, parent_port_idx_base, vlan_id, nhop_num): parent_port_idx = parent_port_idx_base for i in range(0, nhop_num): + if vlan_id != 0: + port_name = "{}{}.{}".format(parent_port_prefix, parent_port_idx, vlan_id) + else: + port_name = "{}{}".format(parent_port_prefix, parent_port_idx) nhop_ip = "10.{}.{}.1".format(parent_port_idx, vlan_id) - dvs.runcmd("arp -d " + nhop_ip) + dvs.runcmd("ip neigh del " + nhop_ip + " dev " + port_name) parent_port_idx += (4 if parent_port_prefix == ETHERNET_PREFIX else 1) - def check_nhg_members_on_parent_port_oper_status_change(self, dvs, parent_port_prefix, parent_port_idx_base, status, \ + def check_nhg_members_on_parent_port_oper_status_change(self, dvs, parent_port_prefix, parent_port_idx_base, status, nhg_oid, nhop_num, create_intf_on_parent_port): parent_port_idx = parent_port_idx_base for i in range(0, nhop_num): @@ -721,12 +1032,12 @@ def check_nhg_members_on_parent_port_oper_status_change(self, dvs, parent_port_p # Verify next hop group member # in ASIC_DB if status == "up": - nhg_member_oids = self.asic_db.wait_for_n_keys(ASIC_NEXT_HOP_GROUP_MEMBER_TABLE, \ + nhg_member_oids = self.asic_db.wait_for_n_keys(ASIC_NEXT_HOP_GROUP_MEMBER_TABLE, 1 + i if create_intf_on_parent_port == False else (1 + i) * 2) else: assert status == "down" - nhg_member_oids = self.asic_db.wait_for_n_keys(ASIC_NEXT_HOP_GROUP_MEMBER_TABLE, \ - (nhop_num - 1) - i if create_intf_on_parent_port == False else \ + nhg_member_oids = self.asic_db.wait_for_n_keys(ASIC_NEXT_HOP_GROUP_MEMBER_TABLE, + (nhop_num - 1) - i if create_intf_on_parent_port == False else ((nhop_num - 1) - i) * 2) # Verify that next hop group members in ASIC_DB all @@ -739,7 +1050,7 @@ def check_nhg_members_on_parent_port_oper_status_change(self, dvs, parent_port_p parent_port_idx += (4 if parent_port_prefix == ETHERNET_PREFIX else 1) - def _test_sub_port_intf_nhg_accel(self, dvs, sub_port_intf_name, nhop_num=3, create_intf_on_parent_port=False): + def _test_sub_port_intf_nhg_accel(self, dvs, sub_port_intf_name, nhop_num=3, create_intf_on_parent_port=False, vrf_name=None): substrs = sub_port_intf_name.split(VLAN_SUB_INTERFACE_SEPARATOR) parent_port = substrs[0] vlan_id = substrs[1] @@ -752,6 +1063,8 @@ def _test_sub_port_intf_nhg_accel(self, dvs, sub_port_intf_name, nhop_num=3, cre parent_port_prefix = LAG_PREFIX parent_port_idx_base = self.get_parent_port_index(parent_port) + vrf_oid = self.default_vrf_oid + # Set parent ports admin status up parent_port_idx = parent_port_idx_base for i in range(0, nhop_num): @@ -760,13 +1073,20 @@ def _test_sub_port_intf_nhg_accel(self, dvs, sub_port_intf_name, nhop_num=3, cre parent_port_idx += (4 if parent_port_prefix == ETHERNET_PREFIX else 1) + if vrf_name: + self.create_vrf(vrf_name) + vrf_oid = self.get_newly_created_oid(ASIC_VIRTUAL_ROUTER_TABLE, [vrf_oid]) + ifnames = [] + rif_cnt = len(self.asic_db.get_keys(ASIC_RIF_TABLE)) # Create sub port interfaces - ifnames.extend(self.create_nhg_router_intfs(dvs, parent_port_prefix, parent_port_idx_base, int(vlan_id), nhop_num)) + ifnames.extend(self.create_nhg_router_intfs(dvs, parent_port_prefix, parent_port_idx_base, int(vlan_id), nhop_num, vrf_name)) # Create router interfaces on parent ports if create_intf_on_parent_port == True: - ifnames.extend(self.create_nhg_router_intfs(dvs, parent_port_prefix, parent_port_idx_base, 0, nhop_num)) + ifnames.extend(self.create_nhg_router_intfs(dvs, parent_port_prefix, parent_port_idx_base, 0, nhop_num, vrf_name)) + + self.asic_db.wait_for_n_keys(ASIC_RIF_TABLE, rif_cnt + nhop_num if create_intf_on_parent_port == False else rif_cnt + nhop_num * 2) nhop_ips = [] nhop_cnt = len(self.asic_db.get_keys(ASIC_NEXT_HOP_TABLE)) @@ -780,19 +1100,17 @@ def _test_sub_port_intf_nhg_accel(self, dvs, sub_port_intf_name, nhop_num=3, cre self.asic_db.wait_for_n_keys(ASIC_NEXT_HOP_TABLE, nhop_cnt + nhop_num if create_intf_on_parent_port == False else nhop_cnt + nhop_num * 2) # Create multi-next-hop route entry - rt_tbl = swsscommon.ProducerStateTable(self.app_db.db_connection, APP_ROUTE_TABLE_NAME) - fvs = swsscommon.FieldValuePairs([("nexthop", ",".join(nhop_ips)), ("ifname", ",".join(ifnames))]) ip_prefix = "2.2.2.0/24" - rt_tbl.set(ip_prefix, fvs) + self.add_route_appl_db(ip_prefix, nhop_ips, ifnames, vrf_name) # Verify route entry created in ASIC_DB and get next hop group oid - nhg_oid = self.get_ip_prefix_nhg_oid(ip_prefix) + nhg_oid = self.get_ip_prefix_nhg_oid(ip_prefix, vrf_oid) # Verify next hop group of the specified oid created in ASIC_DB self.check_sub_port_intf_key_existence(self.asic_db, ASIC_NEXT_HOP_GROUP_TABLE, nhg_oid) # Verify next hop group members created in ASIC_DB - nhg_member_oids = self.asic_db.wait_for_n_keys(ASIC_NEXT_HOP_GROUP_MEMBER_TABLE, \ + nhg_member_oids = self.asic_db.wait_for_n_keys(ASIC_NEXT_HOP_GROUP_MEMBER_TABLE, nhop_num if create_intf_on_parent_port == False else nhop_num * 2) # Verify that next hop group members all belong to the next hop group of the specified oid @@ -803,16 +1121,19 @@ def _test_sub_port_intf_nhg_accel(self, dvs, sub_port_intf_name, nhop_num=3, cre self.check_sub_port_intf_fvs(self.asic_db, ASIC_NEXT_HOP_GROUP_MEMBER_TABLE, nhg_member_oid, fv_dict) # Bring parent ports oper status down one at a time, and verify next hop group members - self.check_nhg_members_on_parent_port_oper_status_change(dvs, parent_port_prefix, parent_port_idx_base, "down", \ + self.check_nhg_members_on_parent_port_oper_status_change(dvs, parent_port_prefix, parent_port_idx_base, "down", nhg_oid, nhop_num, create_intf_on_parent_port) # Bring parent ports oper status up one at a time, and verify next hop group members - self.check_nhg_members_on_parent_port_oper_status_change(dvs, parent_port_prefix, parent_port_idx_base, "up", \ + self.check_nhg_members_on_parent_port_oper_status_change(dvs, parent_port_prefix, parent_port_idx_base, "up", nhg_oid, nhop_num, create_intf_on_parent_port) # Clean up rif_cnt = len(self.asic_db.get_keys(ASIC_RIF_TABLE)) + # Remove ecmp route entry + self.remove_route_appl_db(ip_prefix, vrf_name) + # Remove sub port interfaces self.remove_nhg_router_intfs(dvs, parent_port_prefix, parent_port_idx_base, int(vlan_id), nhop_num) @@ -820,17 +1141,24 @@ def _test_sub_port_intf_nhg_accel(self, dvs, sub_port_intf_name, nhop_num=3, cre if create_intf_on_parent_port == True: self.remove_nhg_router_intfs(dvs, parent_port_prefix, parent_port_idx_base, 0, nhop_num) - # Remove ecmp route entry - rt_tbl._del(ip_prefix) - # Removal of router interfaces indicates the proper removal of nhg, nhg members, next hop objects, and neighbor entries self.asic_db.wait_for_n_keys(ASIC_RIF_TABLE, rif_cnt - nhop_num if create_intf_on_parent_port == False else rif_cnt - nhop_num * 2) - # Make sure parent port is oper status up + # Remove vrf if created + if vrf_name: + self.remove_vrf(vrf_name) + self.check_vrf_removal(vrf_oid) + parent_port_idx = parent_port_idx_base for i in range(0, nhop_num): port_name = "{}{}".format(parent_port_prefix, parent_port_idx) - self.set_parent_port_oper_status(dvs, port_name, "up") + if parent_port.startswith(ETHERNET_PREFIX): + # Make sure physical port is oper status up + self.set_parent_port_oper_status(dvs, port_name, "up") + else: + # Remove lag + self.remove_lag(port_name) + self.asic_db.wait_for_n_keys(ASIC_LAG_TABLE, nhop_num - 1 - i) parent_port_idx += (4 if parent_port_prefix == ETHERNET_PREFIX else 1) @@ -842,7 +1170,15 @@ def test_sub_port_intf_nhg_accel(self, dvs): self._test_sub_port_intf_nhg_accel(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST) self._test_sub_port_intf_nhg_accel(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, create_intf_on_parent_port=True) - def _test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(self, dvs, sub_port_intf_name, nhop_num=3, create_intf_on_parent_port=False): + self._test_sub_port_intf_nhg_accel(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, vrf_name=self.VRF_UNDER_TEST) + self._test_sub_port_intf_nhg_accel(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, + create_intf_on_parent_port=True, vrf_name=self.VRF_UNDER_TEST) + self._test_sub_port_intf_nhg_accel(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, vrf_name=self.VRF_UNDER_TEST) + self._test_sub_port_intf_nhg_accel(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, + create_intf_on_parent_port=True, vrf_name=self.VRF_UNDER_TEST) + + def _test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(self, dvs, sub_port_intf_name, nhop_num=3, + create_intf_on_parent_port=False, vrf_name=None): substrs = sub_port_intf_name.split(VLAN_SUB_INTERFACE_SEPARATOR) parent_port = substrs[0] vlan_id = substrs[1] @@ -855,6 +1191,8 @@ def _test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(self, dvs, sub_ parent_port_prefix = LAG_PREFIX parent_port_idx_base = self.get_parent_port_index(parent_port) + vrf_oid = self.default_vrf_oid + # Set parent ports admin status up parent_port_idx = parent_port_idx_base for i in range(0, nhop_num): @@ -863,12 +1201,18 @@ def _test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(self, dvs, sub_ parent_port_idx += (4 if parent_port_prefix == ETHERNET_PREFIX else 1) + if vrf_name: + self.create_vrf(vrf_name) + vrf_oid = self.get_newly_created_oid(ASIC_VIRTUAL_ROUTER_TABLE, [vrf_oid]) + ifnames = [] + rif_cnt = len(self.asic_db.get_keys(ASIC_RIF_TABLE)) # Create sub port interfaces - ifnames.extend(self.create_nhg_router_intfs(dvs, parent_port_prefix, parent_port_idx_base, int(vlan_id), nhop_num)) + ifnames.extend(self.create_nhg_router_intfs(dvs, parent_port_prefix, parent_port_idx_base, int(vlan_id), nhop_num, vrf_name)) # Create router interfaces on parent ports if create_intf_on_parent_port == True: - ifnames.extend(self.create_nhg_router_intfs(dvs, parent_port_prefix, parent_port_idx_base, 0, nhop_num)) + ifnames.extend(self.create_nhg_router_intfs(dvs, parent_port_prefix, parent_port_idx_base, 0, nhop_num, vrf_name)) + self.asic_db.wait_for_n_keys(ASIC_RIF_TABLE, rif_cnt + nhop_num if create_intf_on_parent_port == False else rif_cnt + nhop_num * 2) # Bring parent port oper status down one at a time # Verify next hop group members created after processing pending tasks @@ -897,19 +1241,17 @@ def _test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(self, dvs, sub_ self.asic_db.wait_for_n_keys(ASIC_NEXT_HOP_TABLE, nhop_cnt + nhop_num if create_intf_on_parent_port == False else nhop_cnt + nhop_num * 2) # Mimic pending multi-next-hop route entry task - rt_tbl = swsscommon.ProducerStateTable(self.app_db.db_connection, APP_ROUTE_TABLE_NAME) - fvs = swsscommon.FieldValuePairs([("nexthop", ",".join(nhop_ips)), ("ifname", ",".join(ifnames))]) ip_prefix = "2.2.2.0/24" - rt_tbl.set(ip_prefix, fvs) + self.add_route_appl_db(ip_prefix, nhop_ips, ifnames, vrf_name) # Verify route entry created in ASIC_DB and get next hop group oid - nhg_oid = self.get_ip_prefix_nhg_oid(ip_prefix) + nhg_oid = self.get_ip_prefix_nhg_oid(ip_prefix, vrf_oid) # Verify next hop group of the specified oid created in ASIC_DB self.check_sub_port_intf_key_existence(self.asic_db, ASIC_NEXT_HOP_GROUP_TABLE, nhg_oid) # Verify next hop group member # created in ASIC_DB - nhg_member_oids = self.asic_db.wait_for_n_keys(ASIC_NEXT_HOP_GROUP_MEMBER_TABLE, \ + nhg_member_oids = self.asic_db.wait_for_n_keys(ASIC_NEXT_HOP_GROUP_MEMBER_TABLE, (nhop_num - 1) - i if create_intf_on_parent_port == False else ((nhop_num - 1) - i) * 2) # Verify that next hop group members all belong to the next hop group of the specified oid @@ -926,7 +1268,7 @@ def _test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(self, dvs, sub_ if create_intf_on_parent_port == True: self.remove_nhg_next_hop_objs(dvs, parent_port_prefix, parent_port_idx_base, 0, nhop_num) # Remove ecmp route entry - rt_tbl._del(ip_prefix) + self.remove_route_appl_db(ip_prefix, vrf_name) # Removal of next hop objects indicates the proper removal of route entry, nhg, and nhg members self.asic_db.wait_for_n_keys(ASIC_NEXT_HOP_TABLE, nhop_cnt - nhop_num if create_intf_on_parent_port == False else nhop_cnt - nhop_num * 2) @@ -941,11 +1283,21 @@ def _test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(self, dvs, sub_ self.remove_nhg_router_intfs(dvs, parent_port_prefix, parent_port_idx_base, 0, nhop_num) self.asic_db.wait_for_n_keys(ASIC_RIF_TABLE, rif_cnt - nhop_num if create_intf_on_parent_port == False else rif_cnt - nhop_num * 2) - # Make sure parent port oper status is up + # Remove vrf if created + if vrf_name: + self.remove_vrf(vrf_name) + self.check_vrf_removal(vrf_oid) + parent_port_idx = parent_port_idx_base for i in range(0, nhop_num): port_name = "{}{}".format(parent_port_prefix, parent_port_idx) - self.set_parent_port_oper_status(dvs, port_name, "up") + if parent_port.startswith(ETHERNET_PREFIX): + # Make sure physical port oper status is up + self.set_parent_port_oper_status(dvs, port_name, "up") + else: + # Remove lag + self.remove_lag(port_name) + self.asic_db.wait_for_n_keys(ASIC_LAG_TABLE, nhop_num - 1 - i) parent_port_idx += (4 if parent_port_prefix == ETHERNET_PREFIX else 1) @@ -957,6 +1309,13 @@ def test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(self, dvs): self._test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST) self._test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, create_intf_on_parent_port=True) + self._test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, vrf_name=self.VRF_UNDER_TEST) + self._test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(dvs, self.SUB_PORT_INTERFACE_UNDER_TEST, + create_intf_on_parent_port=True, vrf_name=self.VRF_UNDER_TEST) + self._test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, vrf_name=self.VRF_UNDER_TEST) + self._test_sub_port_intf_oper_down_with_pending_neigh_route_tasks(dvs, self.LAG_SUB_PORT_INTERFACE_UNDER_TEST, + create_intf_on_parent_port=True, vrf_name=self.VRF_UNDER_TEST) + # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying