[Mellanox] implement sfp.reset for CMIS management (#16862)
- Why I did it For CMIS host management module, we need a different implementation for sfp.reset. This PR is to implement it - How I did it For SW control modules, do reset from hw_reset For FW control modules, do reset as the original way - How to verify it Manual test sonic-mgmt platform test
This commit is contained in:
parent
37a9c25cfb
commit
d8a1ffbace
@ -26,6 +26,7 @@ try:
|
|||||||
import ctypes
|
import ctypes
|
||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
|
import threading
|
||||||
from sonic_py_common.logger import Logger
|
from sonic_py_common.logger import Logger
|
||||||
from sonic_py_common.general import check_output_pipe
|
from sonic_py_common.general import check_output_pipe
|
||||||
from . import utils
|
from . import utils
|
||||||
@ -219,6 +220,9 @@ class SdkHandleContext(object):
|
|||||||
deinitialize_sdk_handle(self.sdk_handle)
|
deinitialize_sdk_handle(self.sdk_handle)
|
||||||
|
|
||||||
class NvidiaSFPCommon(SfpOptoeBase):
|
class NvidiaSFPCommon(SfpOptoeBase):
|
||||||
|
sfp_index_to_logical_port_dict = {}
|
||||||
|
sfp_index_to_logical_lock = threading.Lock()
|
||||||
|
|
||||||
def __init__(self, sfp_index):
|
def __init__(self, sfp_index):
|
||||||
super(NvidiaSFPCommon, self).__init__()
|
super(NvidiaSFPCommon, self).__init__()
|
||||||
self.index = sfp_index + 1
|
self.index = sfp_index + 1
|
||||||
@ -248,6 +252,30 @@ class NvidiaSFPCommon(SfpOptoeBase):
|
|||||||
|
|
||||||
return oper_state, error_type
|
return oper_state, error_type
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_sfp_index_to_logical_port(cls, force=False):
|
||||||
|
if not cls.sfp_index_to_logical_port_dict or force:
|
||||||
|
config_db = utils.DbUtils.get_db_instance('CONFIG_DB')
|
||||||
|
port_data = config_db.get_table('PORT')
|
||||||
|
for key, data in port_data.items():
|
||||||
|
if data['index'] not in cls.sfp_index_to_logical_port_dict:
|
||||||
|
cls.sfp_index_to_logical_port_dict[int(data['index']) - 1] = key
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_logical_port_by_sfp_index(cls, sfp_index):
|
||||||
|
with cls.sfp_index_to_logical_lock:
|
||||||
|
cls.get_sfp_index_to_logical_port()
|
||||||
|
logical_port_name = cls.sfp_index_to_logical_port_dict.get(sfp_index)
|
||||||
|
if not logical_port_name:
|
||||||
|
cls.get_sfp_index_to_logical_port(force=True)
|
||||||
|
else:
|
||||||
|
config_db = utils.DbUtils.get_db_instance('CONFIG_DB')
|
||||||
|
current_index = int(config_db.get('CONFIG_DB', f'PORT|{logical_port_name}', 'index'))
|
||||||
|
if current_index != sfp_index:
|
||||||
|
cls.get_sfp_index_to_logical_port(force=True)
|
||||||
|
logical_port_name = cls.sfp_index_to_logical_port_dict.get(sfp_index)
|
||||||
|
return logical_port_name
|
||||||
|
|
||||||
|
|
||||||
class SFP(NvidiaSFPCommon):
|
class SFP(NvidiaSFPCommon):
|
||||||
"""Platform-specific SFP class"""
|
"""Platform-specific SFP class"""
|
||||||
@ -299,6 +327,17 @@ class SFP(NvidiaSFPCommon):
|
|||||||
Returns:
|
Returns:
|
||||||
bool: True if device is present, False if not
|
bool: True if device is present, False if not
|
||||||
"""
|
"""
|
||||||
|
if DeviceDataManager.is_independent_mode():
|
||||||
|
if utils.read_int_from_file(f'/sys/module/sx_core/asic0/module{self.sdk_index}/control') != 0:
|
||||||
|
if not utils.read_int_from_file(f'/sys/module/sx_core/asic0/module{self.sdk_index}/hw_present'):
|
||||||
|
return False
|
||||||
|
if not utils.read_int_from_file(f'/sys/module/sx_core/asic0/module{self.sdk_index}/power_good'):
|
||||||
|
return False
|
||||||
|
if not utils.read_int_from_file(f'/sys/module/sx_core/asic0/module{self.sdk_index}/power_on'):
|
||||||
|
return False
|
||||||
|
if utils.read_int_from_file(f'/sys/module/sx_core/asic0/module{self.sdk_index}/hw_reset') == 1:
|
||||||
|
return False
|
||||||
|
|
||||||
eeprom_raw = self._read_eeprom(0, 1, log_on_error=False)
|
eeprom_raw = self._read_eeprom(0, 1, log_on_error=False)
|
||||||
return eeprom_raw is not None
|
return eeprom_raw is not None
|
||||||
|
|
||||||
@ -455,8 +494,17 @@ class SFP(NvidiaSFPCommon):
|
|||||||
|
|
||||||
refer plugins/sfpreset.py
|
refer plugins/sfpreset.py
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
|
if not self.is_sw_control():
|
||||||
file_path = SFP_SDK_MODULE_SYSFS_ROOT_TEMPLATE.format(self.sdk_index) + SFP_SYSFS_RESET
|
file_path = SFP_SDK_MODULE_SYSFS_ROOT_TEMPLATE.format(self.sdk_index) + SFP_SYSFS_RESET
|
||||||
return utils.write_file(file_path, '1')
|
return utils.write_file(file_path, '1')
|
||||||
|
else:
|
||||||
|
file_path = SFP_SDK_MODULE_SYSFS_ROOT_TEMPLATE.format(self.sdk_index) + SFP_SYSFS_HWRESET
|
||||||
|
return utils.write_file(file_path, '0') and utils.write_file(file_path, '1')
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Failed to reset module - {e}')
|
||||||
|
logger.log_error(f'Failed to reset module - {e}')
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -918,15 +966,15 @@ class SFP(NvidiaSFPCommon):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
db = utils.DbUtils.get_db_instance('STATE_DB')
|
db = utils.DbUtils.get_db_instance('STATE_DB')
|
||||||
control_type = db.get('STATE_DB', f'TRANSCEIVER_MODULES_MGMT|{self.sdk_index}', 'control_type')
|
logical_port = NvidiaSFPCommon.get_logical_port_by_sfp_index(self.sdk_index)
|
||||||
control_file_value = utils.read_int_from_file(f'/sys/module/sx_core/asic0/module{self.sdk_index}/control')
|
if not logical_port:
|
||||||
|
raise Exception(f'Module {self.sdk_index} is not present or in initialization')
|
||||||
|
|
||||||
if control_type == 'SW_CONTROL' and control_file_value == 1:
|
initialized = db.exists('STATE_DB', f'TRANSCEIVER_STATUS|{logical_port}')
|
||||||
return True
|
if not initialized:
|
||||||
elif control_type == 'FW_CONTROL' and control_file_value == 0:
|
raise Exception(f'Module {self.sdk_index} is not present or in initialization')
|
||||||
return False
|
|
||||||
else:
|
return utils.read_int_from_file(f'/sys/module/sx_core/asic0/module{self.sdk_index}/control') == 1
|
||||||
raise Exception(f'Module {self.sdk_index} is in initialization, please retry later')
|
|
||||||
|
|
||||||
|
|
||||||
class RJ45Port(NvidiaSFPCommon):
|
class RJ45Port(NvidiaSFPCommon):
|
||||||
|
@ -381,9 +381,9 @@ class DbUtils:
|
|||||||
cls.db_instances.data = {}
|
cls.db_instances.data = {}
|
||||||
|
|
||||||
if db_name not in cls.db_instances.data:
|
if db_name not in cls.db_instances.data:
|
||||||
from swsscommon.swsscommon import SonicV2Connector
|
from swsscommon.swsscommon import ConfigDBConnector
|
||||||
db = SonicV2Connector(use_unix_socket_path=True)
|
db = ConfigDBConnector(use_unix_socket_path=True)
|
||||||
db.connect(db_name)
|
db.db_connect(db_name)
|
||||||
cls.db_instances.data[db_name] = db
|
cls.db_instances.data[db_name] = db
|
||||||
return cls.db_instances.data[db_name]
|
return cls.db_instances.data[db_name]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -266,9 +266,14 @@ class TestSfp:
|
|||||||
@mock.patch('sonic_platform.utils.write_file')
|
@mock.patch('sonic_platform.utils.write_file')
|
||||||
def test_reset(self, mock_write):
|
def test_reset(self, mock_write):
|
||||||
sfp = SFP(0)
|
sfp = SFP(0)
|
||||||
|
sfp.is_sw_control = mock.MagicMock(return_value=False)
|
||||||
mock_write.return_value = True
|
mock_write.return_value = True
|
||||||
assert sfp.reset()
|
assert sfp.reset()
|
||||||
mock_write.assert_called_with('/sys/module/sx_core/asic0/module0/reset', '1')
|
mock_write.assert_called_with('/sys/module/sx_core/asic0/module0/reset', '1')
|
||||||
|
sfp.is_sw_control.return_value = True
|
||||||
|
assert sfp.reset()
|
||||||
|
sfp.is_sw_control.side_effect = Exception('')
|
||||||
|
assert not sfp.reset()
|
||||||
|
|
||||||
@mock.patch('sonic_platform.sfp.SFP.read_eeprom')
|
@mock.patch('sonic_platform.sfp.SFP.read_eeprom')
|
||||||
def test_get_xcvr_api(self, mock_read):
|
def test_get_xcvr_api(self, mock_read):
|
||||||
@ -332,31 +337,33 @@ class TestSfp:
|
|||||||
assert sfp.get_temperature_warning_threashold() == 75.0
|
assert sfp.get_temperature_warning_threashold() == 75.0
|
||||||
assert sfp.get_temperature_critical_threashold() == 85.0
|
assert sfp.get_temperature_critical_threashold() == 85.0
|
||||||
|
|
||||||
|
@mock.patch('sonic_platform.sfp.NvidiaSFPCommon.get_logical_port_by_sfp_index')
|
||||||
@mock.patch('sonic_platform.utils.read_int_from_file')
|
@mock.patch('sonic_platform.utils.read_int_from_file')
|
||||||
@mock.patch('sonic_platform.device_data.DeviceDataManager.is_independent_mode')
|
@mock.patch('sonic_platform.device_data.DeviceDataManager.is_independent_mode')
|
||||||
@mock.patch('sonic_platform.utils.DbUtils.get_db_instance')
|
@mock.patch('sonic_platform.utils.DbUtils.get_db_instance')
|
||||||
def test_is_sw_control(self, mock_get_db, mock_mode, mock_read):
|
def test_is_sw_control(self, mock_get_db, mock_mode, mock_read, mock_get_logical):
|
||||||
sfp = SFP(0)
|
sfp = SFP(0)
|
||||||
mock_mode.return_value = False
|
mock_mode.return_value = False
|
||||||
assert not sfp.is_sw_control()
|
assert not sfp.is_sw_control()
|
||||||
mock_mode.return_value = True
|
mock_mode.return_value = True
|
||||||
|
|
||||||
mock_db = mock.MagicMock()
|
mock_get_logical.return_value = None
|
||||||
mock_get_db.return_value = mock_db
|
|
||||||
mock_db.get = mock.MagicMock(return_value=None)
|
|
||||||
with pytest.raises(Exception):
|
with pytest.raises(Exception):
|
||||||
sfp.is_sw_control()
|
sfp.is_sw_control()
|
||||||
|
|
||||||
mock_read.return_value = 0
|
mock_get_logical.return_value = 'Ethernet0'
|
||||||
mock_db.get.return_value = 'FW_CONTROL'
|
mock_db = mock.MagicMock()
|
||||||
assert not sfp.is_sw_control()
|
mock_get_db.return_value = mock_db
|
||||||
mock_read.return_value = 1
|
mock_db.exists = mock.MagicMock(return_value=False)
|
||||||
mock_db.get.return_value = 'SW_CONTROL'
|
|
||||||
assert sfp.is_sw_control()
|
|
||||||
mock_read.return_value = 0
|
|
||||||
with pytest.raises(Exception):
|
with pytest.raises(Exception):
|
||||||
sfp.is_sw_control()
|
sfp.is_sw_control()
|
||||||
|
|
||||||
|
mock_db.exists.return_value = True
|
||||||
|
mock_read.return_value = 0
|
||||||
|
assert not sfp.is_sw_control()
|
||||||
|
mock_read.return_value = 1
|
||||||
|
assert sfp.is_sw_control()
|
||||||
|
|
||||||
@mock.patch('sonic_platform.device_data.DeviceDataManager.is_independent_mode', mock.MagicMock(return_value=False))
|
@mock.patch('sonic_platform.device_data.DeviceDataManager.is_independent_mode', mock.MagicMock(return_value=False))
|
||||||
@mock.patch('sonic_platform.sfp.SFP.is_sw_control', mock.MagicMock(return_value=False))
|
@mock.patch('sonic_platform.sfp.SFP.is_sw_control', mock.MagicMock(return_value=False))
|
||||||
@mock.patch('sonic_platform.utils.is_host', mock.MagicMock(side_effect = [True, True, False, False]))
|
@mock.patch('sonic_platform.utils.is_host', mock.MagicMock(side_effect = [True, True, False, False]))
|
||||||
|
Loading…
Reference in New Issue
Block a user