Skip to content

Commit

Permalink
[dvs] Dynamic Port Breakout system test cases using CLI command (soni…
Browse files Browse the repository at this point in the history
…c-net#1515)

Signed-off-by: Vasant <[email protected]>
Co-authored-by: Danny Allen <[email protected]>
  • Loading branch information
2 people authored and raphaelt-nvidia committed Oct 5, 2021
1 parent 0e3f92e commit cbf5317
Show file tree
Hide file tree
Showing 5 changed files with 944 additions and 19 deletions.
14 changes: 4 additions & 10 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,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 @@ -218,7 +216,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 @@ -1179,6 +1176,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 @@ -1525,7 +1526,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 @@ -1555,7 +1555,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 @@ -1575,14 +1574,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 @@ -1628,7 +1625,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 @@ -1638,12 +1634,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
14 changes: 7 additions & 7 deletions tests/dvslib/dvs_vlan.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ 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 create_vlan_hostif(self, vlan, hostif_name):
Expand All @@ -22,17 +22,17 @@ def remove_vlan(self, vlan):
vlan = "Vlan{}".format(vlan)
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)

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

0 comments on commit cbf5317

Please sign in to comment.