Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Independent Module - sonic-buildimage code to support port SI configuration per speed #5

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions platform/mellanox/mlnx-platform-api/sonic_platform/device_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
21 changes: 21 additions & 0 deletions platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand All @@ -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):
"""
Expand Down Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions platform/mellanox/mlnx-platform-api/tests/test_chassis.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down
2 changes: 2 additions & 0 deletions platform/mellanox/mlnx-platform-api/tests/test_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 14 additions & 0 deletions platform/mellanox/mlnx-platform-api/tests/test_sfp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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):
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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)
Expand All @@ -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):
Expand All @@ -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']
Expand All @@ -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')
Expand Down Expand Up @@ -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)
Expand All @@ -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()
Expand All @@ -240,13 +250,15 @@ 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)
mock_write.return_value = True
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)
Expand All @@ -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):
Expand All @@ -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)
Expand Down