diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/device_data.py b/platform/mellanox/mlnx-platform-api/sonic_platform/device_data.py index 9f681709ccd2..d8ea0e0bd1ff 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/device_data.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/device_data.py @@ -227,3 +227,29 @@ def get_cpld_component_list(cls): # Currently, only fetching BIOS version is supported return ComponentCPLDSN2201.get_component_list() return ComponentCPLD.get_component_list() + + @classmethod + @utils.read_only_cache() + def platform_supports_independent_mode(cls): + from sonic_py_common import device_info + (_, hwsku_dir) = device_info.get_paths_to_platform_and_hwsku_dirs() + + INDEPENDENT_MODULE_SUPPORT_FIELD = 'SAI_INDEPENDENT_MODULE_MODE' + INDEPENDENT_MODULE_SUPPORT_DELIMITER = '=' + INDEPNENT_MODULE_SUPPORT_TRUE_VALUE = '1' + SAI_PROFILE_FILE_NAME = 'sai.profile' + sai_profile_path = hwsku_dir + '/' + SAI_PROFILE_FILE_NAME + + try: + with open(sai_profile_path, "r", encoding='utf-8') as fd: + for line in fd: + if line.startswith(INDEPENDENT_MODULE_SUPPORT_FIELD): + if INDEPENDENT_MODULE_SUPPORT_DELIMITER in line: + split_line = line.split(INDEPENDENT_MODULE_SUPPORT_DELIMITER) + if (len(split_line) > 1): + independent_mode_value = split_line[1].strip() + return True if independent_mode_value == INDEPNENT_MODULE_SUPPORT_TRUE_VALUE else False + return False + + except FileNotFoundError: + return False diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py index 76c841713f80..dc6fc7f4ff13 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py @@ -31,6 +31,7 @@ from . import utils from .device_data import DeviceDataManager from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase + from swsscommon.swsscommon import SonicV2Connector except ImportError as e: raise ImportError (str(e) + "- required module not found") @@ -159,6 +160,18 @@ # Global logger class instance logger = Logger() +def is_independent_module(index): + db = SonicV2Connector(use_unix_socket_path=False) + db.connect(db.STATE_DB) + + TRANSCEIVER_MODULES_MGMT_TABLE_NAME = 'TRANSCEIVER_MODULES_MGMT' + CONTROL_TYPE_KEY = "control type" + SW_CONTROL_CONTROL_TYPE = "SW_CONTROL" + table_name = TRANSCEIVER_MODULES_MGMT_TABLE_NAME + "|" + str(index) + result = db.get(db.STATE_DB, table_name, CONTROL_TYPE_KEY) + + return result == SW_CONTROL_CONTROL_TYPE + class NvidiaSFPCommon(SfpOptoeBase): def __init__(self, sfp_index): @@ -217,6 +230,8 @@ def __init__(self, sfp_index, sfp_type=None, slot_id=0, linecard_port_count=0, l self.slot_id = slot_id self._sfp_type_str = None + self._is_independent_module = is_independent_module(self.sdk_index) + def reinit(self): """ Re-initialize this SFP object when a new SFP inserted @@ -235,6 +250,9 @@ def get_presence(self): eeprom_raw = self._read_eeprom(0, 1, log_on_error=False) return eeprom_raw is not None + def is_independent_module(self): + return self._is_independent_module + # read eeprom specfic bytes beginning from offset with size as num_bytes def read_eeprom(self, offset, num_bytes): """ @@ -483,6 +501,9 @@ def _is_write_protected(self, page, page_offset, num_bytes): Returns: bool: True if the limited bytes is hit """ + if DeviceDataManager.platform_supports_independent_mode() and self.is_independent_module(): + return False + eeprom_path = self._get_eeprom_path() limited_data = limited_eeprom.get(self._get_sfp_type_str(eeprom_path)) if not limited_data: diff --git a/platform/mellanox/mlnx-platform-api/tests/test_chassis.py b/platform/mellanox/mlnx-platform-api/tests/test_chassis.py index aefff3a7f00b..fad03524e92f 100644 --- a/platform/mellanox/mlnx-platform-api/tests/test_chassis.py +++ b/platform/mellanox/mlnx-platform-api/tests/test_chassis.py @@ -122,6 +122,7 @@ def test_fan(self): chassis._fan_drawer_list = [] assert chassis.get_num_fan_drawers() == 2 + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) def test_sfp(self): # Test get_num_sfps, it should not create any SFP objects DeviceDataManager.get_sfp_count = mock.MagicMock(return_value=3) @@ -170,6 +171,7 @@ def test_sfp(self): @mock.patch('sonic_platform.sfp_event.sfp_event.check_sfp_status', MagicMock()) @mock.patch('sonic_platform.sfp_event.sfp_event.__init__', MagicMock(return_value=None)) @mock.patch('sonic_platform.sfp_event.sfp_event.initialize', MagicMock()) + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.device_data.DeviceDataManager.get_sfp_count', MagicMock(return_value=3)) def test_change_event(self): from sonic_platform.sfp_event import sfp_event @@ -244,12 +246,14 @@ def read_int_from_file(file_path, *args, **kwargs): mock_file_content[file_path] = 0 @mock.patch('sonic_platform.chassis.Chassis._wait_reboot_cause_ready', MagicMock(return_value=False)) + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) def test_reboot_cause_timeout(self): chassis = Chassis() major, minor = chassis.get_reboot_cause() assert major == chassis.REBOOT_CAUSE_NON_HARDWARE assert minor == '' + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.utils.read_int_from_file') @mock.patch('sonic_platform.chassis.time.sleep', mock.MagicMock()) def test_wait_reboot_cause_ready(self, mock_read_int): diff --git a/platform/mellanox/mlnx-platform-api/tests/test_module.py b/platform/mellanox/mlnx-platform-api/tests/test_module.py index 4cba90ac95f4..b0cf12a5d2e1 100644 --- a/platform/mellanox/mlnx-platform-api/tests/test_module.py +++ b/platform/mellanox/mlnx-platform-api/tests/test_module.py @@ -44,11 +44,13 @@ def test_chassis_get_num_sfp(self): chassis = ModularChassis() assert chassis.get_num_sfps() == 4 + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) def test_chassis_get_all_sfps(self): utils.read_int_from_file = mock.MagicMock(return_value=1) chassis = ModularChassis() assert len(chassis.get_all_sfps()) == 4 + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.device_data.DeviceDataManager.get_linecard_max_port_count', mock.MagicMock(return_value=16)) def test_chassis_get_sfp(self): utils.read_int_from_file = mock.MagicMock(return_value=1) diff --git a/platform/mellanox/mlnx-platform-api/tests/test_sfp.py b/platform/mellanox/mlnx-platform-api/tests/test_sfp.py index 4f5d4f160008..2dccbb79c333 100644 --- a/platform/mellanox/mlnx-platform-api/tests/test_sfp.py +++ b/platform/mellanox/mlnx-platform-api/tests/test_sfp.py @@ -35,6 +35,7 @@ class TestSfp: @mock.patch('sonic_platform.device_data.DeviceDataManager.get_linecard_count', mock.MagicMock(return_value=8)) @mock.patch('sonic_platform.device_data.DeviceDataManager.get_linecard_max_port_count') + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) def test_sfp_index(self, mock_max_port): sfp = SFP(0) assert sfp.is_replaceable() @@ -56,6 +57,7 @@ def test_sfp_index(self, mock_max_port): @mock.patch('sonic_platform.sfp.SFP.read_eeprom', mock.MagicMock(return_value=None)) @mock.patch('sonic_platform.sfp.SFP._get_module_info') + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.chassis.Chassis.get_num_sfps', mock.MagicMock(return_value=2)) @mock.patch('sonic_platform.chassis.extract_RJ45_ports_index', mock.MagicMock(return_value=[])) def test_sfp_get_error_status(self, mock_get_error_code): @@ -87,6 +89,7 @@ def test_sfp_get_error_status(self, mock_get_error_code): assert description == expected_description + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.sfp.SFP._get_page_and_page_offset') @mock.patch('sonic_platform.sfp.SFP._is_write_protected') def test_sfp_write_eeprom(self, mock_limited_eeprom, mock_get_page): @@ -121,6 +124,7 @@ def test_sfp_write_eeprom(self, mock_limited_eeprom, mock_get_page): handle.write.side_effect = OSError('') assert not sfp.write_eeprom(0, 1, bytearray([1])) + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.sfp.SFP._get_page_and_page_offset') def test_sfp_read_eeprom(self, mock_get_page): sfp = SFP(0) @@ -142,6 +146,8 @@ def test_sfp_read_eeprom(self, mock_get_page): handle.read.side_effect = OSError('') assert sfp.read_eeprom(0, 1) is None + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) + @mock.patch('sonic_platform.device_data.DeviceDataManager.platform_supports_independent_mode', mock.MagicMock(return_value=False)) @mock.patch('sonic_platform.sfp.SFP._get_eeprom_path', mock.MagicMock(return_value = None)) @mock.patch('sonic_platform.sfp.SFP._get_sfp_type_str') def test_is_write_protected(self, mock_get_type_str): @@ -157,6 +163,7 @@ def test_is_write_protected(self, mock_get_type_str): mock_get_type_str.return_value = 'invalid' assert not sfp._is_write_protected(page=0, page_offset=0, num_bytes=1) + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) def test_get_sfp_type_str(self): sfp = SFP(0) expect_sfp_types = ['cmis', 'sff8636', 'sff8472'] @@ -172,6 +179,7 @@ def test_get_sfp_type_str(self): os.system('rm -rf {}'.format(mock_eeprom_path)) assert sfp._get_sfp_type_str('invalid') is None + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('os.path.exists') @mock.patch('sonic_platform.sfp.SFP._get_eeprom_path') @mock.patch('sonic_platform.sfp.SFP._get_sfp_type_str') @@ -207,6 +215,7 @@ def test_get_page_and_page_offset(self, mock_get_type_str, mock_eeprom_path, moc assert page == '/tmp/1/data' assert page_offset is 0 + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.sfp.SFP._read_eeprom') def test_sfp_get_presence(self, mock_read): sfp = SFP(0) @@ -226,6 +235,7 @@ def test_rj45_get_presence(self, mock_read_int): mock_read_int.return_value = 1 assert sfp.get_presence() + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.sfp.SFP.get_xcvr_api') def test_dummy_apis(self, mock_get_xcvr_api): mock_api = mock.MagicMock() @@ -240,6 +250,7 @@ def test_dummy_apis(self, mock_get_xcvr_api): assert sfp.get_rx_los() is None assert sfp.get_tx_fault() is None + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.utils.write_file') def test_reset(self, mock_write): sfp = SFP(0) @@ -247,6 +258,7 @@ def test_reset(self, mock_write): assert sfp.reset() mock_write.assert_called_with('/sys/module/sx_core/asic0/module0/reset', '1') + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.utils.read_int_from_file') def test_get_lpmode(self, mock_read_int): sfp = SFP(0) @@ -257,6 +269,7 @@ def test_get_lpmode(self, mock_read_int): mock_read_int.return_value = 2 assert not sfp.get_lpmode() + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.utils.write_file') @mock.patch('sonic_platform.utils.read_int_from_file') def test_set_lpmode(self, mock_read_int, mock_write): @@ -268,6 +281,7 @@ def test_set_lpmode(self, mock_read_int, mock_write): assert sfp.set_lpmode(True) mock_write.assert_called_with('/sys/module/sx_core/asic0/module0/power_mode_policy', '2') + @mock.patch('sonic_platform.sfp.is_independent_module', mock.MagicMock()) @mock.patch('sonic_platform.sfp.SFP.read_eeprom') def test_get_xcvr_api(self, mock_read): sfp = SFP(0)