From 35d85ee92ac0e5b1de5e048fbc0077815cfa3f1f Mon Sep 17 00:00:00 2001 From: Vasant Patil <36455926+vasant17@users.noreply.github.com> Date: Tue, 29 Oct 2019 13:58:47 -0700 Subject: [PATCH] DPB test case (#5) * DPB test case * Update test case * Remove pdb statements * DPB test cases phase1 * DPB test cases phase1 updated * Addressed code-review comments by Xu --- portsyncd/linksync.cpp | 9 +- tests/conftest.py | 6 ++ tests/port_dpb.py | 200 ++++++++++++++++++++++++++++++++++++++ tests/test_port_config.py | 20 ++-- tests/test_port_dpb.py | 175 +++++++++++++++++++++++++++++++++ 5 files changed, 393 insertions(+), 17 deletions(-) create mode 100644 tests/port_dpb.py create mode 100644 tests/test_port_dpb.py diff --git a/portsyncd/linksync.cpp b/portsyncd/linksync.cpp index da7e3a5e12..fa601e3ef9 100644 --- a/portsyncd/linksync.cpp +++ b/portsyncd/linksync.cpp @@ -151,6 +151,7 @@ LinkSync::LinkSync(DBConnector *appl_db, DBConnector *state_db) : void LinkSync::onMsg(int nlmsg_type, struct nl_object *obj) { + SWSS_LOG_ENTER(); if ((nlmsg_type != RTM_NEWLINK) && (nlmsg_type != RTM_DELLINK)) { return; @@ -222,11 +223,11 @@ void LinkSync::onMsg(int nlmsg_type, struct nl_object *obj) /* Insert or update the ifindex to key map */ m_ifindexNameMap[ifindex] = key; - /* TODO: When port is removed from the kernel */ if (nlmsg_type == RTM_DELLINK) { m_statePortTable.del(key); SWSS_LOG_NOTICE("Delete %s(ok) from state db", key.c_str()); + return; } /* front panel interfaces: Check if the port is in the PORT_TABLE @@ -235,12 +236,6 @@ void LinkSync::onMsg(int nlmsg_type, struct nl_object *obj) vector temp; if (m_portTable.get(key, temp)) { - /* TODO: When port is removed from the kernel */ - if (nlmsg_type == RTM_DELLINK) - { - return; - } - /* Host interface is created */ if (!g_init && g_portSet.find(key) != g_portSet.end()) { diff --git a/tests/conftest.py b/tests/conftest.py index c510e441cd..650ece0d2f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -320,6 +320,12 @@ def start_swss(self): cmd += "supervisorctl start {}; ".format(pname) self.runcmd(['sh', '-c', cmd]) + def stop_all_daemons(self): + cmd = "" + for pname in self.alld: + cmd += "supervisorctl stop {}; ".format(pname) + self.runcmd(['sh', '-c', cmd]) + # stop processes in SWSS def stop_swss(self): cmd = "" diff --git a/tests/port_dpb.py b/tests/port_dpb.py new file mode 100644 index 0000000000..6000b57984 --- /dev/null +++ b/tests/port_dpb.py @@ -0,0 +1,200 @@ +from swsscommon import swsscommon +import redis +import time +import os +import pytest +from pytest import * +import json +import re + +class Port(): + def __init__(self, dvs, name = None): + self._name = name + if name != None: + self._port_num = int(re.compile(r'(\d+)$').search(self._name).group(1)) + self._alias = None + self._speed = None + self._lanes = [] + self._index = None + self._lanes_db_str = None + self._lanes_asic_db_str = None + self._oid = None + self._dvs = dvs + self._cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + self._cfg_db_ptbl = swsscommon.Table(self._cfg_db, "PORT") + self._app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + self._app_db_ptbl = swsscommon.Table(self._app_db, swsscommon.APP_PORT_TABLE_NAME) + self._asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + self._asic_db_ptbl = swsscommon.Table(self._asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_PORT") + + def set_name(self, name): + self._name = name + self._port_num = int(re.compile(r'(\d+)$').search(self._name).group(1)) + + def set_speed(self, speed): + self._speed = speed + + def set_alias(self, alias): + self._alias = alias + + def set_lanes(self, lanes): + self._lanes = lanes + lanes_list = [] + for lane in lanes: + lanes_list.append(int(lane)) + lanes_list.sort() + self._lanes_db_str = str(lanes_list)[1:-1] + self._lanes_asic_db_str = str(len(lanes)) + ":" + self._lanes_db_str + self._lanes_asic_db_str = self._lanes_asic_db_str.replace(" ", "") + + def set_index(self, index): + self._index = index + + def get_speed(self): + return self._speed + + def get_alias(self): + return self._alias + + def get_lanes(self): + return self._lanes + + def get_num_lanes(self): + return len(self._lanes) + + def get_index(self): + return self._index + + def get_name(self): + return self._name + + def get_port_num(self): + return self._port_num + + def get_lanes_db_str(self): + return self._lanes_db_str + + def get_lanes_asic_db_str(self): + return self._lanes_asic_db_str + + def get_oid(self): + return self._oid + + def print_port(self): + print "Port: %s Lanes: %s Speed: %d, Index: %d"%(self._name, self._lanes, self._speed, self._index) + + def port_merge(self, child_ports): + child_ports.sort(key=lambda x: x.get_port_num()) + self.set_name(child_ports[0].get_name()) + speed = 0 + for cp in child_ports: + speed = speed + cp.get_speed() + self.set_speed(speed) + self.set_alias(child_ports[0].get_alias().rsplit(',',1)[0]) + self.set_index(child_ports[0].get_index()) + lanes =[] + for cp in child_ports: + for l in cp.get_lanes(): + lanes.append(l) + self.set_lanes(lanes) + + + def port_split(self, child_ports): + if child_ports == 1: + return self + child_port_list = [] + port_num = self.get_port_num() + num_lanes = len(self._lanes) + offset = num_lanes/child_ports; + lanes_per_child = offset + for i in range(child_ports): + child_port_num = port_num + (i * offset) + child_port_name = "Ethernet%d"%(child_port_num) + child_port_alias = "Eth%d/%d"%(port_num, child_port_num) + child_port_lanes = [] + for j in range(lanes_per_child): + child_port_lanes.append(self._lanes[(i*offset)+j]) + child_port_speed = self._speed/child_ports + child_port_index = self._index + + child_port = Port(self._dvs, child_port_name) + child_port.set_alias(child_port_alias) + child_port.set_speed(child_port_speed) + child_port.set_lanes(child_port_lanes) + child_port.set_index(child_port_index) + child_port_list.append(child_port) + return child_port_list + + def delete_from_config_db(self): + self._cfg_db_ptbl._del(self.get_name()) + self._oid = None + + def sync_from_config_db(self): + (status, fvs) = self._cfg_db_ptbl.get(self.get_name()) + assert status == True + fvs_dict = self.get_fvs_dict(fvs) + self.set_alias(fvs_dict['alias']) + self.set_speed(int(fvs_dict['speed'])) + self.set_lanes(list(fvs_dict['lanes'].split(","))) + self.set_index(int(fvs_dict['index'])) + + def write_to_config_db(self): + lanes_str = self.get_lanes_db_str() + index_str = str(self.get_index()) + alias_str = self.get_alias() + speed_str = str(self.get_speed()) + fvs = swsscommon.FieldValuePairs([("alias", alias_str), + ("lanes", lanes_str), + ("speed", speed_str), + ("index", index_str)]) + self._cfg_db_ptbl.set(self.get_name(), fvs) + + def get_fvs_dict(self, fvs): + fvs_dict = {} + for fv in fvs: + fvs_dict.update({fv[0]:fv[1]}) + return fvs_dict + + def exists_in_config_db(self): + (status, _) = self._cfg_db_ptbl.get(self.get_name()) + return status + + def exists_in_app_db(self): + (status, _) = self._app_db_ptbl.get(self.get_name()) + return status + + def exists_in_asic_db(self): + if self._oid is None: + counter_redis_conn = redis.Redis(unix_socket_path=self._dvs.redis_sock, db=swsscommon.COUNTERS_DB) + self._oid = counter_redis_conn.hget("COUNTERS_PORT_NAME_MAP", self.get_name()) + if self._oid is None: + return False + (status, _) = self._asic_db_ptbl.get(self._oid) + return status + + def verify_config_db(self): + (status, fvs) = self._cfg_db_ptbl.get(self.get_name()) + assert(status == True) + fvs_dict = self.get_fvs_dict(fvs) + assert(fvs_dict['alias'] == self.get_alias()) + assert(fvs_dict['lanes'] == self.get_lanes_db_str()) + assert(fvs_dict['speed'] == str(self.get_speed())) + assert(fvs_dict['index'] == str(self.get_index())) + + def verify_app_db(self): + (status, fvs) = self._app_db_ptbl.get(self.get_name()) + assert(status == True) + fvs_dict = self.get_fvs_dict(fvs) + assert(fvs_dict['alias'] == self.get_alias()) + assert(fvs_dict['lanes'] == self.get_lanes_db_str()) + assert(fvs_dict['speed'] == str(self.get_speed())) + assert(fvs_dict['index'] == str(self.get_index())) + + def verify_asic_db(self): + (status, fvs) = self._asic_db_ptbl.get(self.get_oid()) + assert(status == True) + fvs_dict = self.get_fvs_dict(fvs) + if (fvs_dict.has_key("SAI_PORT_ATTR_HW_LANE_LIST")): + assert(fvs_dict['SAI_PORT_ATTR_HW_LANE_LIST'] == self.get_lanes_asic_db_str()) + assert(fvs_dict['SAI_PORT_ATTR_SPEED'] == str(self.get_speed())) + diff --git a/tests/test_port_config.py b/tests/test_port_config.py index 656b96565e..fa55373d0e 100644 --- a/tests/test_port_config.py +++ b/tests/test_port_config.py @@ -33,25 +33,25 @@ def getVIDfromRID(self, dvs, port_rid): asic_r = redis.Redis(unix_socket_path=dvs.redis_sock, db=swsscommon.ASIC_DB) return asic_r.hget("RIDTOVID", port_rid); - def test_port_hw_lane(self, dvs): app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - port_tbl = swsscommon.Table(app_db, "PORT_TABLE") + app_db_ptbl = swsscommon.Table(app_db, "PORT_TABLE") + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + asic_db_lanes_tbl = swsscommon.Table(asic_db, "LANES") - asic_r = redis.Redis(unix_socket_path=dvs.redis_sock, db=swsscommon.ASIC_DB) - num_lanes = asic_r.hlen("LANES") - for i in range(1, num_lanes+1): - port_rid = asic_r.hget("LANES", i) + lanes = asic_db_lanes_tbl.get('')[1] + num_lanes = len(lanes) + for lane in lanes: + lane_num = lane[0]; + port_rid = lane[1]; port_vid = self.getVIDfromRID(dvs, port_rid) port_name = self.getPortName(dvs, port_vid) - - (status, fvs) = port_tbl.get(port_name) + (status, fvs) = app_db_ptbl.get(port_name) assert status == True for fv in fvs: if fv[0] == "lanes": - assert str(i) in list(fv[1].split(",")) - + assert str(lane_num) in list(fv[1].split(",")) def test_port_breakout(self, dvs, port_config): diff --git a/tests/test_port_dpb.py b/tests/test_port_dpb.py new file mode 100644 index 0000000000..59cf1dfdbd --- /dev/null +++ b/tests/test_port_dpb.py @@ -0,0 +1,175 @@ +from swsscommon import swsscommon +import redis +import time +import os +import pytest +from pytest import * +import json +import re +from port_dpb import Port + +@pytest.yield_fixture(scope="class") +def create_dpb_config_file(dvs): + cmd = "sonic-cfggen -j /etc/sonic/init_cfg.json -j /tmp/ports.json --print-data > /tmp/dpb_config_db.json" + dvs.runcmd(['sh', '-c', cmd]) + cmd = "mv /etc/sonic/config_db.json /etc/sonic/config_db.json.bak" + dvs.runcmd(cmd) + cmd = "cp /tmp/dpb_config_db.json /etc/sonic/config_db.json" + dvs.runcmd(cmd) + +@pytest.yield_fixture(scope="class") +def remove_dpb_config_file(dvs): + cmd = "mv /etc/sonic/config_db.json.bak /etc/sonic/config_db.json" + dvs.runcmd(cmd) + +@pytest.yield_fixture(scope="class", autouse=True) +def dpb_setup_fixture(dvs): + start_cmd = "/usr/bin/start.sh" + + print "Set Up" + create_dpb_config_file(dvs) + #dvs.restart() + dvs.stop_all_daemons() + dvs.runcmd(start_cmd) + + yield + + print "Tear Down" + remove_dpb_config_file(dvs) + #dvs.restart() + dvs.stop_all_daemons() + dvs.runcmd(start_cmd) + +@pytest.mark.usefixtures('dpb_setup_fixture') +class TestPortDPB(object): + + def breakin(self, dvs, port_names): + child_ports = [] + for pname in port_names: + cp = Port(dvs, pname) + cp.sync_from_config_db() + child_ports.append(cp) + + for cp in child_ports: + cp.delete_from_config_db() + dvs.runcmd("ip link delete " + cp.get_name()) + print "Deleted child ports from config DB" + + for cp in child_ports: + assert(cp.exists_in_config_db() == False) + for cp in child_ports: + assert(cp.exists_in_app_db() == False) + time.sleep(6) + for cp in child_ports: + assert(cp.exists_in_asic_db() == False) + print "Verified child ports are deleted from all DBs" + + p = Port(dvs) + p.port_merge(child_ports) + p.write_to_config_db() + print "Added port to config DB" + + p.verify_config_db() + print "Config DB verification passed!" + + time.sleep(1) + p.verify_app_db() + print "Application DB verification passed!" + + time.sleep(6) + p.verify_asic_db() + print "ASIC DB verification passed!" + + def breakout(self, dvs, port_name, num_child_ports): + + p = Port(dvs, port_name) + p.sync_from_config_db() + + # Delete port from config DB and kernel + p.delete_from_config_db() + dvs.runcmd("ip link delete " + p.get_name()) + + # Verify port is deleted from all DBs + assert(p.exists_in_config_db() == False) + assert(p.exists_in_app_db() == False) + time.sleep(6) + assert(p.exists_in_asic_db() == False) + + # Create child ports and write to config DB + child_ports = p.port_split(num_child_ports) + for cp in child_ports: + cp.write_to_config_db() + print "Added child ports to config DB" + + time.sleep(1) + for cp in child_ports: + assert(cp.exists_in_config_db() == True) + cp.verify_config_db() + print "Config DB verification passed" + + for cp in child_ports: + assert(cp.exists_in_app_db() == True) + cp.verify_app_db() + print "APP DB verification passed" + + for cp in child_ports: + assert(cp.exists_in_asic_db() == True) + cp.verify_asic_db() + print "ASIC DB verification passed" + + ''' + @pytest.mark.skip() + ''' + def test_port_1X40G(self, dvs): + self.breakout(dvs, "Ethernet0", 4) + print "**** 1X40G --> 4X10G passed ****" + self.breakin(dvs, ["Ethernet0", "Ethernet1", "Ethernet2", "Ethernet3"]) + print "**** 4X10G --> 1X40G passed ****" + + ''' + @pytest.mark.skip() + ''' + def test_port_1X100G(self, dvs): + + # Change Ethernet0 speed to 100G + p = Port(dvs, "Ethernet0") + p.sync_from_config_db() + p.set_speed(100000) + p.write_to_config_db() + p.verify_config_db() + time.sleep(1) + p.verify_app_db() + time.sleep(1) + p.verify_asic_db() + + self.breakout(dvs, "Ethernet0", 4) + print "**** 1X100G --> 4X25G passed ****" + self.breakin(dvs, ["Ethernet0", "Ethernet1", "Ethernet2", "Ethernet3"]) + print "**** 4X25G --> 1X100G passed ****" + self.breakout(dvs, "Ethernet0", 2) + print "**** 1X100G --> 2X50G passed ****" + self.breakin(dvs, ["Ethernet0", "Ethernet2"]) + print "**** 2X50G --> 1X100G passed ****" + + + ''' + @pytest.mark.skip() + ''' + def test_port_breakout_all_4X10G(self, dvs): + port_names = [] + for i in range(32): + pname = "Ethernet" + str(i*4) + port_names.append(pname) + + for pname in port_names: + self.breakout(dvs, pname, 4) + + child_port_names = [] + for i in range(128): + cpname = "Ethernet" + str(i) + child_port_names.append(cpname) + + for i in range(32): + start = i*4 + end = start+4 + self.breakin(dvs, child_port_names[start:end])