Skip to content

Commit 0451a76

Browse files
Enhance qos tests to support single-asic, multi-asic, and multi-dut testing (#8149)
* Enhance qos tests to support single-asic, multi-asic, and multi-dut testing (sandeep: PR#6946) Cleanup for QoS Minor fixes for Qos tests Changes to support QoS multi-asic and ixes to QoS tests for single-asic - Ignoring qos/test_buffer.py for T2 and allowing to run test_qos_sai.py on our chassis - Changes to support QoS multi-asic Run only single-asic QoS tests Integrating cint calls into qos tests Fixes for QoS multi-asic support qos masic - docker services should be updated on both src and dst asics it was being done only on the src asic More fixes for QoS tests Adding missing import of 'socket' to sai_qos_base.py file More fixes to QoS tests based on PR creation Final fixes for Qos tests with rebase Fixes for multi-dut and multi-asic in ReleaseAllPorts Adding missing texttable.py file needed for QoS tests Fixing typo in QoS tests Embedding 'show counter' calls in PgSharedWatermark qos test Adding missing QoS file Fixing select fixture for QoS test Fixing the path used for docker-sync-rpc image for QoS tests qos tuning for LossyQueue parameter Fixes for PFCXon test QoS changes after rebase double commit PR #7109 #7119 #7140 #7154 (#7173) Changes to DscpToPgmapping and PgSharedWatermarkTest for qos Updating cint scripts and validating successfully executed Adding sleep before checking stats for QoS tests Change PgSharedWatermark_test assert stmt More fixes for QoS tests Fixes for QoS QSharedWatermarkTest test Need to ignore one of the asserts as SAI_INGRESS_PRIORITY_GROUP_STAT_XOFF_ROOM_WATERMARK_BYTES is not supported on DNX Enabling multi-asic/multi-dut and single-asic mode for QoS tests All the fixes are in libsai that comes with 202205 - so we can run all the tests in our weekend pipeline QoS rebase fixes Removing ptf_dut_ip - internal Nokia related code Fixing issue created via rebase Latest fixes Fixes to QoS tests for mellanox and cisco-8000 platforms Fix json.loads exception in dut_qos_maps if corresponding data is not present in the output of sonic-cfggen Fix to allow tests to run one a single DUT in the testbed that has multiple DUTs defined Fixed missing 'target' parameter in sai_thrift_read_queue_occupancy calls for cisco-8000 Fixes for Mellanox platforms fixed indentation error fixed precheck errors fixed pre-check errors fix for tests * Fixes from 202205 branch * Fixes for ToR QoS test cases * Fix for nightly failures * Fix for nightly failures-2 * dual tor fixes * dual tor fixes - 2 * dual tor fixes - 3 * pre-check fixes * pre-check fixes - 2 * pre-check fixes - 3 * pre-check fixes - 4 * pre-check fixes - 5 * pre-check fixes 6 * pre-check fixes 7 --------- Co-authored-by: sanmalho <sandeep.malhotra@nokia.com>
1 parent 568bab2 commit 0451a76

15 files changed

Lines changed: 1543 additions & 1182 deletions

tests/common/devices/sonic.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1954,22 +1954,6 @@ def is_service_running(self, service_name, docker_name):
19541954

19551955
return "RUNNING" in service_status
19561956

1957-
def remove_ssh_tunnel_sai_rpc(self):
1958-
"""
1959-
Removes any ssh tunnels if present created for syncd RPC communication
1960-
1961-
Returns:
1962-
None
1963-
"""
1964-
try:
1965-
pid_list = self.shell(
1966-
r'pgrep -f "ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=60 -fN -L \*:9092"'
1967-
)["stdout_lines"]
1968-
except RunAnsibleModuleFail:
1969-
return
1970-
for pid in pid_list:
1971-
self.shell("kill {}".format(pid), module_ignore_errors=True)
1972-
19731957
def get_up_ip_ports(self):
19741958
"""
19751959
Get a list for all up ip interfaces

tests/common/devices/sonic_asic.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class SonicAsic(object):
1919

2020
_MULTI_ASIC_SERVICE_NAME = "{}@{}" # service name, asic_id
2121
_MULTI_ASIC_DOCKER_NAME = "{}{}" # docker name, asic_id
22+
_RPC_PORT_FOR_SSH_TUNNEL = 9092
2223

2324
def __init__(self, sonichost, asic_index):
2425
""" Initializing a ASIC on a SONiC host.
@@ -325,6 +326,9 @@ def bgp_drop_rule(self, ip_version, state="present"):
325326

326327
logger.debug(output)
327328

329+
def get_rpc_port_ssh_tunnel(self):
330+
return self._RPC_PORT_FOR_SSH_TUNNEL + self.asic_index
331+
328332
def remove_ssh_tunnel_sai_rpc(self):
329333
"""
330334
Removes any ssh tunnels if present created for syncd RPC communication
@@ -334,7 +338,15 @@ def remove_ssh_tunnel_sai_rpc(self):
334338
"""
335339
if not self.sonichost.is_multi_asic:
336340
return
337-
return self.sonichost.remove_ssh_tunnel_sai_rpc()
341+
342+
try:
343+
pid_list = self.sonichost.shell(
344+
r'pgrep -f "ssh -o StrictHostKeyChecking=no -fN -L \*:{}"'.format(self.get_rpc_port_ssh_tunnel())
345+
)["stdout_lines"]
346+
except RunAnsibleModuleFail:
347+
return
348+
for pid in pid_list:
349+
self.shell("kill {}".format(pid), module_ignore_errors=True)
338350

339351
def create_ssh_tunnel_sai_rpc(self):
340352
"""
@@ -362,8 +374,9 @@ def create_ssh_tunnel_sai_rpc(self):
362374
raise Exception("Invalid V4 address {}".format(ns_docker_if_ipv4))
363375

364376
self.sonichost.shell(
365-
("ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=60 -fN"
366-
" -L *:9092:{}:9092 localhost").format(ns_docker_if_ipv4))
377+
("ssh -o StrictHostKeyChecking=no -fN"
378+
" -L *:{}:{}:{} localhost").format(self.get_rpc_port_ssh_tunnel(), ns_docker_if_ipv4,
379+
self._RPC_PORT_FOR_SSH_TUNNEL))
367380

368381
def command(self, cmdstr):
369382
"""

tests/common/fixtures/duthost_utils.py

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -448,10 +448,9 @@ def utils_create_test_vlans(duthost, cfg_facts, vlan_ports_list, vlan_intfs_dict
448448
duthost.shell_cmds(cmds=cmds)
449449

450450

451-
@pytest.fixture(scope='module')
452-
def dut_qos_maps(rand_selected_front_end_dut):
451+
def _dut_qos_map(dut):
453452
"""
454-
A module level fixture to get QoS map from DUT host.
453+
A helper function to get QoS map from DUT host.
455454
Return a dict
456455
{
457456
"dscp_to_tc_map": {
@@ -467,43 +466,62 @@ def dut_qos_maps(rand_selected_front_end_dut):
467466
"""
468467
maps = {}
469468
try:
470-
if rand_selected_front_end_dut.is_multi_asic:
469+
if dut.is_multi_asic:
471470
sonic_cfggen_cmd = "sonic-cfggen -n asic0 -d --var-json"
472471
else:
473472
sonic_cfggen_cmd = "sonic-cfggen -d --var-json"
474473

475474
# port_qos_map
476-
port_qos_map_data = rand_selected_front_end_dut.shell("{} 'PORT_QOS_MAP'".format(sonic_cfggen_cmd))['stdout']
477-
maps['port_qos_map'] = json.loads(port_qos_map_data) if port_qos_map_data else None
475+
port_qos_map = dut.shell("{} 'PORT_QOS_MAP'".format(sonic_cfggen_cmd))['stdout']
476+
maps['port_qos_map'] = json.loads(port_qos_map) if port_qos_map else None
477+
478478
# dscp_to_tc_map
479-
dscp_to_tc_map_data = rand_selected_front_end_dut.shell(
480-
"{} 'DSCP_TO_TC_MAP'".format(sonic_cfggen_cmd))['stdout']
481-
maps['dscp_to_tc_map'] = json.loads(dscp_to_tc_map_data) if dscp_to_tc_map_data else None
479+
dscp_to_tc_map = dut.shell("{} 'DSCP_TO_TC_MAP'".format(sonic_cfggen_cmd))['stdout']
480+
maps['dscp_to_tc_map'] = json.loads(dscp_to_tc_map) if dscp_to_tc_map else None
481+
482482
# tc_to_queue_map
483-
tc_to_queue_map_data = rand_selected_front_end_dut.shell(
484-
"{} 'TC_TO_QUEUE_MAP'".format(sonic_cfggen_cmd))['stdout']
485-
maps['tc_to_queue_map'] = json.loads(tc_to_queue_map_data) if tc_to_queue_map_data else None
483+
tc_to_queue_map = dut.shell("{} 'TC_TO_QUEUE_MAP'".format(sonic_cfggen_cmd))['stdout']
484+
maps['tc_to_queue_map'] = json.loads(tc_to_queue_map) if tc_to_queue_map else None
485+
486486
# tc_to_priority_group_map
487-
tc_to_priority_group_map_data = rand_selected_front_end_dut.shell(
488-
"{} 'TC_TO_PRIORITY_GROUP_MAP'".format(sonic_cfggen_cmd))['stdout']
489-
maps['tc_to_priority_group_map'] = json.loads(
490-
tc_to_priority_group_map_data) if tc_to_priority_group_map_data else None
487+
tc_to_priority_group_map = dut.shell("{} 'TC_TO_PRIORITY_GROUP_MAP'".format(sonic_cfggen_cmd))['stdout']
488+
maps['tc_to_priority_group_map'] = json.loads(tc_to_priority_group_map) if tc_to_priority_group_map else None
489+
491490
# tc_to_dscp_map
492-
tc_to_dscp_map_data = rand_selected_front_end_dut.shell(
493-
"{} 'TC_TO_DSCP_MAP'".format(sonic_cfggen_cmd))['stdout']
494-
maps['tc_to_dscp_map'] = json.loads(tc_to_dscp_map_data) if tc_to_dscp_map_data else None
491+
tc_to_dscp_map = dut.shell("{} 'TC_TO_DSCP_MAP'".format(sonic_cfggen_cmd))['stdout']
492+
maps['tc_to_dscp_map'] = json.loads(tc_to_dscp_map) if tc_to_dscp_map else None
495493
except Exception as e:
496494
logger.error("Got exception: " + repr(e))
497495
return maps
498496

499497

500-
def separated_dscp_to_tc_map_on_uplink(duthost, dut_qos_maps):
498+
@pytest.fixture(scope='class')
499+
def dut_qos_maps(get_src_dst_asic_and_duts):
500+
"""
501+
A class level fixture to get QoS map from DUT host.
502+
Return a dict
503+
"""
504+
dut = get_src_dst_asic_and_duts['src_dut']
505+
return _dut_qos_map(dut)
506+
507+
508+
@pytest.fixture(scope='module')
509+
def dut_qos_maps_module(rand_selected_front_end_dut):
510+
"""
511+
A module level fixture to get QoS map from DUT host.
512+
return a dict
513+
"""
514+
dut = rand_selected_front_end_dut
515+
return _dut_qos_map(dut)
516+
517+
518+
def separated_dscp_to_tc_map_on_uplink(dut_qos_maps_module):
501519
"""
502520
A helper function to check if separated DSCP_TO_TC_MAP is applied to
503521
downlink/unlink ports.
504522
"""
505523
dscp_to_tc_map_names = set()
506-
for port_name, qos_map in list(dut_qos_maps['port_qos_map'].items()):
524+
for port_name, qos_map in dut_qos_maps_module['port_qos_map'].items():
507525
if port_name == "global":
508526
continue
509527
dscp_to_tc_map_names.add(qos_map.get("dscp_to_tc_map", ""))
@@ -512,20 +530,20 @@ def separated_dscp_to_tc_map_on_uplink(duthost, dut_qos_maps):
512530
return False
513531

514532

515-
def load_dscp_to_pg_map(duthost, port, dut_qos_maps):
533+
def load_dscp_to_pg_map(duthost, port, dut_qos_maps_module):
516534
"""
517535
Helper function to calculate DSCP to PG map for a port.
518536
The map is derived from DSCP_TO_TC_MAP + TC_TO_PG_MAP
519537
return a dict like {0:0, 1:1...}
520538
"""
521539
try:
522-
port_qos_map = dut_qos_maps['port_qos_map']
540+
port_qos_map = dut_qos_maps_module['port_qos_map']
523541
dscp_to_tc_map_name = port_qos_map[port]['dscp_to_tc_map'].split('|')[-1].strip(']')
524542
tc_to_pg_map_name = port_qos_map[port]['tc_to_pg_map'].split('|')[-1].strip(']')
525543
# Load dscp_to_tc_map
526-
dscp_to_tc_map = dut_qos_maps['dscp_to_tc_map'][dscp_to_tc_map_name]
544+
dscp_to_tc_map = dut_qos_maps_module['dscp_to_tc_map'][dscp_to_tc_map_name]
527545
# Load tc_to_pg_map
528-
tc_to_pg_map = dut_qos_maps['tc_to_priority_group_map'][tc_to_pg_map_name]
546+
tc_to_pg_map = dut_qos_maps_module['tc_to_priority_group_map'][tc_to_pg_map_name]
529547
# Calculate dscp to pg map
530548
dscp_to_pg_map = {}
531549
for dscp, tc in list(dscp_to_tc_map.items()):
@@ -536,20 +554,20 @@ def load_dscp_to_pg_map(duthost, port, dut_qos_maps):
536554
return {}
537555

538556

539-
def load_dscp_to_queue_map(duthost, port, dut_qos_maps):
557+
def load_dscp_to_queue_map(duthost, port, dut_qos_maps_module):
540558
"""
541559
Helper function to calculate DSCP to Queue map for a port.
542560
The map is derived from DSCP_TO_TC_MAP + TC_TO_QUEUE_MAP
543561
return a dict like {0:0, 1:1...}
544562
"""
545563
try:
546-
port_qos_map = dut_qos_maps['port_qos_map']
564+
port_qos_map = dut_qos_maps_module['port_qos_map']
547565
dscp_to_tc_map_name = port_qos_map[port]['dscp_to_tc_map'].split('|')[-1].strip(']')
548566
tc_to_queue_map_name = port_qos_map[port]['tc_to_queue_map'].split('|')[-1].strip(']')
549567
# Load dscp_to_tc_map
550-
dscp_to_tc_map = dut_qos_maps['dscp_to_tc_map'][dscp_to_tc_map_name][dscp_to_tc_map_name]
568+
dscp_to_tc_map = dut_qos_maps_module['dscp_to_tc_map'][dscp_to_tc_map_name][dscp_to_tc_map_name]
551569
# Load tc_to_queue_map
552-
tc_to_queue_map = dut_qos_maps['tc_to_queue_map'][tc_to_queue_map_name]
570+
tc_to_queue_map = dut_qos_maps_module['tc_to_queue_map'][tc_to_queue_map_name]
553571
# Calculate dscp to queue map
554572
dscp_to_queue_map = {}
555573
for dscp, tc in list(dscp_to_tc_map.items()):

tests/common/fixtures/ptfhost_utils.py

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -518,28 +518,38 @@ def ptf_test_port_map_active_active(ptfhost, tbinfo, duthosts, mux_server_url, d
518518
]
519519

520520
disabled_ptf_ports = set()
521-
for ptf_map in list(tbinfo['topo']['ptf_map_disabled'].values()):
521+
for ptf_map in tbinfo['topo']['ptf_map_disabled'].values():
522522
# Loop ptf_map of each DUT. Each ptf_map maps from ptf port index to dut port index
523523
disabled_ptf_ports = disabled_ptf_ports.union(set(ptf_map.keys()))
524524

525-
router_macs = [duthost.facts['router_mac'] for duthost in duthosts]
525+
router_macs = []
526+
all_dut_names = [duthost.hostname for duthost in duthosts]
527+
for a_dut_name in tbinfo['duts']:
528+
if a_dut_name in all_dut_names:
529+
duthost = duthosts[a_dut_name]
530+
router_macs.append(duthost.facts['router_mac'])
531+
else:
532+
router_macs.append(None)
526533

527534
logger.info('active_dut_map={}'.format(active_dut_map))
528535
logger.info('disabled_ptf_ports={}'.format(disabled_ptf_ports))
529536
logger.info('router_macs={}'.format(router_macs))
530537

531-
asic_idx = 0
532538
ports_map = {}
533539
for ptf_port, dut_intf_map in list(tbinfo['topo']['ptf_dut_intf_map'].items()):
534540
if str(ptf_port) in disabled_ptf_ports:
535541
# Skip PTF ports that are connected to disabled VLAN interfaces
536542
continue
543+
asic_idx = 0
544+
dut_port = None
537545

538-
if len(list(dut_intf_map.keys())) == 2:
546+
if len(dut_intf_map.keys()) == 2:
539547
# PTF port is mapped to two DUTs -> dualtor topology and the PTF port is a vlan port
540548
# Packet sent from this ptf port will only be accepted by the active side DUT
541-
# DualToR DUTs use same special Vlan interface MAC address
549+
# DualToR DUTs use same special Vlan interface MAC addres
542550
target_dut_indexes = list(map(int, active_dut_map[ptf_port]))
551+
target_dut_port = int(list(dut_intf_map.values())[0])
552+
target_hostname = duthosts[target_dut_indexes[0]].hostname
543553
ports_map[ptf_port] = {
544554
'target_dut': target_dut_indexes,
545555
'target_dest_mac': tbinfo['topo']['properties']['topology']['DUT']['vlan_configs']['one_vlan_a']
@@ -549,12 +559,17 @@ def ptf_test_port_map_active_active(ptfhost, tbinfo, duthosts, mux_server_url, d
549559
}
550560
else:
551561
# PTF port is mapped to single DUT
562+
dut_index_for_pft_port = int(list(dut_intf_map.keys())[0])
563+
if router_macs[dut_index_for_pft_port] is None:
564+
continue
552565
target_dut_index = int(list(dut_intf_map.keys())[0])
553566
target_dut_port = int(list(dut_intf_map.values())[0])
554567
router_mac = router_macs[target_dut_index]
555-
dut_port = None
556-
if len(duts_minigraph_facts[duthosts[target_dut_index].hostname]) > 1:
557-
for list_idx, mg_facts_tuple in enumerate(duts_minigraph_facts[duthosts[target_dut_index].hostname]):
568+
target_hostname = tbinfo['duts'][target_dut_index]
569+
570+
if len(duts_minigraph_facts[target_hostname]) > 1:
571+
# Dealing with multi-asic target dut
572+
for list_idx, mg_facts_tuple in enumerate(duts_minigraph_facts[target_hostname]):
558573
idx, mg_facts = mg_facts_tuple
559574
for a_dut_port, a_dut_port_index in list(mg_facts['minigraph_port_indices'].items()):
560575
if a_dut_port_index == target_dut_port and "Ethernet-Rec" not in a_dut_port and \
@@ -569,10 +584,18 @@ def ptf_test_port_map_active_active(ptfhost, tbinfo, duthosts, mux_server_url, d
569584
'target_dut': [target_dut_index],
570585
'target_dest_mac': router_mac,
571586
'target_src_mac': [router_mac],
572-
'dut_port': dut_port,
573587
'asic_idx': asic_idx
574588
}
575589

590+
_, asic_mg_facts = duts_minigraph_facts[target_hostname][asic_idx]
591+
for a_dut_port, a_dut_port_index in asic_mg_facts['minigraph_port_indices'].items():
592+
if a_dut_port_index == target_dut_port and "Ethernet-Rec" not in a_dut_port and \
593+
"Ethernet-IB" not in a_dut_port and "Ethernet-BP" not in a_dut_port:
594+
dut_port = a_dut_port
595+
break
596+
597+
ports_map[ptf_port]['dut_port'] = dut_port
598+
576599
logger.debug('ptf_test_port_map={}'.format(json.dumps(ports_map, indent=2)))
577600

578601
ptfhost.copy(content=json.dumps(ports_map), dest=PTF_TEST_PORT_MAP)

tests/conftest.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from tests.common.helpers.parallel import parallel_run
2929
from tests.common.fixtures.duthost_utils import backup_and_restore_config_db_session # noqa F401
3030
from tests.common.fixtures.ptfhost_utils import ptf_portmap_file # noqa F401
31+
from tests.common.fixtures.ptfhost_utils import ptf_test_port_map_active_active # noqa F401
3132
from tests.common.fixtures.ptfhost_utils import run_icmp_responder_session # noqa F401
3233

3334
from tests.common.helpers.constants import (
@@ -1708,6 +1709,59 @@ def duts_running_config_facts(duthosts):
17081709

17091710

17101711
@pytest.fixture(scope='class')
1712+
def dut_test_params_qos(duthosts, tbinfo, ptfhost, get_src_dst_asic_and_duts, lower_tor_host, creds,
1713+
mux_server_url, mux_status_from_nic_simulator, duts_running_config_facts, duts_minigraph_facts):
1714+
if 'dualtor' in tbinfo['topo']['name']:
1715+
all_duts = [lower_tor_host]
1716+
else:
1717+
all_duts = get_src_dst_asic_and_duts['all_duts']
1718+
1719+
src_asic = get_src_dst_asic_and_duts['src_asic']
1720+
dst_asic = get_src_dst_asic_and_duts['dst_asic']
1721+
1722+
src_dut = get_src_dst_asic_and_duts['src_dut']
1723+
src_dut_ip = src_dut.host.options['inventory_manager'].get_host(src_dut.hostname).vars['ansible_host']
1724+
src_server = "{}:{}".format(src_dut_ip, src_asic.get_rpc_port_ssh_tunnel())
1725+
1726+
duthost = all_duts[0]
1727+
mgFacts = duthost.get_extended_minigraph_facts(tbinfo)
1728+
topo = tbinfo["topo"]["name"]
1729+
1730+
rtn_dict = {
1731+
"topo": topo,
1732+
"hwsku": mgFacts["minigraph_hwsku"],
1733+
"basicParams": {
1734+
"router_mac": duthost.facts["router_mac"],
1735+
"src_server": src_server,
1736+
"port_map_file": ptf_test_port_map_active_active(
1737+
ptfhost, tbinfo, duthosts, mux_server_url,
1738+
duts_running_config_facts, duts_minigraph_facts,
1739+
mux_status_from_nic_simulator()),
1740+
"sonic_asic_type": duthost.facts['asic_type'],
1741+
"sonic_version": duthost.os_version,
1742+
"src_dut_index": get_src_dst_asic_and_duts['src_dut_index'],
1743+
"src_asic_index": get_src_dst_asic_and_duts['src_asic_index'],
1744+
"dst_dut_index": get_src_dst_asic_and_duts['dst_dut_index'],
1745+
"dst_asic_index": get_src_dst_asic_and_duts['dst_asic_index'],
1746+
"dut_username": creds['sonicadmin_user'],
1747+
"dut_password": creds['sonicadmin_password']
1748+
},
1749+
1750+
}
1751+
1752+
# Add dst server info if src and dst asic are different
1753+
if src_asic != dst_asic:
1754+
dst_dut = get_src_dst_asic_and_duts['dst_dut']
1755+
dst_dut_ip = dst_dut.host.options['inventory_manager'].get_host(dst_dut.hostname).vars['ansible_host']
1756+
rtn_dict["basicParams"]["dst_server"] = "{}:{}".format(dst_dut_ip, dst_asic.get_rpc_port_ssh_tunnel())
1757+
1758+
if 'platform_asic' in duthost.facts:
1759+
rtn_dict['basicParams']["platform_asic"] = duthost.facts['platform_asic']
1760+
1761+
yield rtn_dict
1762+
1763+
1764+
@ pytest.fixture(scope='class')
17111765
def dut_test_params(duthosts, enum_rand_one_per_hwsku_frontend_hostname, tbinfo,
17121766
ptf_portmap_file, lower_tor_host, creds): # noqa F811
17131767
"""

0 commit comments

Comments
 (0)