Skip to content

Commit

Permalink
Move firmware version fields to TRANSCEIVER_FIRMWARE_INFO table (#435) (
Browse files Browse the repository at this point in the history
#436)

Signed-off-by: Mihir Patel <patelmi@microsoft.com>
  • Loading branch information
mihirpat1 authored Feb 19, 2024
1 parent 824c20a commit 95eb0c2
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 14 deletions.
37 changes: 35 additions & 2 deletions sonic-xcvrd/tests/test_xcvrd.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,19 @@ def test_post_port_dom_info_to_db(self, mock_get_sfp_type):
mock_get_sfp_type.return_value = 'QSFP_DD'
post_port_dom_info_to_db(logical_port_name, port_mapping, dom_tbl, stop_event)

@patch('xcvrd.xcvrd_utilities.port_mapping.PortMapping.logical_port_name_to_physical_port_list', MagicMock(return_value=[0]))
@patch('xcvrd.xcvrd._wrapper_get_presence', MagicMock(return_value=True))
@patch('xcvrd.xcvrd._wrapper_get_transceiver_firmware_info', MagicMock(return_value={'active_firmware': '2.1.1',
'inactive_firmware': '1.2.4'}))
def test_post_port_sfp_firmware_info_to_db(self):
logical_port_name = "Ethernet0"
port_mapping = PortMapping()
stop_event = threading.Event()
firmware_info_tbl = Table("STATE_DB", TRANSCEIVER_FIRMWARE_INFO_TABLE)
assert firmware_info_tbl.get_size() == 0
post_port_sfp_firmware_info_to_db(logical_port_name, port_mapping, firmware_info_tbl, stop_event)
assert firmware_info_tbl.get_size_for_key(logical_port_name) == 2

def test_post_port_dom_threshold_info_to_db(self, mock_get_sfp_type):
logical_port_name = "Ethernet0"
port_mapping = PortMapping()
Expand Down Expand Up @@ -214,7 +227,8 @@ def test_del_port_sfp_dom_info_from_db(self):
dom_threshold_tbl = Table("STATE_DB", TRANSCEIVER_DOM_THRESHOLD_TABLE)
init_tbl = Table("STATE_DB", TRANSCEIVER_INFO_TABLE)
pm_tbl = Table("STATE_DB", TRANSCEIVER_PM_TABLE)
del_port_sfp_dom_info_from_db(logical_port_name, port_mapping, init_tbl, dom_tbl, dom_threshold_tbl, pm_tbl)
firmware_info_tbl = Table("STATE_DB", TRANSCEIVER_FIRMWARE_INFO_TABLE)
del_port_sfp_dom_info_from_db(logical_port_name, port_mapping, init_tbl, dom_tbl, dom_threshold_tbl, pm_tbl, firmware_info_tbl)

@patch('xcvrd.xcvrd.get_physical_port_name_dict', MagicMock(return_value={0: 'Ethernet0'}))
@patch('xcvrd.xcvrd._wrapper_get_presence', MagicMock(return_value=True))
Expand Down Expand Up @@ -1181,6 +1195,7 @@ def test_SfpStateUpdateTask_retry_eeprom_reading(self, mock_post_sfp_info):
task.xcvr_table_helper.get_dom_threshold_tbl = MagicMock(return_value=mock_table)
task.xcvr_table_helper.get_app_port_tbl = MagicMock(return_value=mock_table)
task.xcvr_table_helper.get_status_tbl = MagicMock(return_value=mock_table)
task.xcvr_table_helper.get_firmware_info_tbl = MagicMock(return_value=mock_table)
task.retry_eeprom_reading()
assert mock_post_sfp_info.call_count == 0

Expand Down Expand Up @@ -1229,12 +1244,13 @@ def test_SfpStateUpdateTask_mapping_event_from_change_event(self):
@patch('xcvrd.xcvrd._wrapper_get_transceiver_change_event')
@patch('xcvrd.xcvrd.del_port_sfp_dom_info_from_db')
@patch('xcvrd.xcvrd.notify_media_setting')
@patch('xcvrd.xcvrd.post_port_sfp_firmware_info_to_db')
@patch('xcvrd.xcvrd.post_port_dom_threshold_info_to_db')
@patch('xcvrd.xcvrd.post_port_sfp_info_to_db')
@patch('xcvrd.xcvrd.update_port_transceiver_status_table_sw')
@patch('xcvrd.xcvrd.delete_port_from_status_table_hw')
def test_SfpStateUpdateTask_task_worker(self, mock_del_status_hw,
mock_update_status, mock_post_sfp_info, mock_post_dom_th, mock_update_media_setting,
mock_update_status, mock_post_sfp_info, mock_post_dom_th, mock_post_firmware_info, mock_update_media_setting,
mock_del_dom, mock_change_event, mock_mapping_event, mock_os_kill):
port_mapping = PortMapping()
stop_event = threading.Event()
Expand Down Expand Up @@ -1286,6 +1302,7 @@ def test_SfpStateUpdateTask_task_worker(self, mock_del_status_hw,
assert mock_update_status.call_count == 1
assert mock_post_sfp_info.call_count == 2 # first call and retry call
assert mock_post_dom_th.call_count == 0
assert mock_post_firmware_info.call_count == 0
assert mock_update_media_setting.call_count == 0
assert 'Ethernet0' in task.retry_eeprom_set
task.retry_eeprom_set.clear()
Expand All @@ -1299,6 +1316,7 @@ def test_SfpStateUpdateTask_task_worker(self, mock_del_status_hw,
assert mock_update_status.call_count == 1
assert mock_post_sfp_info.call_count == 1
assert mock_post_dom_th.call_count == 1
assert mock_post_firmware_info.call_count == 1
assert mock_update_media_setting.call_count == 1

stop_event.is_set = MagicMock(side_effect=[False, True])
Expand Down Expand Up @@ -1479,6 +1497,21 @@ def test_wrapper_get_transceiver_info(self, mock_sfputil, mock_chassis):
mock_sfputil.get_transceiver_info_dict = MagicMock(return_value=False)
assert not _wrapper_get_transceiver_info(1)

@patch('xcvrd.xcvrd.platform_chassis')
@patch('xcvrd.xcvrd.platform_sfputil')
def test_wrapper_get_transceiver_firmware_info(self, mock_sfputil, mock_chassis):
mock_object = MagicMock()
mock_object.get_transceiver_bulk_status = MagicMock(return_value=True)
mock_chassis.get_sfp = MagicMock(return_value=mock_object)
from xcvrd.xcvrd import _wrapper_get_transceiver_firmware_info
assert _wrapper_get_transceiver_firmware_info(1)

mock_object.get_transceiver_info_firmware_versions = MagicMock(return_value={})
assert _wrapper_get_transceiver_firmware_info(1) == {}

mock_chassis.get_sfp = MagicMock(side_effect=NotImplementedError)
assert _wrapper_get_transceiver_firmware_info(1) == {}

@patch('xcvrd.xcvrd.platform_chassis')
@patch('xcvrd.xcvrd.platform_sfputil')
def test_wrapper_get_transceiver_dom_info(self, mock_sfputil, mock_chassis):
Expand Down
67 changes: 55 additions & 12 deletions sonic-xcvrd/xcvrd/xcvrd.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
PLATFORM_SPECIFIC_CLASS_NAME = "SfpUtil"

TRANSCEIVER_INFO_TABLE = 'TRANSCEIVER_INFO'
TRANSCEIVER_FIRMWARE_INFO_TABLE = 'TRANSCEIVER_FIRMWARE_INFO'
TRANSCEIVER_DOM_SENSOR_TABLE = 'TRANSCEIVER_DOM_SENSOR'
TRANSCEIVER_DOM_THRESHOLD_TABLE = 'TRANSCEIVER_DOM_THRESHOLD'
TRANSCEIVER_STATUS_TABLE = 'TRANSCEIVER_STATUS'
Expand Down Expand Up @@ -175,6 +176,13 @@ def _wrapper_get_transceiver_info(physical_port):
pass
return platform_sfputil.get_transceiver_info_dict(physical_port)

def _wrapper_get_transceiver_firmware_info(physical_port):
if platform_chassis is not None:
try:
return platform_chassis.get_sfp(physical_port).get_transceiver_info_firmware_versions()
except NotImplementedError:
pass
return {}

def _wrapper_get_transceiver_dom_info(physical_port):
if platform_chassis is not None:
Expand Down Expand Up @@ -361,10 +369,6 @@ def post_port_sfp_info_to_db(logical_port_name, port_mapping, table, transceiver
('dom_capability', port_info_dict['dom_capability']
if 'dom_capability' in port_info_dict else 'N/A'),
('cmis_rev', port_info_dict['cmis_rev'] if 'cmis_rev' in port_info_dict else 'N/A'),
('active_firmware', port_info_dict['active_firmware']
if 'active_firmware' in port_info_dict else 'N/A'),
('inactive_firmware', port_info_dict['inactive_firmware']
if 'inactive_firmware' in port_info_dict else 'N/A'),
('hardware_rev', port_info_dict['hardware_rev']
if 'hardware_rev' in port_info_dict else 'N/A'),
('media_interface_code', port_info_dict['media_interface_code']
Expand Down Expand Up @@ -438,6 +442,29 @@ def post_port_sfp_info_to_db(logical_port_name, port_mapping, table, transceiver
helper_logger.log_error("This functionality is currently not implemented for this platform")
sys.exit(NOT_IMPLEMENTED_ERROR)

# Update port sfp firmware info in db

def post_port_sfp_firmware_info_to_db(logical_port_name, port_mapping, table,
stop_event=threading.Event()):
for physical_port, physical_port_name in get_physical_port_name_dict(logical_port_name, port_mapping).items():
if stop_event.is_set():
break

if not _wrapper_get_presence(physical_port):
continue

try:
transceiver_firmware_info_dict = _wrapper_get_transceiver_firmware_info(physical_port)
if transceiver_firmware_info_dict is not None:
fvs = swsscommon.FieldValuePairs([(k, v) for k, v in transceiver_firmware_info_dict.items()])
table.set(physical_port_name, fvs)
else:
return SFP_EEPROM_NOT_READY

except NotImplementedError:
helper_logger.log_error("Transceiver firmware info functionality is currently not implemented for this platform")
sys.exit(NOT_IMPLEMENTED_ERROR)

# Update port dom threshold info in db


Expand Down Expand Up @@ -548,7 +575,7 @@ def post_port_pm_info_to_db(logical_port_name, port_mapping, table, stop_event=t
# Delete port dom/sfp info from db


def del_port_sfp_dom_info_from_db(logical_port_name, port_mapping, int_tbl, dom_tbl, dom_threshold_tbl, pm_tbl):
def del_port_sfp_dom_info_from_db(logical_port_name, port_mapping, int_tbl, dom_tbl, dom_threshold_tbl, pm_tbl, firmware_info_tbl):
for physical_port_name in get_physical_port_name_dict(logical_port_name, port_mapping).values():
try:
if int_tbl:
Expand All @@ -559,6 +586,8 @@ def del_port_sfp_dom_info_from_db(logical_port_name, port_mapping, int_tbl, dom_
dom_threshold_tbl._del(physical_port_name)
if pm_tbl:
pm_tbl._del(physical_port_name)
if firmware_info_tbl:
firmware_info_tbl._del(physical_port_name)

except NotImplementedError:
helper_logger.log_error("This functionality is currently not implemented for this platform")
Expand Down Expand Up @@ -1834,13 +1863,14 @@ def on_remove_logical_port(self, port_change_event):
"""
# To avoid race condition, remove the entry TRANSCEIVER_DOM_SENSOR, TRANSCEIVER_PM and HW section of TRANSCEIVER_STATUS table.
# This thread only updates TRANSCEIVER_DOM_SENSOR, TRANSCEIVER_PM and HW section of TRANSCEIVER_STATUS table,
# so we don't have to remove entries from TRANSCEIVER_INFO and TRANSCEIVER_DOM_THRESHOLD
# so we don't have to remove entries from TRANSCEIVER_INFO, TRANSCEIVER_FIRMWARE_INFO and TRANSCEIVER_DOM_THRESHOLD
del_port_sfp_dom_info_from_db(port_change_event.port_name,
self.port_mapping,
None,
self.xcvr_table_helper.get_dom_tbl(port_change_event.asic_id),
None,
self.xcvr_table_helper.get_pm_tbl(port_change_event.asic_id))
self.xcvr_table_helper.get_pm_tbl(port_change_event.asic_id),
None)
delete_port_from_status_table_hw(port_change_event.port_name,
self.port_mapping,
self.xcvr_table_helper.get_status_tbl(port_change_event.asic_id))
Expand Down Expand Up @@ -1918,6 +1948,7 @@ def _post_port_sfp_info_and_dom_thr_to_db_once(self, port_mapping, xcvr_table_he
rc = post_port_sfp_info_to_db(logical_port_name, port_mapping, xcvr_table_helper.get_intf_tbl(asic_index), transceiver_dict, stop_event)
if rc != SFP_EEPROM_NOT_READY:
post_port_dom_threshold_info_to_db(logical_port_name, port_mapping, xcvr_table_helper.get_dom_threshold_tbl(asic_index), stop_event)
post_port_sfp_firmware_info_to_db(logical_port_name, port_mapping, xcvr_table_helper.get_firmware_info_tbl(asic_index), stop_event)

# Do not notify media settings during warm reboot to avoid dataplane traffic impact
if is_warm_start == False:
Expand Down Expand Up @@ -2143,6 +2174,7 @@ def task_worker(self, stopping_event, sfp_error_event):

if rc != SFP_EEPROM_NOT_READY:
post_port_dom_threshold_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_threshold_tbl(asic_index))
post_port_sfp_firmware_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_firmware_info_tbl(asic_index))
notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper.get_app_port_tbl(asic_index), self.port_mapping)
transceiver_dict.clear()
elif value == sfp_status_helper.SFP_STATUS_REMOVED:
Expand All @@ -2154,7 +2186,8 @@ def task_worker(self, stopping_event, sfp_error_event):
self.xcvr_table_helper.get_intf_tbl(asic_index),
self.xcvr_table_helper.get_dom_tbl(asic_index),
self.xcvr_table_helper.get_dom_threshold_tbl(asic_index),
self.xcvr_table_helper.get_pm_tbl(asic_index))
self.xcvr_table_helper.get_pm_tbl(asic_index),
self.xcvr_table_helper.get_firmware_info_tbl(asic_index))
delete_port_from_status_table_hw(logical_port, self.port_mapping, self.xcvr_table_helper.get_status_tbl(asic_index))
else:
try:
Expand Down Expand Up @@ -2182,7 +2215,8 @@ def task_worker(self, stopping_event, sfp_error_event):
None,
self.xcvr_table_helper.get_dom_tbl(asic_index),
self.xcvr_table_helper.get_dom_threshold_tbl(asic_index),
self.xcvr_table_helper.get_pm_tbl(asic_index))
self.xcvr_table_helper.get_pm_tbl(asic_index),
self.xcvr_table_helper.get_firmware_info_tbl(asic_index))
delete_port_from_status_table_hw(logical_port, self.port_mapping, self.xcvr_table_helper.get_status_tbl(asic_index))
except (TypeError, ValueError) as e:
helper_logger.log_error("{}: Got unrecognized event {}, ignored".format(logical_port, value))
Expand Down Expand Up @@ -2279,7 +2313,8 @@ def on_remove_logical_port(self, port_change_event):
self.xcvr_table_helper.get_intf_tbl(port_change_event.asic_id),
self.xcvr_table_helper.get_dom_tbl(port_change_event.asic_id),
self.xcvr_table_helper.get_dom_threshold_tbl(port_change_event.asic_id),
self.xcvr_table_helper.get_pm_tbl(port_change_event.asic_id))
self.xcvr_table_helper.get_pm_tbl(port_change_event.asic_id),
self.xcvr_table_helper.get_firmware_info_tbl(port_change_event.asic_id))
delete_port_from_status_table_sw(port_change_event.port_name, self.xcvr_table_helper.get_status_tbl(port_change_event.asic_id))
delete_port_from_status_table_hw(port_change_event.port_name,
self.port_mapping,
Expand Down Expand Up @@ -2308,6 +2343,7 @@ def on_add_logical_port(self, port_change_event):
status_tbl = self.xcvr_table_helper.get_status_tbl(port_change_event.asic_id)
int_tbl = self.xcvr_table_helper.get_intf_tbl(port_change_event.asic_id)
dom_threshold_tbl = self.xcvr_table_helper.get_dom_threshold_tbl(port_change_event.asic_id)
firmware_info_tbl = self.xcvr_table_helper.get_firmware_info_tbl(port_change_event.asic_id)

error_description = 'N/A'
status = None
Expand Down Expand Up @@ -2342,6 +2378,7 @@ def on_add_logical_port(self, port_change_event):
self.retry_eeprom_set.add(port_change_event.port_name)
else:
post_port_dom_threshold_info_to_db(port_change_event.port_name, self.port_mapping, dom_threshold_tbl)
post_port_sfp_firmware_info_to_db(port_change_event.port_name, self.port_mapping, firmware_info_tbl)
notify_media_setting(port_change_event.port_name, transceiver_dict, self.xcvr_table_helper.get_app_port_tbl(port_change_event.asic_id), self.port_mapping)
else:
status = sfp_status_helper.SFP_STATUS_REMOVED if not status else status
Expand All @@ -2368,6 +2405,7 @@ def retry_eeprom_reading(self):
rc = post_port_sfp_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_intf_tbl(asic_index), transceiver_dict)
if rc != SFP_EEPROM_NOT_READY:
post_port_dom_threshold_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_threshold_tbl(asic_index))
post_port_sfp_firmware_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_firmware_info_tbl(asic_index))
notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper.get_app_port_tbl(asic_index), self.port_mapping)
transceiver_dict.clear()
retry_success_set.add(logical_port)
Expand Down Expand Up @@ -2508,7 +2546,8 @@ def deinit(self):
self.xcvr_table_helper.get_intf_tbl(asic_index),
self.xcvr_table_helper.get_dom_tbl(asic_index),
self.xcvr_table_helper.get_dom_threshold_tbl(asic_index),
self.xcvr_table_helper.get_pm_tbl(asic_index))
self.xcvr_table_helper.get_pm_tbl(asic_index),
self.xcvr_table_helper.get_firmware_info_tbl(asic_index))
delete_port_from_status_table_sw(logical_port_name, self.xcvr_table_helper.get_status_tbl(asic_index))
delete_port_from_status_table_hw(logical_port_name, port_mapping_data, self.xcvr_table_helper.get_status_tbl(asic_index))

Expand Down Expand Up @@ -2588,7 +2627,7 @@ def run(self):
class XcvrTableHelper:
def __init__(self, namespaces):
self.int_tbl, self.dom_tbl, self.dom_threshold_tbl, self.status_tbl, self.app_port_tbl, \
self.cfg_port_tbl, self.state_port_tbl, self.pm_tbl = {}, {}, {}, {}, {}, {}, {}, {}
self.cfg_port_tbl, self.state_port_tbl, self.pm_tbl, self.firmware_info_tbl = {}, {}, {}, {}, {}, {}, {}, {}, {}
self.state_db = {}
self.cfg_db = {}
for namespace in namespaces:
Expand All @@ -2599,6 +2638,7 @@ def __init__(self, namespaces):
self.dom_threshold_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_DOM_THRESHOLD_TABLE)
self.status_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_STATUS_TABLE)
self.pm_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_PM_TABLE)
self.firmware_info_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_FIRMWARE_INFO_TABLE)
self.state_port_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], swsscommon.STATE_PORT_TABLE_NAME)
appl_db = daemon_base.db_connect("APPL_DB", namespace)
self.app_port_tbl[asic_id] = swsscommon.ProducerStateTable(appl_db, swsscommon.APP_PORT_TABLE_NAME)
Expand All @@ -2620,6 +2660,9 @@ def get_status_tbl(self, asic_id):
def get_pm_tbl(self, asic_id):
return self.pm_tbl[asic_id]

def get_firmware_info_tbl(self, asic_id):
return self.firmware_info_tbl[asic_id]

def get_app_port_tbl(self, asic_id):
return self.app_port_tbl[asic_id]

Expand Down

0 comments on commit 95eb0c2

Please sign in to comment.