Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic Port Breakout system test cases using CLI command #1515

Merged
merged 11 commits into from
May 4, 2021
20 changes: 7 additions & 13 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@
# a dynamic number of ports. GitHub Issue: Azure/sonic-swss#1384.
NUM_PORTS = 32


def ensure_system(cmd):
rc, output = subprocess.getstatusoutput(cmd)
if rc:
raise RuntimeError(f"Failed to run command: {cmd}. rc={rc}. output: {output}")


def pytest_addoption(parser):
parser.addoption("--dvsname",
action="store",
Expand Down Expand Up @@ -206,7 +204,6 @@ def runcmd_async(self, cmd: str) -> subprocess.Popen:
def runcmd_output(self, cmd: str) -> str:
return subprocess.check_output(f"ip netns exec {self.nsname} {cmd}", shell=True).decode("utf-8")


class DockerVirtualSwitch:
APPL_DB_ID = 0
ASIC_DB_ID = 1
Expand Down Expand Up @@ -1134,6 +1131,10 @@ def get_state_db(self) -> DVSDatabase:

return self.state_db

def change_port_breakout_mode(self, intf_name, target_mode, options=""):
cmd = f"config interface breakout {intf_name} {target_mode} -y {options}"
self.runcmd(cmd)
time.sleep(2)

class DockerVirtualChassisTopology:
def __init__(
Expand Down Expand Up @@ -1415,7 +1416,7 @@ def get_chassis_instance_port_statuses(self):
chassis_container_name = device_info["hostname"] + "." + self.ns

port_info = config["PORT"]

for port, config in port_info.items():
if "admin_status" not in config:
continue
Expand All @@ -1424,13 +1425,13 @@ def get_chassis_instance_port_statuses(self):
instance_to_port_status_map[chassis_container_name] = []

instance_to_port_status_map[chassis_container_name].append((port, config.get("admin_status")))

return instance_to_port_status_map

def handle_chassis_connections(self):
if self.oper != "create":
return

instance_to_port_status_map = self.get_chassis_instance_port_statuses()
for chassis_instance, port_statuses in instance_to_port_status_map.items():
if chassis_instance not in self.dvss:
Expand Down Expand Up @@ -1480,7 +1481,6 @@ def verify_vct(self):
print("vct verifications passed ? %s" % (ret1 and ret2))
return ret1 and ret2


@pytest.yield_fixture(scope="module")
def dvs(request) -> DockerVirtualSwitch:
if sys.version_info[0] < 3:
Expand Down Expand Up @@ -1509,7 +1509,6 @@ def dvs(request) -> DockerVirtualSwitch:
dvs.runcmd("mv /etc/sonic/config_db.json.orig /etc/sonic/config_db.json")
dvs.ctn_restart()


@pytest.yield_fixture(scope="module")
def vct(request):
vctns = request.config.getoption("--vctns")
Expand All @@ -1529,14 +1528,12 @@ def vct(request):
vct.get_logs(request.module.__name__)
vct.destroy()


@pytest.yield_fixture
def testlog(request, dvs):
dvs.runcmd(f"logger === start test {request.node.name} ===")
yield testlog
dvs.runcmd(f"logger === finish test {request.node.name} ===")


################# DVSLIB module manager fixtures #############################
@pytest.fixture(scope="class")
def dvs_acl(request, dvs) -> DVSAcl:
Expand Down Expand Up @@ -1576,7 +1573,6 @@ def dvs_policer_manager(request, dvs):
request.cls.dvs_policer = dvs_policer.DVSPolicer(dvs.get_asic_db(),
dvs.get_config_db())


##################### DPB fixtures ###########################################
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"
Expand All @@ -1586,12 +1582,10 @@ def create_dpb_config_file(dvs):
cmd = "cp /tmp/dpb_config_db.json /etc/sonic/config_db.json"
dvs.runcmd(cmd)


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="module")
def dpb_setup_fixture(dvs):
create_dpb_config_file(dvs)
Expand Down
4 changes: 2 additions & 2 deletions tests/dvslib/dvs_acl.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def create_acl_table(
table_attrs = {
"policy_desc": table_name,
"type": table_type,
"ports": ",".join(ports)
"ports@": ",".join(ports)
}

if stage:
Expand Down Expand Up @@ -95,7 +95,7 @@ def update_acl_table_port_list(self, table_name: str, ports: List[str]) -> None:
table_name: The name of the ACL table to update.
ports: The new list of ports to bind to the ACL table.
"""
table_attrs = {"ports": ",".join(ports)}
table_attrs = {"ports@": ",".join(ports)}
self.config_db.update_entry(self.CDB_ACL_TABLE_NAME, table_name, table_attrs)

def remove_acl_table(self, table_name: str) -> None:
Expand Down
18 changes: 9 additions & 9 deletions tests/dvslib/dvs_vlan.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@ def __init__(self, adb, cdb, sdb, cntrdb, appdb):
self.counters_db = cntrdb
self.app_db = appdb

def create_vlan(self, vlan):
vlan = "Vlan{}".format(vlan)
vlan_entry = {"vlanid": vlan}
def create_vlan(self, vlanID):
vlan = "Vlan{}".format(vlanID)
vlan_entry = {"vlanid": vlanID}
self.config_db.create_entry("VLAN", vlan, vlan_entry)

def remove_vlan(self, vlan):
vlan = "Vlan{}".format(vlan)
def remove_vlan(self, vlanID):
vlan = "Vlan{}".format(vlanID)
self.config_db.delete_entry("VLAN", vlan)

def create_vlan_member(self, vlan, interface, tagging_mode="untagged"):
member = "Vlan{}|{}".format(vlan, interface)
def create_vlan_member(self, vlanID, interface, tagging_mode="untagged"):
member = "Vlan{}|{}".format(vlanID, interface)
if tagging_mode:
member_entry = {"tagging_mode": tagging_mode}
else:
member_entry = {"no_tag_mode": ""}

self.config_db.create_entry("VLAN_MEMBER", member, member_entry)

def remove_vlan_member(self, vlan, interface):
member = "Vlan{}|{}".format(vlan, interface)
def remove_vlan_member(self, vlanID, interface):
member = "Vlan{}|{}".format(vlanID, interface)
self.config_db.delete_entry("VLAN_MEMBER", member)

def check_app_db_vlan_fields(self, fvs, admin_status="up", mtu="9100"):
Expand Down
72 changes: 72 additions & 0 deletions tests/port_dpb.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ def verify_asic_db(self):
assert(fvs_dict['SAI_PORT_ATTR_SPEED'] == str(self.get_speed()))

class DPB():
MAX_LANES = 4
def breakin(self, dvs, port_names):
child_ports = []
for pname in port_names:
Expand Down Expand Up @@ -313,3 +314,74 @@ def change_speed_and_verify(self, dvs, port_names, speed = 100000):
p.verify_app_db()
time.sleep(1)
p.verify_asic_db()

def verify_port_breakout_mode(self, dvs, port_name, breakout_mode):
dvs.get_config_db().wait_for_field_match("BREAKOUT_CFG", port_name, {"brkout_mode": breakout_mode})

"""
Examples:
--------------------------------------------------------------------------------------
| Root Port | Breakout Mode | Lanes | Child Ports |
--------------------------------------------------------------------------------------
| Ethernet0 | 4x25G(10G) | 4 | Ethernet0, Ethernet1, Ethernet2, Ethernet3 |
--------------------------------------------------------------------------------------
| Ethernet0 | 2x50G | 4 | Ethernet0, Ethernet2 |
--------------------------------------------------------------------------------------
| Ethernet0 | 1x100G(40G) | 4 | Ethernet0 |
--------------------------------------------------------------------------------------
**| Ethernet0 | 2x25G(2)+1x50G(2) | 4 | Ethernet0, Ethernet1, Ethernet2 |
--------------------------------------------------------------------------------------
**| Ethernet0 | 1x50G(2)+2x25G(2) | 4 | Ethernet0, Ethernet2, Ethernet3 |
--------------------------------------------------------------------------------------
** --> Asymmetric breakout modes
For symmetric breakout modes, this method directly calls _get_child_ports(),
and for asymmetric breakout modes, it breaks the mode with '+' as delimiter
and calls _get_child_ports() for each term while accumulating the result.
"""
def get_child_ports(self, root_port, breakout_mode):
if '+' not in breakout_mode:
return self._get_child_ports(root_port, breakout_mode, self.MAX_LANES)

modes = breakout_mode.split('+')
child_ports = []
root_port_num = int(root_port.split('Ethernet')[1])
for mode in modes:
lanes = int(mode.split('(')[1].split(')')[0])
mode = mode.split('(')[0]
child_ports = child_ports + self._get_child_ports(root_port, mode, lanes)
root_port_num = root_port_num + lanes
root_port = 'Ethernet' + str(root_port_num)
vasant17 marked this conversation as resolved.
Show resolved Hide resolved

return child_ports

"""
Examples:
-----------------------------------------------------------------------------------
| Root Port | Breakout Mode | Lanes | Child Ports |
-----------------------------------------------------------------------------------
| Ethernet0 | 4x25G(10G) | 4 | Ethernet0, Ethernet1, Ethernet2, Ethernet3 |
-----------------------------------------------------------------------------------
| Ethernet0 | 2x50G | 4 | Ethernet0, Ethernet2 |
-----------------------------------------------------------------------------------
| Ethernet0 | 1x100G(40G) | 4 | Ethernet0 |
-----------------------------------------------------------------------------------
*| Ethernet0 | 2x25G(2) | 2 | Ethernet0, Ethernet1 |
-----------------------------------------------------------------------------------
*| Ethernet2 | 1x50G(2) | 2 | Ethernet2 |
-----------------------------------------------------------------------------------
*| Ethernet0 | 1x50G(2) | 2 | Ethernet0 |
-----------------------------------------------------------------------------------
*| Ethernet2 | 2x25G(2) | 2 | Ethernet2, Ethernet3 |
-----------------------------------------------------------------------------------
* -> Breakout modes in these cases are a term of asymmetric breakout modes. Please
refer above method
"""
def _get_child_ports(self, root_port, breakout_mode, lanes):
count = int(breakout_mode.split('x')[0])
port = int(root_port.split('Ethernet')[1])

child_ports = []
jump = int(lanes/count)
for i in range(0, lanes, jump):
child_ports.append('Ethernet{}'.format(port+i))
return child_ports
Loading