Skip to content

Commit 489b754

Browse files
authored
[Mellanox] Update spf test related to error status when sw control is enabled (sonic-net#16573) (sonic-net#17540)
* Update spf platform test related to error status, due to sonic-net/sonic-buildimage#20964 When software control is enabled, the port error status is as follows: 1. For active module, the expected state is OK 2. For cmis passive module, the expected state is ModuleLowPwr 3. For non cmis passive module, the expected state is 'Not supported' when software control is disabled, the port error status keep the original behaviour * fix issue caused by the vs * sfp test just run on physical setup * update sfp tests 1. For cmis passive module, when cmis ver is 3.0, the expected state is ModuleLowPwr, else it is OK
1 parent 70909df commit 489b754

5 files changed

Lines changed: 122 additions & 13 deletions

File tree

tests/common/platform/transceiver_utils.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,3 +387,60 @@ def is_passive_cable(sfp_eeprom_info):
387387
"CR" in spec_compliance.get("Extended Specification Compliance", " "):
388388
return True
389389
return False
390+
391+
392+
def get_passive_cable_port_list(dut):
393+
passive_cable_port_list = []
394+
cmd_show_eeprom = "sudo sfputil show eeprom -d"
395+
eeprom_infos = dut.command(cmd_show_eeprom)['stdout']
396+
eeprom_infos = parse_sfp_eeprom_infos(eeprom_infos)
397+
for port_name, eeprom_info in eeprom_infos.items():
398+
if is_passive_cable(eeprom_info):
399+
logging.info(f"{port_name} is passive cable")
400+
passive_cable_port_list.append(port_name)
401+
logging.info(f"Ports with passive cable are: {passive_cable_port_list}")
402+
return passive_cable_port_list
403+
404+
405+
def get_cmis_cable_ports_and_ver(dut):
406+
cmis_cable_port_to_version_map = {}
407+
cmd_show_eeprom = "sudo sfputil show eeprom -d"
408+
eeprom_infos = dut.command(cmd_show_eeprom)['stdout']
409+
eeprom_infos = parse_sfp_eeprom_infos(eeprom_infos)
410+
for port_name, eeprom_info in eeprom_infos.items():
411+
if 'CMIS Revision' in eeprom_info:
412+
logging.info(f"{port_name} is cmis cable")
413+
cmis_cable_port_to_version_map[port_name] = eeprom_info['CMIS Revision']
414+
logging.info(f"cmis_cable_port_to_version_map: {cmis_cable_port_to_version_map}")
415+
return cmis_cable_port_to_version_map
416+
417+
418+
def get_port_expected_error_state_for_mellanox_device_on_sw_control_enabled(
419+
intf, passive_cable_ports, cmis_cable_ports_and_ver):
420+
expected_state = 'OK'
421+
if intf in passive_cable_ports:
422+
# for active module, the expected state is OK
423+
# for cmis passive module, when cmis ver is 3.0, the expected state is ModuleLowPwr, else it is OK
424+
# for non cmis passive module, the expected state is 'Not supported'
425+
if intf in cmis_cable_ports_and_ver:
426+
expected_state = 'ModuleLowPwr' if cmis_cable_ports_and_ver[intf] == '3.0' else 'OK'
427+
else:
428+
expected_state = 'Not supported'
429+
logging.info(f"port {intf}, expected error state:{expected_state}")
430+
return expected_state
431+
432+
433+
def is_sw_control_enabled(duthost, port_index):
434+
"""
435+
@summary: This method is for checking if software control SAI attribute set to 1 in sai.profile
436+
@param: duthosts: duthosts fixture
437+
"""
438+
sw_control_enabled = False
439+
module_path = f'/sys/module/sx_core/asic0/module{int(port_index) - 1}'
440+
cmd_check_if_exist_conctrol_file = f'ls {module_path} | grep control'
441+
if duthost.shell(cmd_check_if_exist_conctrol_file, module_ignore_errors=True)['stdout']:
442+
cmd_get_control_value = f"sudo cat {module_path}/control"
443+
if duthost.shell(cmd_get_control_value)['stdout'] == "1":
444+
sw_control_enabled = True
445+
logging.info(f'The sw control enable of port index {port_index} is {sw_control_enabled}')
446+
return sw_control_enabled

tests/platform_tests/api/test_sfp.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
from tests.common.utilities import wait_until
1111
from tests.common.fixtures.conn_graph_facts import conn_graph_facts # noqa F401
1212
from tests.common.fixtures.duthost_utils import shutdown_ebgp # noqa F401
13+
from tests.common.platform.transceiver_utils import is_sw_control_enabled,\
14+
get_port_expected_error_state_for_mellanox_device_on_sw_control_enabled
15+
from tests.common.mellanox_data import is_mellanox_device
16+
from collections import defaultdict
1317

1418
from .platform_api_test_base import PlatformApiTestBase
1519

@@ -47,6 +51,10 @@ def setup(request, duthosts, enum_rand_one_per_hwsku_hostname,
4751
physical_port_index_map = get_physical_port_indices(duthost, physical_intfs)
4852
sfp_setup["physical_port_index_map"] = physical_port_index_map
4953

54+
sfp_setup["index_physical_port_map"] = defaultdict(list)
55+
for port, index in physical_port_index_map.items():
56+
sfp_setup["index_physical_port_map"][index].append(port)
57+
5058
sfp_port_indices = set([physical_port_index_map[intf] for intf in list(physical_port_index_map.keys())])
5159
sfp_setup["sfp_port_indices"] = sorted(sfp_port_indices)
5260

@@ -846,23 +854,33 @@ def test_power_override(self, duthosts, enum_rand_one_per_hwsku_hostname, localh
846854
"Transceiver {} power override data is incorrect".format(i))
847855
self.assert_expectations()
848856

849-
def test_get_error_description(self, duthosts, enum_rand_one_per_hwsku_hostname, localhost, platform_api_conn):
857+
@pytest.mark.device_type('physical')
858+
def test_get_error_description(self, duthosts, enum_rand_one_per_hwsku_hostname, localhost,
859+
platform_api_conn, passive_cable_ports, cmis_cable_ports_and_ver): # noqa F811
850860
"""This function tests get_error_description() API (supported on 202106 and above)"""
851-
skip_release(duthosts[enum_rand_one_per_hwsku_hostname], ["201811", "201911", "202012"])
861+
duthost = duthosts[enum_rand_one_per_hwsku_hostname]
862+
skip_release(duthost, ["201811", "201911", "202012"])
852863

853864
for i in self.sfp_setup["sfp_test_port_indices"]:
854865
error_description = sfp.get_error_description(platform_api_conn, i)
855866
if self.expect(error_description is not None,
856867
"Unable to retrieve transceiver {} error description".format(i)):
857868
if "Not implemented" in error_description:
858869
pytest.skip("get_error_description isn't implemented. Skip the test")
859-
if "Not supported" in error_description:
870+
871+
expected_state = 'OK'
872+
if is_mellanox_device(duthost) and is_sw_control_enabled(duthost, i):
873+
intf = self.sfp_setup["index_physical_port_map"][i][0]
874+
expected_state = get_port_expected_error_state_for_mellanox_device_on_sw_control_enabled(
875+
intf, passive_cable_ports[duthost.hostname], cmis_cable_ports_and_ver[duthost.hostname])
876+
elif "Not supported" in error_description:
860877
logger.warning("test_get_error_description: Skipping transceiver {} as error description not "
861878
"supported on this port)".format(i))
862879
continue
863880
if self.expect(isinstance(error_description, str) or isinstance(error_description, str),
864881
"Transceiver {} error description appears incorrect".format(i)):
865-
self.expect(error_description == "OK", "Transceiver {} is not present".format(i))
882+
self.expect(error_description == expected_state,
883+
f"Transceiver {i} is not {expected_state}, actual state is:{error_description}.")
866884
self.assert_expectations()
867885

868886
def test_thermals(self, platform_api_conn):

tests/platform_tests/conftest.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
from tests.common.plugins.sanity_check.recover import neighbor_vm_restore
1616
from .args.counterpoll_cpu_usage_args import add_counterpoll_cpu_usage_args
1717
from .mellanox.mellanox_thermal_control_test_helper import suspend_hw_tc_service, resume_hw_tc_service
18-
from tests.common.platform.transceiver_utils import get_ports_with_flat_memory
18+
from tests.common.platform.transceiver_utils import get_ports_with_flat_memory, \
19+
get_passive_cable_port_list, get_cmis_cable_ports_and_ver
20+
1921

2022
logger = logging.getLogger(__name__)
2123

@@ -800,3 +802,21 @@ def port_list_with_flat_memory(duthosts):
800802
ports_with_flat_memory.update({dut.hostname: get_ports_with_flat_memory(dut)})
801803
logging.info(f"port list with flat memory: {ports_with_flat_memory}")
802804
return ports_with_flat_memory
805+
806+
807+
@pytest.fixture(scope="module")
808+
def passive_cable_ports(duthosts):
809+
passive_cable_ports = {}
810+
for dut in duthosts:
811+
passive_cable_ports.update({dut.hostname: get_passive_cable_port_list(dut)})
812+
logging.info(f"passive_cable_ports: {passive_cable_ports}")
813+
return passive_cable_ports
814+
815+
816+
@pytest.fixture(scope="module")
817+
def cmis_cable_ports_and_ver(duthosts):
818+
cmis_cable_ports_and_ver = {}
819+
for dut in duthosts:
820+
cmis_cable_ports_and_ver.update({dut.hostname: get_cmis_cable_ports_and_ver(dut)})
821+
logging.info(f"cmis_cable_ports_and_ver: {cmis_cable_ports_and_ver}")
822+
return cmis_cable_ports_and_ver

tests/platform_tests/sfp/test_sfputil.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
from tests.common.fixtures.duthost_utils import shutdown_ebgp # noqa F401
1818
from tests.common.port_toggle import default_port_toggle_wait_time
1919
from tests.common.platform.interface_utils import get_physical_port_indices
20+
from tests.common.mellanox_data import is_mellanox_device
21+
from tests.common.platform.transceiver_utils import is_sw_control_enabled,\
22+
get_port_expected_error_state_for_mellanox_device_on_sw_control_enabled
23+
2024

2125
cmd_sfp_presence = "sudo sfputil show presence"
2226
cmd_sfp_eeprom = "sudo sfputil show eeprom"
@@ -319,10 +323,12 @@ def test_check_sfputil_presence(duthosts, enum_rand_one_per_hwsku_frontend_hostn
319323
assert parsed_presence[intf] == "Present", "Interface presence is not 'Present'"
320324

321325

326+
@pytest.mark.device_type('physical')
322327
@pytest.mark.parametrize("cmd_sfp_error_status",
323328
["sudo sfputil show error-status", "sudo sfputil show error-status --fetch-from-hardware"])
324329
def test_check_sfputil_error_status(duthosts, enum_rand_one_per_hwsku_frontend_hostname,
325-
enum_frontend_asic_index, conn_graph_facts, cmd_sfp_error_status, xcvr_skip_list):
330+
enum_frontend_asic_index, conn_graph_facts, cmd_sfp_error_status, xcvr_skip_list,
331+
passive_cable_ports, cmis_cable_ports_and_ver):
326332
"""
327333
@summary: Check SFP error status using 'sfputil show error-status'
328334
and 'sfputil show error-status --fetch-from-hardware'
@@ -339,14 +345,22 @@ def test_check_sfputil_error_status(duthosts, enum_rand_one_per_hwsku_frontend_h
339345
if "NOT implemented" in sfp_error_status['stdout']:
340346
pytest.skip("Skip test as error status isn't supported")
341347
parsed_presence = parse_output(sfp_error_status["stdout_lines"][2:])
348+
physical_port_index_map = get_physical_port_indices(duthost, conn_graph_facts["device_conn"][duthost.hostname])
342349
for intf in dev_conn:
343350
if intf not in xcvr_skip_list[duthost.hostname]:
344-
if "Not supported" in sfp_error_status['stdout']:
345-
logger.warning("test_check_sfputil_error_status: Skipping transceiver {} as error status not "
346-
"supported on this port)".format(intf))
351+
expected_state = 'OK'
352+
intf_index = physical_port_index_map[intf]
353+
if cmd_sfp_error_status == "sudo sfputil show error-status --fetch-from-hardware"\
354+
and is_mellanox_device(duthost) and is_sw_control_enabled(duthost, intf_index):
355+
expected_state = get_port_expected_error_state_for_mellanox_device_on_sw_control_enabled(
356+
intf, passive_cable_ports[duthost.hostname], cmis_cable_ports_and_ver[duthost.hostname])
357+
elif "Not supported" in sfp_error_status['stdout']:
358+
logger.warning("test_check_sfputil_error_status: Skipping transceiver {} as error status "
359+
"not supported on this port)".format(intf))
347360
continue
348-
assert intf in parsed_presence, "Interface is not in output of '{}'".format(cmd_sfp_presence)
349-
assert parsed_presence[intf] == "OK", "Interface error status is not 'OK'"
361+
assert intf in parsed_presence, "Interface is not in output of '{}'".format(cmd_sfp_error_status)
362+
assert parsed_presence[intf] == expected_state, \
363+
f"Interface {intf}'s error status is not {expected_state}, actual state is:{parsed_presence[intf]}."
350364

351365

352366
def test_check_sfputil_eeprom(duthosts, enum_rand_one_per_hwsku_frontend_hostname,

tests/platform_tests/sfp/util.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ def parse_output(output_lines):
1212
res = {}
1313
for line in output_lines:
1414
fields = line.split()
15-
if len(fields) != 2:
15+
if len(fields) < 2:
1616
continue
17-
res[fields[0]] = fields[1]
17+
res[fields[0]] = line.replace(fields[0], '').strip()
1818
return res
1919

2020

0 commit comments

Comments
 (0)