From 172255fc8ad49c4fd0f6bf542896a58d9d8b9404 Mon Sep 17 00:00:00 2001 From: longhuan-cisco <84595962+longhuan-cisco@users.noreply.github.com> Date: Fri, 7 Oct 2022 14:47:38 -0700 Subject: [PATCH 01/10] Add new fields to DOM_SENSOR table in STATE_DB for C_CMIS (#1) * Push new fields to DOM_SENSOR table in STATE_DB * Remove empty line Signed-off-by: Longyin Huang longhuan@cisco.com --- sonic-xcvrd/xcvrd/xcvrd.py | 89 ++++++-------------------------------- 1 file changed, 14 insertions(+), 75 deletions(-) diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 55d5da8f1..9b643c406 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -19,6 +19,7 @@ import datetime import subprocess import argparse + import re from sonic_py_common import daemon_base, device_info, logger from sonic_py_common import multi_asic @@ -216,33 +217,18 @@ def _wrapper_get_sfp_error_description(physical_port): # Remove unnecessary unit from the raw data def beautify_dom_info_dict(dom_info_dict, physical_port): - dom_info_dict['temperature'] = strip_unit_and_beautify(dom_info_dict['temperature'], TEMP_UNIT) - dom_info_dict['voltage'] = strip_unit_and_beautify(dom_info_dict['voltage'], VOLT_UNIT) - dom_info_dict['rx1power'] = strip_unit_and_beautify(dom_info_dict['rx1power'], POWER_UNIT) - dom_info_dict['rx2power'] = strip_unit_and_beautify(dom_info_dict['rx2power'], POWER_UNIT) - dom_info_dict['rx3power'] = strip_unit_and_beautify(dom_info_dict['rx3power'], POWER_UNIT) - dom_info_dict['rx4power'] = strip_unit_and_beautify(dom_info_dict['rx4power'], POWER_UNIT) - dom_info_dict['tx1bias'] = strip_unit_and_beautify(dom_info_dict['tx1bias'], BIAS_UNIT) - dom_info_dict['tx2bias'] = strip_unit_and_beautify(dom_info_dict['tx2bias'], BIAS_UNIT) - dom_info_dict['tx3bias'] = strip_unit_and_beautify(dom_info_dict['tx3bias'], BIAS_UNIT) - dom_info_dict['tx4bias'] = strip_unit_and_beautify(dom_info_dict['tx4bias'], BIAS_UNIT) - dom_info_dict['tx1power'] = strip_unit_and_beautify(dom_info_dict['tx1power'], POWER_UNIT) - dom_info_dict['tx2power'] = strip_unit_and_beautify(dom_info_dict['tx2power'], POWER_UNIT) - dom_info_dict['tx3power'] = strip_unit_and_beautify(dom_info_dict['tx3power'], POWER_UNIT) - dom_info_dict['tx4power'] = strip_unit_and_beautify(dom_info_dict['tx4power'], POWER_UNIT) - if 'rx5power' in dom_info_dict: - dom_info_dict['rx5power'] = strip_unit_and_beautify(dom_info_dict['rx5power'], POWER_UNIT) - dom_info_dict['rx6power'] = strip_unit_and_beautify(dom_info_dict['rx6power'], POWER_UNIT) - dom_info_dict['rx7power'] = strip_unit_and_beautify(dom_info_dict['rx7power'], POWER_UNIT) - dom_info_dict['rx8power'] = strip_unit_and_beautify(dom_info_dict['rx8power'], POWER_UNIT) - dom_info_dict['tx5bias'] = strip_unit_and_beautify(dom_info_dict['tx5bias'], BIAS_UNIT) - dom_info_dict['tx6bias'] = strip_unit_and_beautify(dom_info_dict['tx6bias'], BIAS_UNIT) - dom_info_dict['tx7bias'] = strip_unit_and_beautify(dom_info_dict['tx7bias'], BIAS_UNIT) - dom_info_dict['tx8bias'] = strip_unit_and_beautify(dom_info_dict['tx8bias'], BIAS_UNIT) - dom_info_dict['tx5power'] = strip_unit_and_beautify(dom_info_dict['tx5power'], POWER_UNIT) - dom_info_dict['tx6power'] = strip_unit_and_beautify(dom_info_dict['tx6power'], POWER_UNIT) - dom_info_dict['tx7power'] = strip_unit_and_beautify(dom_info_dict['tx7power'], POWER_UNIT) - dom_info_dict['tx8power'] = strip_unit_and_beautify(dom_info_dict['tx8power'], POWER_UNIT) + for k, v in dom_info_dict.items(): + if k == 'temperature': + dom_info_dict[k] = strip_unit_and_beautify(v, TEMP_UNIT) + elif k == 'voltage': + dom_info_dict[k] = strip_unit_and_beautify(v, VOLT_UNIT) + elif re.match('^(tx|rx)[1-8]power$', k): + dom_info_dict[k] = strip_unit_and_beautify(v, POWER_UNIT) + elif re.match('^(tx|rx)[1-8]bias$', k): + dom_info_dict[k] = strip_unit_and_beautify(v, BIAS_UNIT) + elif type(v) is not str: + # For all the other keys: + dom_info_dict[k] = str(v) def beautify_dom_threshold_info_dict(dom_info_dict): @@ -507,55 +493,8 @@ def post_port_dom_info_to_db(logical_port_name, port_mapping, table, stop_event= dom_info_cache[physical_port] = dom_info_dict if dom_info_dict is not None: beautify_dom_info_dict(dom_info_dict, physical_port) - if 'rx5power' in dom_info_dict: - fvs = swsscommon.FieldValuePairs( - [('temperature', dom_info_dict['temperature']), - ('voltage', dom_info_dict['voltage']), - ('rx1power', dom_info_dict['rx1power']), - ('rx2power', dom_info_dict['rx2power']), - ('rx3power', dom_info_dict['rx3power']), - ('rx4power', dom_info_dict['rx4power']), - ('rx5power', dom_info_dict['rx5power']), - ('rx6power', dom_info_dict['rx6power']), - ('rx7power', dom_info_dict['rx7power']), - ('rx8power', dom_info_dict['rx8power']), - ('tx1bias', dom_info_dict['tx1bias']), - ('tx2bias', dom_info_dict['tx2bias']), - ('tx3bias', dom_info_dict['tx3bias']), - ('tx4bias', dom_info_dict['tx4bias']), - ('tx5bias', dom_info_dict['tx5bias']), - ('tx6bias', dom_info_dict['tx6bias']), - ('tx7bias', dom_info_dict['tx7bias']), - ('tx8bias', dom_info_dict['tx8bias']), - ('tx1power', dom_info_dict['tx1power']), - ('tx2power', dom_info_dict['tx2power']), - ('tx3power', dom_info_dict['tx3power']), - ('tx4power', dom_info_dict['tx4power']), - ('tx5power', dom_info_dict['tx5power']), - ('tx6power', dom_info_dict['tx6power']), - ('tx7power', dom_info_dict['tx7power']), - ('tx8power', dom_info_dict['tx8power']) - ]) - else: - fvs = swsscommon.FieldValuePairs( - [('temperature', dom_info_dict['temperature']), - ('voltage', dom_info_dict['voltage']), - ('rx1power', dom_info_dict['rx1power']), - ('rx2power', dom_info_dict['rx2power']), - ('rx3power', dom_info_dict['rx3power']), - ('rx4power', dom_info_dict['rx4power']), - ('tx1bias', dom_info_dict['tx1bias']), - ('tx2bias', dom_info_dict['tx2bias']), - ('tx3bias', dom_info_dict['tx3bias']), - ('tx4bias', dom_info_dict['tx4bias']), - ('tx1power', dom_info_dict['tx1power']), - ('tx2power', dom_info_dict['tx2power']), - ('tx3power', dom_info_dict['tx3power']), - ('tx4power', dom_info_dict['tx4power']) - ]) - + fvs = swsscommon.FieldValuePairs([(k, v) for k, v in dom_info_dict.items()]) table.set(port_name, fvs) - else: return SFP_EEPROM_NOT_READY From 1af64a0a48f4b93115aca06047dad45d3387c532 Mon Sep 17 00:00:00 2001 From: Longyin Huang Date: Mon, 10 Oct 2022 18:55:15 -0700 Subject: [PATCH 02/10] Add new fields to status table in STATE_DB --- sonic-xcvrd/tests/test_xcvrd.py | 4 +- sonic-xcvrd/xcvrd/xcvrd.py | 137 +++++++++++++++++++++++++++++--- 2 files changed, 127 insertions(+), 14 deletions(-) diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index 4af09bf23..84c520463 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -812,7 +812,7 @@ def test_SfpStateUpdateTask_mapping_event_from_change_event(self): @patch('xcvrd.xcvrd.post_port_dom_threshold_info_to_db') @patch('xcvrd.xcvrd.post_port_dom_info_to_db') @patch('xcvrd.xcvrd.post_port_sfp_info_to_db') - @patch('xcvrd.xcvrd.update_port_transceiver_status_table') + @patch('xcvrd.xcvrd.update_port_transceiver_status_table_sw') def test_SfpStateUpdateTask_task_worker(self, mock_updata_status, mock_post_sfp_info, mock_post_dom_info, mock_post_dom_th, mock_update_media_setting, mock_del_dom, mock_change_event, mock_mapping_event, mock_os_kill): port_mapping = PortMapping() retry_eeprom_set = set() @@ -906,7 +906,7 @@ def test_SfpStateUpdateTask_task_worker(self, mock_updata_status, mock_post_sfp_ @patch('xcvrd.xcvrd.post_port_dom_threshold_info_to_db') @patch('xcvrd.xcvrd.post_port_dom_info_to_db') @patch('xcvrd.xcvrd.post_port_sfp_info_to_db') - @patch('xcvrd.xcvrd.update_port_transceiver_status_table') + @patch('xcvrd.xcvrd.update_port_transceiver_status_table_sw') def test_SfpStateUpdateTask_on_add_logical_port(self, mock_updata_status, mock_post_sfp_info, mock_post_dom_info, mock_post_dom_th, mock_update_media_setting, mock_get_presence, mock_table_helper): class MockTable: pass diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 9b5117239..7543a9677 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -43,6 +43,8 @@ TRANSCEIVER_DOM_SENSOR_TABLE = 'TRANSCEIVER_DOM_SENSOR' TRANSCEIVER_STATUS_TABLE = 'TRANSCEIVER_STATUS' +TRANSCEIVER_STATUS_TABLE_SW_FIELDS = ["status", "error"] + # Mgminit time required as per CMIS spec MGMT_INIT_TIME_DELAY_SECS = 2 @@ -107,6 +109,28 @@ def get_physical_port_name(logical_port, physical_port, ganged): else: return logical_port +# Get physical port name dict (port_idx to port_name) + + +def get_physical_port_name_dict(logical_port_name, port_mapping): + ganged_port = False + ganged_member_num = 1 + + physical_port_list = port_mapping.logical_port_name_to_physical_port_list(logical_port_name) + if physical_port_list is None: + helper_logger.log_error("No physical ports found for logical port '{}'".format(logical_port_name)) + + if len(physical_port_list) > 1: + ganged_port = True + + port_name_dict = {} + for physical_port in physical_port_list: + port_name = get_physical_port_name(logical_port_name, ganged_member_num, ganged_port) + ganged_member_num += 1 + port_name_dict[physical_port] = port_name + + return port_name_dict + # Strip units and beautify @@ -165,6 +189,16 @@ def _wrapper_get_transceiver_dom_threshold_info(physical_port): pass return platform_sfputil.get_transceiver_dom_threshold_info_dict(physical_port) + +def _wrapper_get_transceiver_status(physical_port): + if platform_chassis is not None: + try: + return platform_chassis.get_sfp(physical_port).get_transceiver_status() + except NotImplementedError: + pass + return {} + + # Soak SFP insert event until management init completes def _wrapper_soak_sfp_insert_event(sfp_insert_events, port_dict): for key, value in list(port_dict.items()): @@ -257,6 +291,13 @@ def beautify_dom_threshold_info_dict(dom_info_dict): dom_info_dict['txbiashighwarning'] = strip_unit_and_beautify(dom_info_dict['txbiashighwarning'], BIAS_UNIT) dom_info_dict['txbiaslowwarning'] = strip_unit_and_beautify(dom_info_dict['txbiaslowwarning'], BIAS_UNIT) + +def beautify_transceiver_status_dict(transceiver_status_dict, physical_port): + for k, v in transceiver_status_dict.items(): + if type(v) is str: + continue + transceiver_status_dict[k] = str(v) + # Update port sfp info in db @@ -525,6 +566,10 @@ def post_port_sfp_dom_info_to_db(is_warm_start, port_mapping, xcvr_table_helper, if rc != SFP_EEPROM_NOT_READY: post_port_dom_info_to_db(logical_port_name, port_mapping, xcvr_table_helper.get_dom_tbl(asic_index), stop_event) post_port_dom_threshold_info_to_db(logical_port_name, port_mapping, xcvr_table_helper.get_dom_tbl(asic_index), stop_event) + update_port_transceiver_status_table_hw(logical_port_name, + port_mapping, + xcvr_table_helper.get_status_tbl(asic_index), + stop_event) # Do not notify media settings during warm reboot to avoid dataplane traffic impact if is_warm_start == False: @@ -795,20 +840,65 @@ def waiting_time_compensation_with_sleep(time_start, time_to_wait): if time_diff < time_to_wait: time.sleep(time_to_wait - time_diff) -# Update port SFP status table on receiving SFP change event +# Update port SFP status table for SW fields on receiving SFP change event -def update_port_transceiver_status_table(logical_port_name, status_tbl, status, error_descriptions='N/A'): +def update_port_transceiver_status_table_sw(logical_port_name, status_tbl, status, error_descriptions='N/A'): fvs = swsscommon.FieldValuePairs([('status', status), ('error', error_descriptions)]) status_tbl.set(logical_port_name, fvs) +# Update port SFP status table for HW fields + + +def update_port_transceiver_status_table_hw(logical_port_name, port_mapping, + table, stop_event=threading.Event(), transceiver_status_cache=None): + 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: + if transceiver_status_cache is not None and physical_port in transceiver_status_cache: + # If cache is enabled and dom information is in cache, just read from cache, no need read from EEPROM + transceiver_status_dict = transceiver_status_cache[physical_port] + else: + transceiver_status_dict = _wrapper_get_transceiver_status(physical_port) + if transceiver_status_cache is not None: + # If cache is enabled, put dom information to cache + transceiver_status_cache[physical_port] = transceiver_status_dict + if transceiver_status_dict is not None: + beautify_transceiver_status_dict(transceiver_status_dict, physical_port) + fvs = swsscommon.FieldValuePairs([(k, v) for k, v in transceiver_status_dict.items()]) + table.set(physical_port_name, fvs) + else: + return SFP_EEPROM_NOT_READY + + except NotImplementedError: + helper_logger.log_error("This functionality is currently not implemented for this platform") + sys.exit(NOT_IMPLEMENTED_ERROR) # Delete port from SFP status table -def delete_port_from_status_table(logical_port_name, status_tbl): +def delete_port_from_status_table_sw(logical_port_name, status_tbl): status_tbl._del(logical_port_name) +# Delete port from SFP status table for HW fields which are fetched from EEPROM + + +def delete_port_from_status_table_hw(logical_port_name, port_mapping, status_tbl): + for physical_port_name in get_physical_port_name_dict(logical_port_name, port_mapping).values(): + found, fvs = status_tbl.get(physical_port_name) + if not found: + return + status_dict = dict(fvs) + for f, _ in status_dict: + if f in TRANSCEIVER_STATUS_TABLE_SW_FIELDS: + continue + status_tbl.hdel(physical_port_name, f) + # Init TRANSCEIVER_STATUS table @@ -828,16 +918,16 @@ def init_port_sfp_status_tbl(port_mapping, xcvr_table_helper, stop_event=threadi physical_port_list = port_mapping.logical_port_name_to_physical_port_list(logical_port_name) if physical_port_list is None: helper_logger.log_error("No physical ports found for logical port '{}'".format(logical_port_name)) - update_port_transceiver_status_table(logical_port_name, xcvr_table_helper.get_status_tbl(asic_index), sfp_status_helper.SFP_STATUS_REMOVED) + update_port_transceiver_status_table_sw(logical_port_name, xcvr_table_helper.get_status_tbl(asic_index), sfp_status_helper.SFP_STATUS_REMOVED) for physical_port in physical_port_list: if stop_event.is_set(): break if not _wrapper_get_presence(physical_port): - update_port_transceiver_status_table(logical_port_name, xcvr_table_helper.get_status_tbl(asic_index), sfp_status_helper.SFP_STATUS_REMOVED) + update_port_transceiver_status_table_sw(logical_port_name, xcvr_table_helper.get_status_tbl(asic_index), sfp_status_helper.SFP_STATUS_REMOVED) else: - update_port_transceiver_status_table(logical_port_name, xcvr_table_helper.get_status_tbl(asic_index), sfp_status_helper.SFP_STATUS_INSERTED) + update_port_transceiver_status_table_sw(logical_port_name, xcvr_table_helper.get_status_tbl(asic_index), sfp_status_helper.SFP_STATUS_INSERTED) def is_fast_reboot_enabled(): fastboot_enabled = False @@ -1559,6 +1649,7 @@ def task_worker(self): helper_logger.log_info("Start DOM monitoring loop") dom_info_cache = {} dom_th_info_cache = {} + transceiver_status_cache = {} sel, asic_context = port_mapping.subscribe_port_config_change(self.namespaces) # Start loop to update dom info in DB periodically @@ -1566,6 +1657,7 @@ def task_worker(self): # Clear the cache at the begin of the loop to make sure it will be clear each time dom_info_cache.clear() dom_th_info_cache.clear() + transceiver_status_cache.clear() # Handle port change event from main thread port_mapping.handle_port_config_change(sel, asic_context, self.task_stopping_event, self.port_mapping, helper_logger, self.on_port_config_change) @@ -1580,6 +1672,11 @@ def task_worker(self): if not sfp_status_helper.detect_port_in_error_status(logical_port_name, self.xcvr_table_helper.get_status_tbl(asic_index)): post_port_dom_info_to_db(logical_port_name, self.port_mapping, self.xcvr_table_helper.get_dom_tbl(asic_index), self.task_stopping_event, dom_info_cache=dom_info_cache) post_port_dom_threshold_info_to_db(logical_port_name, self.port_mapping, self.xcvr_table_helper.get_dom_tbl(asic_index), self.task_stopping_event, dom_th_info_cache=dom_th_info_cache) + update_port_transceiver_status_table_hw(logical_port_name, + self.port_mapping, + self.xcvr_table_helper.get_status_tbl(asic_index), + self.task_stopping_event, + transceiver_status_cache=transceiver_status_cache) helper_logger.log_info("Stop DOM monitoring loop") @@ -1612,6 +1709,9 @@ def on_remove_logical_port(self, port_change_event): self.port_mapping, None, self.xcvr_table_helper.get_dom_tbl(port_change_event.asic_id)) + 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)) # Process wrapper class to update sfp state info periodically @@ -1817,7 +1917,7 @@ def task_worker(self, stopping_event, sfp_error_event): if value == sfp_status_helper.SFP_STATUS_INSERTED: helper_logger.log_info("Got SFP inserted event") # A plugin event will clear the error state. - update_port_transceiver_status_table( + update_port_transceiver_status_table_sw( logical_port, self.xcvr_table_helper.get_status_tbl(asic_index), sfp_status_helper.SFP_STATUS_INSERTED) helper_logger.log_info("receive plug in and update port sfp status table.") rc = post_port_sfp_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_intf_tbl(asic_index), transceiver_dict) @@ -1833,14 +1933,16 @@ def task_worker(self, stopping_event, sfp_error_event): if rc != SFP_EEPROM_NOT_READY: post_port_dom_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_tbl(asic_index)) post_port_dom_threshold_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_tbl(asic_index)) + update_port_transceiver_status_table_hw(logical_port, self.port_mapping, self.xcvr_table_helper.get_status_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: helper_logger.log_info("Got SFP removed event") - update_port_transceiver_status_table( + update_port_transceiver_status_table_sw( logical_port, self.xcvr_table_helper.get_status_tbl(asic_index), sfp_status_helper.SFP_STATUS_REMOVED) helper_logger.log_info("receive plug out and pdate port sfp status table.") del_port_sfp_dom_info_from_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_intf_tbl(asic_index), self.xcvr_table_helper.get_dom_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: error_bits = int(value) @@ -1857,7 +1959,7 @@ def task_worker(self, stopping_event, sfp_error_event): # Add error info to database # Any existing error will be replaced by the new one. - update_port_transceiver_status_table(logical_port, self.xcvr_table_helper.get_status_tbl(asic_index), value, '|'.join(error_descriptions)) + update_port_transceiver_status_table_sw(logical_port, self.xcvr_table_helper.get_status_tbl(asic_index), value, '|'.join(error_descriptions)) helper_logger.log_info("Receive error update port sfp status table.") # In this case EEPROM is not accessible. The DOM info will be removed since it can be out-of-date. # The interface info remains in the DB since it is static. @@ -1866,6 +1968,9 @@ def task_worker(self, stopping_event, sfp_error_event): self.port_mapping, None, self.xcvr_table_helper.get_dom_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(value)) @@ -1940,7 +2045,10 @@ def on_remove_logical_port(self, port_change_event): self.port_mapping, self.xcvr_table_helper.get_intf_tbl(port_change_event.asic_id), self.xcvr_table_helper.get_dom_tbl(port_change_event.asic_id)) - delete_port_from_status_table(port_change_event.port_name, self.xcvr_table_helper.get_status_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, + self.xcvr_table_helper.get_status_tbl(port_change_event.asic_id)) # The logical port has been removed, no need retry EEPROM reading if port_change_event.port_name in self.retry_eeprom_set: @@ -2034,11 +2142,14 @@ def on_add_logical_port(self, port_change_event): else: post_port_dom_info_to_db(port_change_event.port_name, self.port_mapping, dom_tbl) post_port_dom_threshold_info_to_db(port_change_event.port_name, self.port_mapping, dom_tbl) + update_port_transceiver_status_table_hw(port_change_event.port_name, + self.port_mapping, + self.xcvr_table_helper.get_status_tbl(port_change_event.asic_id)) 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 logical_port_event_dict[port_change_event.port_name] = status - update_port_transceiver_status_table(port_change_event.port_name, status_tbl, status, error_description) + update_port_transceiver_status_table_sw(port_change_event.port_name, status_tbl, status, error_description) return logical_port_event_dict def retry_eeprom_reading(self): @@ -2063,6 +2174,7 @@ def retry_eeprom_reading(self): if rc != SFP_EEPROM_NOT_READY: post_port_dom_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_tbl(asic_index)) post_port_dom_threshold_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_tbl(asic_index)) + update_port_transceiver_status_table_hw(logical_port, self.port_mapping, self.xcvr_table_helper.get_status_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) @@ -2212,7 +2324,8 @@ def deinit(self): continue del_port_sfp_dom_info_from_db(logical_port_name, port_mapping_data, self.xcvr_table_helper.get_intf_tbl(asic_index), self.xcvr_table_helper.get_dom_tbl(asic_index)) - delete_port_from_status_table(logical_port_name, self.xcvr_table_helper.get_status_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)) del globals()['platform_chassis'] From 67e779e8c7fea9c5c95e4ff6b0e4102aee994bf6 Mon Sep 17 00:00:00 2001 From: Longyin Huang Date: Mon, 17 Oct 2022 16:02:00 -0700 Subject: [PATCH 03/10] Add test_xcvrd support --- sonic-xcvrd/tests/mock_swsscommon.py | 28 ++++--- sonic-xcvrd/tests/test_xcvrd.py | 113 +++++++++++++++++++++------ sonic-xcvrd/xcvrd/xcvrd.py | 5 +- 3 files changed, 111 insertions(+), 35 deletions(-) diff --git a/sonic-xcvrd/tests/mock_swsscommon.py b/sonic-xcvrd/tests/mock_swsscommon.py index 819547082..0cfc1e552 100644 --- a/sonic-xcvrd/tests/mock_swsscommon.py +++ b/sonic-xcvrd/tests/mock_swsscommon.py @@ -14,6 +14,19 @@ def _del(self, key): self.mock_keys.remove(key) pass + def hdel(self, key, field): + if key not in self.mock_dict: + return + + # swsscommon.FieldValuePairs + fvs = self.mock_dict[key] + for i, fv in enumerate(fvs): + if fv[0] == field: + del fvs[i] + break + if self.get_size_for_key(key) == 0: + self._del(key) + def set(self, key, fvs): self.mock_dict[key] = fvs self.mock_keys.append(key) @@ -21,17 +34,14 @@ def set(self, key, fvs): def get(self, key): if key in self.mock_dict: - return self.mock_dict[key] - return None + return True, self.mock_dict[key] + return False, None def get_size(self): return (len(self.mock_dict)) - - def getKeys(self): - return self.mock_keys + def get_size_for_key(self, key): + return len(self.mock_dict[key]) -class FieldValuePairs: - def __init__(self, fvs): - self.fv_dict = dict(fvs) - pass + def getKeys(self): + return self.mock_keys diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index 84c520463..02d1dccd0 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -89,6 +89,42 @@ def test_del_port_sfp_dom_info_from_db(self): init_tbl = Table("STATE_DB", TRANSCEIVER_INFO_TABLE) del_port_sfp_dom_info_from_db(logical_port_name, port_mapping, init_tbl, dom_tbl) + @patch('xcvrd.xcvrd.get_physical_port_name_dict', MagicMock(return_value={0: 'Ethernet0'})) + @patch('xcvrd.xcvrd._wrapper_get_presence', MagicMock(return_value=True)) + @patch('xcvrd.xcvrd._wrapper_get_transceiver_status', MagicMock(return_value={'module_state': 'ModuleReady', + 'module_fault_cause': 'No Fault detected', + 'datapath_firmware_fault': 'False', + 'module_firmware_fault': 'False', + 'module_state_changed': 'True'})) + def test_update_port_transceiver_status_table_hw(self): + logical_port_name = "Ethernet0" + port_mapping = PortMapping() + stop_event = threading.Event() + status_tbl = Table("STATE_DB", TRANSCEIVER_STATUS_TABLE) + assert status_tbl.get_size() == 0 + update_port_transceiver_status_table_hw(logical_port_name, port_mapping, status_tbl, stop_event) + assert status_tbl.get_size_for_key(logical_port_name) == 5 + + @patch('xcvrd.xcvrd.get_physical_port_name_dict', MagicMock(return_value={0: 'Ethernet0'})) + def test_delete_port_from_status_table_hw(self): + logical_port_name = "Ethernet0" + port_mapping = PortMapping() + status_tbl = Table("STATE_DB", TRANSCEIVER_STATUS_TABLE) + status_tbl.set(logical_port_name, + swsscommon.FieldValuePairs([('status', '1'), ('error', 'N/A'), ('module_state', 'ModuleReady')])) + assert status_tbl.get_size_for_key(logical_port_name) == 3 + delete_port_from_status_table_hw(logical_port_name, port_mapping, status_tbl) + assert status_tbl.get_size_for_key(logical_port_name) == 2 + + def test_delete_port_from_status_table_sw(self): + logical_port_name = "Ethernet0" + status_tbl = Table("STATE_DB", TRANSCEIVER_STATUS_TABLE) + status_tbl.set(logical_port_name, + swsscommon.FieldValuePairs([('status', '1'), ('error', 'N/A'), ('module_state', 'ModuleReady')])) + assert status_tbl.get_size_for_key(logical_port_name) == 3 + delete_port_from_status_table_sw(logical_port_name, status_tbl) + assert status_tbl.get_size_for_key(logical_port_name) == 1 + @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_dom_threshold_info', MagicMock(return_value={'temphighalarm': '22.75', @@ -642,7 +678,8 @@ def test_CmisManagerTask_task_worker(self, mock_chassis): assert task.port_dict['Ethernet0']['cmis_state'] == 'DP_ACTIVATION' @patch('xcvrd.xcvrd.XcvrTableHelper', MagicMock()) - def test_DomInfoUpdateTask_handle_port_change_event(self): + @patch('xcvrd.xcvrd.delete_port_from_status_table_hw') + def test_DomInfoUpdateTask_handle_port_change_event(self, mock_del_status_tbl_hw): port_mapping = PortMapping() task = DomInfoUpdateTask(DEFAULT_NAMESPACE, port_mapping) task.xcvr_table_helper = XcvrTableHelper(DEFAULT_NAMESPACE) @@ -652,6 +689,7 @@ def test_DomInfoUpdateTask_handle_port_change_event(self): assert task.port_mapping.get_asic_id_for_logical_port('Ethernet0') == 0 assert task.port_mapping.get_physical_to_logical(1) == ['Ethernet0'] assert task.port_mapping.get_logical_to_physical('Ethernet0') == [1] + assert mock_del_status_tbl_hw.call_count == 0 port_change_event = PortChangeEvent('Ethernet0', 1, 0, PortChangeEvent.PORT_REMOVE) task.on_port_config_change(port_change_event) @@ -659,6 +697,7 @@ def test_DomInfoUpdateTask_handle_port_change_event(self): assert not task.port_mapping.logical_to_physical assert not task.port_mapping.physical_to_logical assert not task.port_mapping.logical_to_asic + assert mock_del_status_tbl_hw.call_count == 1 @patch('xcvrd.xcvrd_utilities.port_mapping.subscribe_port_config_change', MagicMock(return_value=(None, None))) @patch('xcvrd.xcvrd_utilities.port_mapping.handle_port_config_change', MagicMock()) @@ -676,7 +715,9 @@ def test_DomInfoUpdateTask_task_run_stop(self): @patch('swsscommon.swsscommon.Select.addSelectable', MagicMock()) @patch('swsscommon.swsscommon.SubscriberStateTable') @patch('swsscommon.swsscommon.Select.select') - def test_DomInfoUpdateTask_task_worker(self, mock_select, mock_sub_table, mock_post_dom_th, mock_post_dom_info, mock_detect_error): + @patch('xcvrd.xcvrd.update_port_transceiver_status_table_hw') + def test_DomInfoUpdateTask_task_worker(self, mock_update_status_hw, mock_select, mock_sub_table, mock_post_dom_th, + mock_post_dom_info, mock_detect_error): mock_selectable = MagicMock() mock_selectable.pop = MagicMock( side_effect=[('Ethernet0', swsscommon.SET_COMMAND, (('index', '1'), )), (None, None, None), (None, None, None)]) @@ -695,15 +736,18 @@ def test_DomInfoUpdateTask_task_worker(self, mock_select, mock_sub_table, mock_p assert task.port_mapping.get_logical_to_physical('Ethernet0') == [1] assert mock_post_dom_th.call_count == 0 assert mock_post_dom_info.call_count == 0 + assert mock_update_status_hw.call_count == 0 mock_detect_error.return_value = False task.task_stopping_event.wait = MagicMock(side_effect=[False, True]) task.task_worker() assert mock_post_dom_th.call_count == 1 assert mock_post_dom_info.call_count == 1 + assert mock_update_status_hw.call_count == 1 @patch('xcvrd.xcvrd._wrapper_get_presence', MagicMock(return_value=False)) @patch('xcvrd.xcvrd.XcvrTableHelper') - def test_SfpStateUpdateTask_handle_port_change_event(self, mock_table_helper): + @patch('xcvrd.xcvrd.delete_port_from_status_table_hw') + def test_SfpStateUpdateTask_handle_port_change_event(self, mock_update_status_hw, mock_table_helper): mock_table = MagicMock() mock_table.get = MagicMock(return_value=(False, None)) mock_table_helper.get_status_tbl = MagicMock(return_value=mock_table) @@ -726,6 +770,7 @@ def test_SfpStateUpdateTask_handle_port_change_event(self, mock_table_helper): assert task.port_mapping.get_asic_id_for_logical_port('Ethernet0') == 0 assert task.port_mapping.get_physical_to_logical(1) == ['Ethernet0'] assert task.port_mapping.get_logical_to_physical('Ethernet0') == [1] + assert mock_update_status_hw.call_count == 0 port_change_event = PortChangeEvent('Ethernet0', 1, 0, PortChangeEvent.PORT_REMOVE) wait_time = 5 @@ -739,6 +784,7 @@ def test_SfpStateUpdateTask_handle_port_change_event(self, mock_table_helper): assert not task.port_mapping.logical_to_physical assert not task.port_mapping.physical_to_logical assert not task.port_mapping.logical_to_asic + assert mock_update_status_hw.call_count == 1 def test_SfpStateUpdateTask_task_run_stop(self): port_mapping = PortMapping() @@ -752,7 +798,8 @@ def test_SfpStateUpdateTask_task_run_stop(self): @patch('xcvrd.xcvrd.XcvrTableHelper', MagicMock()) @patch('xcvrd.xcvrd.post_port_sfp_info_to_db') - def test_SfpStateUpdateTask_retry_eeprom_reading(self, mock_post_sfp_info): + @patch('xcvrd.xcvrd.update_port_transceiver_status_table_hw') + def test_SfpStateUpdateTask_retry_eeprom_reading(self, mock_update_status_hw, mock_post_sfp_info): mock_table = MagicMock() mock_table.get = MagicMock(return_value=(False, None)) @@ -763,6 +810,7 @@ def test_SfpStateUpdateTask_retry_eeprom_reading(self, mock_post_sfp_info): task.xcvr_table_helper.get_intf_tbl = MagicMock(return_value=mock_table) task.xcvr_table_helper.get_dom_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.retry_eeprom_reading() assert mock_post_sfp_info.call_count == 0 @@ -770,16 +818,19 @@ def test_SfpStateUpdateTask_retry_eeprom_reading(self, mock_post_sfp_info): task.last_retry_eeprom_time = time.time() task.retry_eeprom_reading() assert mock_post_sfp_info.call_count == 0 + assert mock_update_status_hw.call_count == 0 task.last_retry_eeprom_time = 0 mock_post_sfp_info.return_value = SFP_EEPROM_NOT_READY task.retry_eeprom_reading() assert 'Ethernet0' in task.retry_eeprom_set + assert mock_update_status_hw.call_count == 0 task.last_retry_eeprom_time = 0 mock_post_sfp_info.return_value = None task.retry_eeprom_reading() assert 'Ethernet0' not in task.retry_eeprom_set + assert mock_update_status_hw.call_count == 1 def test_SfpStateUpdateTask_mapping_event_from_change_event(self): port_mapping = PortMapping() @@ -813,7 +864,11 @@ def test_SfpStateUpdateTask_mapping_event_from_change_event(self): @patch('xcvrd.xcvrd.post_port_dom_info_to_db') @patch('xcvrd.xcvrd.post_port_sfp_info_to_db') @patch('xcvrd.xcvrd.update_port_transceiver_status_table_sw') - def test_SfpStateUpdateTask_task_worker(self, mock_updata_status, mock_post_sfp_info, mock_post_dom_info, mock_post_dom_th, mock_update_media_setting, mock_del_dom, mock_change_event, mock_mapping_event, mock_os_kill): + @patch('xcvrd.xcvrd.update_port_transceiver_status_table_hw') + @patch('xcvrd.xcvrd.delete_port_from_status_table_hw') + def test_SfpStateUpdateTask_task_worker(self, mock_del_status_hw, mock_update_status_hw, mock_update_status, + mock_post_sfp_info, mock_post_dom_info, mock_post_dom_th, mock_update_media_setting, mock_del_dom, + mock_change_event, mock_mapping_event, mock_os_kill): port_mapping = PortMapping() retry_eeprom_set = set() task = SfpStateUpdateTask(DEFAULT_NAMESPACE, port_mapping, retry_eeprom_set) @@ -862,43 +917,52 @@ def test_SfpStateUpdateTask_task_worker(self, mock_updata_status, mock_post_sfp_ stop_event.is_set = MagicMock(side_effect=[False, True]) # Test state machine: handle SFP insert event, but EEPROM read failure task.task_worker(stop_event, sfp_error_event) - assert mock_updata_status.call_count == 1 + assert mock_update_status.call_count == 1 assert mock_post_sfp_info.call_count == 2 # first call and retry call assert mock_post_dom_info.call_count == 0 assert mock_post_dom_th.call_count == 0 + assert mock_update_status_hw.call_count == 0 assert mock_update_media_setting.call_count == 0 assert 'Ethernet0' in task.retry_eeprom_set task.retry_eeprom_set.clear() stop_event.is_set = MagicMock(side_effect=[False, True]) mock_post_sfp_info.return_value = None - mock_updata_status.reset_mock() + mock_update_status.reset_mock() mock_post_sfp_info.reset_mock() # Test state machine: handle SFP insert event, and EEPROM read success task.task_worker(stop_event, sfp_error_event) - assert mock_updata_status.call_count == 1 + assert mock_update_status.call_count == 1 assert mock_post_sfp_info.call_count == 1 assert mock_post_dom_info.call_count == 1 assert mock_post_dom_th.call_count == 1 + assert mock_update_status_hw.call_count == 1 assert mock_update_media_setting.call_count == 1 stop_event.is_set = MagicMock(side_effect=[False, True]) mock_change_event.return_value = (True, {1: SFP_STATUS_REMOVED}, {}) - mock_updata_status.reset_mock() + mock_update_status.reset_mock() + mock_update_status_hw.reset_mock() # Test state machine: handle SFP remove event task.task_worker(stop_event, sfp_error_event) - assert mock_updata_status.call_count == 1 + assert mock_update_status.call_count == 1 + assert mock_update_status_hw.call_count == 0 # only SW fields are updated assert mock_del_dom.call_count == 1 + assert mock_del_status_hw.call_count == 1 stop_event.is_set = MagicMock(side_effect=[False, True]) error = int(SFP_STATUS_INSERTED) | SfpBase.SFP_ERROR_BIT_BLOCKING | SfpBase.SFP_ERROR_BIT_POWER_BUDGET_EXCEEDED mock_change_event.return_value = (True, {1: error}, {}) - mock_updata_status.reset_mock() + mock_update_status.reset_mock() + mock_update_status_hw.reset_mock() mock_del_dom.reset_mock() + mock_del_status_hw.reset_mock() # Test state machine: handle SFP error event task.task_worker(stop_event, sfp_error_event) - assert mock_updata_status.call_count == 1 + assert mock_update_status.call_count == 1 + assert mock_update_status_hw.call_count == 0 # only SW fields are updated assert mock_del_dom.call_count == 1 + assert mock_del_status_hw.call_count == 1 @patch('xcvrd.xcvrd.XcvrTableHelper') @patch('xcvrd.xcvrd._wrapper_get_presence') @@ -907,7 +971,8 @@ def test_SfpStateUpdateTask_task_worker(self, mock_updata_status, mock_post_sfp_ @patch('xcvrd.xcvrd.post_port_dom_info_to_db') @patch('xcvrd.xcvrd.post_port_sfp_info_to_db') @patch('xcvrd.xcvrd.update_port_transceiver_status_table_sw') - def test_SfpStateUpdateTask_on_add_logical_port(self, mock_updata_status, mock_post_sfp_info, mock_post_dom_info, mock_post_dom_th, mock_update_media_setting, mock_get_presence, mock_table_helper): + def test_SfpStateUpdateTask_on_add_logical_port(self, mock_update_status, mock_post_sfp_info, mock_post_dom_info, + mock_post_dom_th, mock_update_media_setting, mock_get_presence, mock_table_helper): class MockTable: pass @@ -947,8 +1012,8 @@ class MockTable: mock_post_sfp_info.return_value = SFP_EEPROM_NOT_READY # SFP information is not in the DB, and SFP is present, and SFP has no error, but SFP EEPROM reading failed task.on_add_logical_port(port_change_event) - assert mock_updata_status.call_count == 1 - mock_updata_status.assert_called_with('Ethernet0', status_tbl, SFP_STATUS_INSERTED, 'N/A') + assert mock_update_status.call_count == 1 + mock_update_status.assert_called_with('Ethernet0', status_tbl, SFP_STATUS_INSERTED, 'N/A') assert mock_post_sfp_info.call_count == 1 mock_post_sfp_info.assert_called_with('Ethernet0', task.port_mapping, int_tbl, {}) assert mock_post_dom_info.call_count == 0 @@ -958,12 +1023,12 @@ class MockTable: task.retry_eeprom_set.clear() mock_post_sfp_info.return_value = None - mock_updata_status.reset_mock() + mock_update_status.reset_mock() mock_post_sfp_info.reset_mock() # SFP information is not in the DB, and SFP is present, and SFP has no error, and SFP EEPROM reading succeed task.on_add_logical_port(port_change_event) - assert mock_updata_status.call_count == 1 - mock_updata_status.assert_called_with('Ethernet0', status_tbl, SFP_STATUS_INSERTED, 'N/A') + assert mock_update_status.call_count == 1 + mock_update_status.assert_called_with('Ethernet0', status_tbl, SFP_STATUS_INSERTED, 'N/A') assert mock_post_sfp_info.call_count == 1 mock_post_sfp_info.assert_called_with('Ethernet0', task.port_mapping, int_tbl, {}) assert mock_post_dom_info.call_count == 1 @@ -974,18 +1039,18 @@ class MockTable: assert 'Ethernet0' not in task.retry_eeprom_set mock_get_presence.return_value = False - mock_updata_status.reset_mock() + mock_update_status.reset_mock() # SFP information is not in DB and SFP is not present task.on_add_logical_port(port_change_event) - assert mock_updata_status.call_count == 1 - mock_updata_status.assert_called_with('Ethernet0', status_tbl, SFP_STATUS_REMOVED, 'N/A') + assert mock_update_status.call_count == 1 + mock_update_status.assert_called_with('Ethernet0', status_tbl, SFP_STATUS_REMOVED, 'N/A') task.sfp_error_dict[1] = (str(SfpBase.SFP_ERROR_BIT_BLOCKING | SfpBase.SFP_ERROR_BIT_POWER_BUDGET_EXCEEDED), {}) - mock_updata_status.reset_mock() + mock_update_status.reset_mock() # SFP information is not in DB, and SFP is not present, and SFP is in error status task.on_add_logical_port(port_change_event) - assert mock_updata_status.call_count == 1 - mock_updata_status.assert_called_with( + assert mock_update_status.call_count == 1 + mock_update_status.assert_called_with( 'Ethernet0', status_tbl, task.sfp_error_dict[1][0], 'Blocking EEPROM from being read|Power budget exceeded') def test_sfp_insert_events(self): diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 7543a9677..2c3a7f4af 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -883,7 +883,8 @@ def update_port_transceiver_status_table_hw(logical_port_name, port_mapping, def delete_port_from_status_table_sw(logical_port_name, status_tbl): - status_tbl._del(logical_port_name) + for f in TRANSCEIVER_STATUS_TABLE_SW_FIELDS: + status_tbl.hdel(logical_port_name, f) # Delete port from SFP status table for HW fields which are fetched from EEPROM @@ -894,7 +895,7 @@ def delete_port_from_status_table_hw(logical_port_name, port_mapping, status_tbl if not found: return status_dict = dict(fvs) - for f, _ in status_dict: + for f in status_dict.keys(): if f in TRANSCEIVER_STATUS_TABLE_SW_FIELDS: continue status_tbl.hdel(physical_port_name, f) From 800c82b6af9f82bf24d7657b0a54434f645d26d9 Mon Sep 17 00:00:00 2001 From: Longyin Huang Date: Wed, 26 Oct 2022 20:13:18 -0700 Subject: [PATCH 04/10] Add testcase test_wrapper_get_transceiver_status --- sonic-xcvrd/tests/test_xcvrd.py | 14 ++++++++++++++ sonic-xcvrd/xcvrd/xcvrd.py | 6 +++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index 02d1dccd0..1ebd8d215 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -1172,6 +1172,20 @@ def test_wrapper_get_transceiver_dom_threshold_info(self, mock_sfputil, mock_cha mock_sfputil.get_transceiver_dom_threshold_info_dict = MagicMock(return_value=False) assert not _wrapper_get_transceiver_dom_threshold_info(1) + @patch('xcvrd.xcvrd.platform_chassis') + def test_wrapper_get_transceiver_status(self, mock_chassis): + mock_object = MagicMock() + mock_object.get_transceiver_status= MagicMock(return_value=True) + mock_chassis.get_sfp = MagicMock(return_value=mock_object) + from xcvrd.xcvrd import _wrapper_get_transceiver_status + assert _wrapper_get_transceiver_status(1) + + mock_object.get_transceiver_status = MagicMock(return_value=False) + assert not _wrapper_get_transceiver_status(1) + + mock_chassis.get_sfp = MagicMock(side_effect=NotImplementedError) + assert _wrapper_get_transceiver_status(1) == {} + @patch('xcvrd.xcvrd.platform_chassis') @patch('xcvrd.xcvrd.platform_sfputil') def test_wrapper_get_transceiver_change_event(self, mock_sfputil, mock_chassis): diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 2c3a7f4af..1e21551bb 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -861,12 +861,12 @@ def update_port_transceiver_status_table_hw(logical_port_name, port_mapping, try: if transceiver_status_cache is not None and physical_port in transceiver_status_cache: - # If cache is enabled and dom information is in cache, just read from cache, no need read from EEPROM + # If cache is enabled and status info is in cache, just read from cache, no need read from EEPROM transceiver_status_dict = transceiver_status_cache[physical_port] else: transceiver_status_dict = _wrapper_get_transceiver_status(physical_port) if transceiver_status_cache is not None: - # If cache is enabled, put dom information to cache + # If cache is enabled, put status info to cache transceiver_status_cache[physical_port] = transceiver_status_dict if transceiver_status_dict is not None: beautify_transceiver_status_dict(transceiver_status_dict, physical_port) @@ -2145,7 +2145,7 @@ def on_add_logical_port(self, port_change_event): post_port_dom_threshold_info_to_db(port_change_event.port_name, self.port_mapping, dom_tbl) update_port_transceiver_status_table_hw(port_change_event.port_name, self.port_mapping, - self.xcvr_table_helper.get_status_tbl(port_change_event.asic_id)) + status_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 From c9b079b2671647a40cb70762a4f2d2bf5be59809 Mon Sep 17 00:00:00 2001 From: Longyin Huang Date: Wed, 26 Oct 2022 22:01:58 -0700 Subject: [PATCH 05/10] Simplify post_port_dom_info_to_db --- sonic-xcvrd/xcvrd/xcvrd.py | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 1e21551bb..03714abd1 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -119,6 +119,7 @@ def get_physical_port_name_dict(logical_port_name, port_mapping): physical_port_list = port_mapping.logical_port_name_to_physical_port_list(logical_port_name) if physical_port_list is None: helper_logger.log_error("No physical ports found for logical port '{}'".format(logical_port_name)) + return {} if len(physical_port_list) > 1: ganged_port = True @@ -502,27 +503,13 @@ def post_port_dom_threshold_info_to_db(logical_port_name, port_mapping, table, def post_port_dom_info_to_db(logical_port_name, port_mapping, table, stop_event=threading.Event(), dom_info_cache=None): - ganged_port = False - ganged_member_num = 1 - - physical_port_list = port_mapping.logical_port_name_to_physical_port_list(logical_port_name) - if physical_port_list is None: - helper_logger.log_error("No physical ports found for logical port '{}'".format(logical_port_name)) - return PHYSICAL_PORT_NOT_EXIST - - if len(physical_port_list) > 1: - ganged_port = True - - for physical_port in physical_port_list: + 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 - port_name = get_physical_port_name(logical_port_name, ganged_member_num, ganged_port) - ganged_member_num += 1 - try: if dom_info_cache is not None and physical_port in dom_info_cache: # If cache is enabled and dom information is in cache, just read from cache, no need read from EEPROM @@ -535,7 +522,7 @@ def post_port_dom_info_to_db(logical_port_name, port_mapping, table, stop_event= if dom_info_dict is not None: beautify_dom_info_dict(dom_info_dict, physical_port) fvs = swsscommon.FieldValuePairs([(k, v) for k, v in dom_info_dict.items()]) - table.set(port_name, fvs) + table.set(physical_port_name, fvs) else: return SFP_EEPROM_NOT_READY From 3b10f27aa94264bd9622a3b9a7cdbb44c0bd2de8 Mon Sep 17 00:00:00 2001 From: Longyin Huang Date: Fri, 28 Oct 2022 17:55:14 -0700 Subject: [PATCH 06/10] Use unique info in log --- sonic-xcvrd/xcvrd/xcvrd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 03714abd1..32713cb68 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -863,7 +863,7 @@ def update_port_transceiver_status_table_hw(logical_port_name, port_mapping, return SFP_EEPROM_NOT_READY except NotImplementedError: - helper_logger.log_error("This functionality is currently not implemented for this platform") + helper_logger.log_error("get_transceiver_status is currently not implemented for this platform") sys.exit(NOT_IMPLEMENTED_ERROR) # Delete port from SFP status table From fa6ce8beab5a2e5c7ab0254eeaf77068ae794ddd Mon Sep 17 00:00:00 2001 From: longhuan-cisco <84595962+longhuan-cisco@users.noreply.github.com> Date: Mon, 7 Nov 2022 21:06:23 -0800 Subject: [PATCH 07/10] Add TRANSCEIVER_PM table in STATE_DB for C_CMIS (#3) * Add pm tbl to STATE_DB * Use unique info in post_port_pm_info_to_db log --- sonic-xcvrd/tests/test_xcvrd.py | 52 ++++++++++++-- sonic-xcvrd/xcvrd/xcvrd.py | 119 +++++++++++++++++++++++--------- 2 files changed, 134 insertions(+), 37 deletions(-) diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index 1ebd8d215..e76bbf875 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -80,6 +80,23 @@ 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_pm', MagicMock(return_value={'prefec_ber_avg': '0.0003407240007014899', + 'prefec_ber_min': '0.0006814479342250317', + 'prefec_ber_max': '0.0006833674050752236', + 'uncorr_frames_avg': '0.0', + 'uncorr_frames_min': '0.0', + 'uncorr_frames_max': '0.0', })) + def test_post_port_pm_info_to_db(self): + logical_port_name = "Ethernet0" + port_mapping = PortMapping() + stop_event = threading.Event() + pm_tbl = Table("STATE_DB", TRANSCEIVER_PM_TABLE) + assert pm_tbl.get_size() == 0 + post_port_pm_info_to_db(logical_port_name, port_mapping, pm_tbl, stop_event) + assert pm_tbl.get_size_for_key(logical_port_name) == 6 + @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)) def test_del_port_sfp_dom_info_from_db(self): @@ -87,7 +104,8 @@ def test_del_port_sfp_dom_info_from_db(self): port_mapping = PortMapping() dom_tbl = Table("STATE_DB", TRANSCEIVER_DOM_SENSOR_TABLE) init_tbl = Table("STATE_DB", TRANSCEIVER_INFO_TABLE) - del_port_sfp_dom_info_from_db(logical_port_name, port_mapping, init_tbl, dom_tbl) + pm_tbl = Table("STATE_DB", TRANSCEIVER_PM_TABLE) + del_port_sfp_dom_info_from_db(logical_port_name, port_mapping, init_tbl, dom_tbl, pm_tbl) @patch('xcvrd.xcvrd.get_physical_port_name_dict', MagicMock(return_value={0: 'Ethernet0'})) @patch('xcvrd.xcvrd._wrapper_get_presence', MagicMock(return_value=True)) @@ -716,8 +734,10 @@ def test_DomInfoUpdateTask_task_run_stop(self): @patch('swsscommon.swsscommon.SubscriberStateTable') @patch('swsscommon.swsscommon.Select.select') @patch('xcvrd.xcvrd.update_port_transceiver_status_table_hw') - def test_DomInfoUpdateTask_task_worker(self, mock_update_status_hw, mock_select, mock_sub_table, mock_post_dom_th, - mock_post_dom_info, mock_detect_error): + @patch('xcvrd.xcvrd.post_port_pm_info_to_db') + def test_DomInfoUpdateTask_task_worker(self, mock_post_pm_info, mock_update_status_hw, + mock_select, mock_sub_table, mock_post_dom_th, + mock_post_dom_info, mock_detect_error): mock_selectable = MagicMock() mock_selectable.pop = MagicMock( side_effect=[('Ethernet0', swsscommon.SET_COMMAND, (('index', '1'), )), (None, None, None), (None, None, None)]) @@ -737,12 +757,14 @@ def test_DomInfoUpdateTask_task_worker(self, mock_update_status_hw, mock_select, assert mock_post_dom_th.call_count == 0 assert mock_post_dom_info.call_count == 0 assert mock_update_status_hw.call_count == 0 + assert mock_post_pm_info.call_count == 0 mock_detect_error.return_value = False task.task_stopping_event.wait = MagicMock(side_effect=[False, True]) task.task_worker() assert mock_post_dom_th.call_count == 1 assert mock_post_dom_info.call_count == 1 assert mock_update_status_hw.call_count == 1 + assert mock_post_pm_info.call_count == 1 @patch('xcvrd.xcvrd._wrapper_get_presence', MagicMock(return_value=False)) @patch('xcvrd.xcvrd.XcvrTableHelper') @@ -811,6 +833,7 @@ def test_SfpStateUpdateTask_retry_eeprom_reading(self, mock_update_status_hw, mo task.xcvr_table_helper.get_dom_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_pm_tbl = MagicMock(return_value=mock_table) task.retry_eeprom_reading() assert mock_post_sfp_info.call_count == 0 @@ -866,9 +889,10 @@ def test_SfpStateUpdateTask_mapping_event_from_change_event(self): @patch('xcvrd.xcvrd.update_port_transceiver_status_table_sw') @patch('xcvrd.xcvrd.update_port_transceiver_status_table_hw') @patch('xcvrd.xcvrd.delete_port_from_status_table_hw') - def test_SfpStateUpdateTask_task_worker(self, mock_del_status_hw, mock_update_status_hw, mock_update_status, - mock_post_sfp_info, mock_post_dom_info, mock_post_dom_th, mock_update_media_setting, mock_del_dom, - mock_change_event, mock_mapping_event, mock_os_kill): + @patch('xcvrd.xcvrd.post_port_pm_info_to_db') + def test_SfpStateUpdateTask_task_worker(self, mock_post_pm_info, mock_del_status_hw, mock_update_status_hw, + mock_update_status, mock_post_sfp_info, mock_post_dom_info, mock_post_dom_th, mock_update_media_setting, + mock_del_dom, mock_change_event, mock_mapping_event, mock_os_kill): port_mapping = PortMapping() retry_eeprom_set = set() task = SfpStateUpdateTask(DEFAULT_NAMESPACE, port_mapping, retry_eeprom_set) @@ -922,6 +946,7 @@ def test_SfpStateUpdateTask_task_worker(self, mock_del_status_hw, mock_update_st assert mock_post_dom_info.call_count == 0 assert mock_post_dom_th.call_count == 0 assert mock_update_status_hw.call_count == 0 + assert mock_post_pm_info.call_count == 0 assert mock_update_media_setting.call_count == 0 assert 'Ethernet0' in task.retry_eeprom_set task.retry_eeprom_set.clear() @@ -937,6 +962,7 @@ def test_SfpStateUpdateTask_task_worker(self, mock_del_status_hw, mock_update_st assert mock_post_dom_info.call_count == 1 assert mock_post_dom_th.call_count == 1 assert mock_update_status_hw.call_count == 1 + assert mock_post_pm_info.call_count == 1 assert mock_update_media_setting.call_count == 1 stop_event.is_set = MagicMock(side_effect=[False, True]) @@ -1186,6 +1212,20 @@ def test_wrapper_get_transceiver_status(self, mock_chassis): mock_chassis.get_sfp = MagicMock(side_effect=NotImplementedError) assert _wrapper_get_transceiver_status(1) == {} + @patch('xcvrd.xcvrd.platform_chassis') + def test_wrapper_get_transceiver_pm(self, mock_chassis): + mock_object = MagicMock() + mock_object.get_transceiver_pm = MagicMock(return_value=True) + mock_chassis.get_sfp = MagicMock(return_value=mock_object) + from xcvrd.xcvrd import _wrapper_get_transceiver_pm + assert _wrapper_get_transceiver_pm(1) + + mock_object.get_transceiver_pm = MagicMock(return_value=False) + assert not _wrapper_get_transceiver_pm(1) + + mock_chassis.get_sfp = MagicMock(side_effect=NotImplementedError) + assert _wrapper_get_transceiver_pm(1) == {} + @patch('xcvrd.xcvrd.platform_chassis') @patch('xcvrd.xcvrd.platform_sfputil') def test_wrapper_get_transceiver_change_event(self, mock_sfputil, mock_chassis): diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 32713cb68..c652db623 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -42,6 +42,7 @@ TRANSCEIVER_INFO_TABLE = 'TRANSCEIVER_INFO' TRANSCEIVER_DOM_SENSOR_TABLE = 'TRANSCEIVER_DOM_SENSOR' TRANSCEIVER_STATUS_TABLE = 'TRANSCEIVER_STATUS' +TRANSCEIVER_PM_TABLE = 'TRANSCEIVER_PM' TRANSCEIVER_STATUS_TABLE_SW_FIELDS = ["status", "error"] @@ -200,6 +201,15 @@ def _wrapper_get_transceiver_status(physical_port): return {} +def _wrapper_get_transceiver_pm(physical_port): + if platform_chassis is not None: + try: + return platform_chassis.get_sfp(physical_port).get_transceiver_pm() + except NotImplementedError: + pass + return {} + + # Soak SFP insert event until management init completes def _wrapper_soak_sfp_insert_event(sfp_insert_events, port_dict): for key, value in list(port_dict.items()): @@ -299,6 +309,13 @@ def beautify_transceiver_status_dict(transceiver_status_dict, physical_port): continue transceiver_status_dict[k] = str(v) + +def beautify_pm_info_dict(pm_info_dict, physical_port): + for k, v in pm_info_dict.items(): + if type(v) is str: + continue + pm_info_dict[k] = str(v) + # Update port sfp info in db @@ -530,6 +547,40 @@ def post_port_dom_info_to_db(logical_port_name, port_mapping, table, stop_event= helper_logger.log_error("This functionality is currently not implemented for this platform") sys.exit(NOT_IMPLEMENTED_ERROR) +# Update port pm info in db + + +def post_port_pm_info_to_db(logical_port_name, port_mapping, table, stop_event=threading.Event(), pm_info_cache=None): + 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: + if pm_info_cache is not None and physical_port in pm_info_cache: + # If cache is enabled and pm info is in cache, just read from cache, no need read from EEPROM + pm_info_dict = pm_info_cache[physical_port] + else: + pm_info_dict = _wrapper_get_transceiver_pm(physical_port) + if pm_info_cache is not None: + # If cache is enabled, put dom information to cache + pm_info_cache[physical_port] = pm_info_dict + if pm_info_dict is not None: + # ignore if empty + if not pm_info_dict: + continue + beautify_pm_info_dict(pm_info_dict, physical_port) + fvs = swsscommon.FieldValuePairs([(k, v) for k, v in pm_info_dict.items()]) + table.set(physical_port_name, fvs) + else: + return SFP_EEPROM_NOT_READY + + except NotImplementedError: + helper_logger.log_error("get_transceiver_pm is currently not implemented for this platform") + sys.exit(NOT_IMPLEMENTED_ERROR) + # Update port dom/sfp info in db @@ -557,6 +608,7 @@ def post_port_sfp_dom_info_to_db(is_warm_start, port_mapping, xcvr_table_helper, port_mapping, xcvr_table_helper.get_status_tbl(asic_index), stop_event) + post_port_pm_info_to_db(logical_port_name, port_mapping, xcvr_table_helper.get_pm_tbl(asic_index), stop_event) # Do not notify media settings during warm reboot to avoid dataplane traffic impact if is_warm_start == False: @@ -570,27 +622,15 @@ def post_port_sfp_dom_info_to_db(is_warm_start, port_mapping, xcvr_table_helper, # Delete port dom/sfp info from db -def del_port_sfp_dom_info_from_db(logical_port_name, port_mapping, int_tbl, dom_tbl): - ganged_port = False - ganged_member_num = 1 - - physical_port_list = port_mapping.logical_port_name_to_physical_port_list(logical_port_name) - if physical_port_list is None: - helper_logger.log_error("No physical ports found for logical port '{}'".format(logical_port_name)) - return PHYSICAL_PORT_NOT_EXIST - - if len(physical_port_list) > 1: - ganged_port = True - - for physical_port in physical_port_list: - port_name = get_physical_port_name(logical_port_name, ganged_member_num, ganged_port) - ganged_member_num += 1 - +def del_port_sfp_dom_info_from_db(logical_port_name, port_mapping, int_tbl, dom_tbl, pm_tbl): + for physical_port_name in get_physical_port_name_dict(logical_port_name, port_mapping).values(): try: - if int_tbl is not None: - int_tbl._del(port_name) - if dom_tbl is not None: - dom_tbl._del(port_name) + if int_tbl: + int_tbl._del(physical_port_name) + if dom_tbl: + dom_tbl._del(physical_port_name) + if pm_tbl: + pm_tbl._del(physical_port_name) except NotImplementedError: helper_logger.log_error("This functionality is currently not implemented for this platform") @@ -1638,6 +1678,7 @@ def task_worker(self): dom_info_cache = {} dom_th_info_cache = {} transceiver_status_cache = {} + pm_info_cache = {} sel, asic_context = port_mapping.subscribe_port_config_change(self.namespaces) # Start loop to update dom info in DB periodically @@ -1646,6 +1687,7 @@ def task_worker(self): dom_info_cache.clear() dom_th_info_cache.clear() transceiver_status_cache.clear() + pm_info_cache.clear() # Handle port change event from main thread port_mapping.handle_port_config_change(sel, asic_context, self.task_stopping_event, self.port_mapping, helper_logger, self.on_port_config_change) @@ -1665,6 +1707,7 @@ def task_worker(self): self.xcvr_table_helper.get_status_tbl(asic_index), self.task_stopping_event, transceiver_status_cache=transceiver_status_cache) + post_port_pm_info_to_db(logical_port_name, self.port_mapping, self.xcvr_table_helper.get_pm_tbl(asic_index), self.task_stopping_event, pm_info_cache=pm_info_cache) helper_logger.log_info("Stop DOM monitoring loop") @@ -1696,7 +1739,8 @@ def on_remove_logical_port(self, port_change_event): 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)) + self.xcvr_table_helper.get_dom_tbl(port_change_event.asic_id), + self.xcvr_table_helper.get_pm_tbl(port_change_event.asic_id)) 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)) @@ -1922,6 +1966,7 @@ def task_worker(self, stopping_event, sfp_error_event): post_port_dom_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_tbl(asic_index)) post_port_dom_threshold_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_tbl(asic_index)) update_port_transceiver_status_table_hw(logical_port, self.port_mapping, self.xcvr_table_helper.get_status_tbl(asic_index)) + post_port_pm_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_pm_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: @@ -1929,7 +1974,10 @@ def task_worker(self, stopping_event, sfp_error_event): update_port_transceiver_status_table_sw( logical_port, self.xcvr_table_helper.get_status_tbl(asic_index), sfp_status_helper.SFP_STATUS_REMOVED) helper_logger.log_info("receive plug out and pdate port sfp status table.") - del_port_sfp_dom_info_from_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_intf_tbl(asic_index), self.xcvr_table_helper.get_dom_tbl(asic_index)) + del_port_sfp_dom_info_from_db(logical_port, self.port_mapping, + self.xcvr_table_helper.get_intf_tbl(asic_index), + self.xcvr_table_helper.get_dom_tbl(asic_index), + self.xcvr_table_helper.get_pm_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: @@ -1952,13 +2000,11 @@ def task_worker(self, stopping_event, sfp_error_event): # In this case EEPROM is not accessible. The DOM info will be removed since it can be out-of-date. # The interface info remains in the DB since it is static. if sfp_status_helper.is_error_block_eeprom_reading(error_bits): - del_port_sfp_dom_info_from_db(logical_port, - self.port_mapping, + del_port_sfp_dom_info_from_db(logical_port, self.port_mapping, None, - self.xcvr_table_helper.get_dom_tbl(asic_index)) - delete_port_from_status_table_hw(logical_port, - self.port_mapping, - self.xcvr_table_helper.get_status_tbl(asic_index)) + self.xcvr_table_helper.get_dom_tbl(asic_index), + self.xcvr_table_helper.get_pm_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(value)) @@ -2032,7 +2078,8 @@ def on_remove_logical_port(self, port_change_event): del_port_sfp_dom_info_from_db(port_change_event.port_name, self.port_mapping, 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_tbl(port_change_event.asic_id), + self.xcvr_table_helper.get_pm_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, @@ -2067,6 +2114,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_tbl = self.xcvr_table_helper.get_dom_tbl(port_change_event.asic_id) + pm_tbl = self.xcvr_table_helper.get_pm_tbl(port_change_event.asic_id) physical_port_list = self.port_mapping.logical_port_name_to_physical_port_list(port_change_event.port_name) # Try to find a logical port with same physical index in DB @@ -2133,6 +2181,7 @@ def on_add_logical_port(self, port_change_event): update_port_transceiver_status_table_hw(port_change_event.port_name, self.port_mapping, status_tbl) + post_port_pm_info_to_db(port_change_event.port_name, self.port_mapping, pm_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 @@ -2163,6 +2212,7 @@ def retry_eeprom_reading(self): post_port_dom_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_tbl(asic_index)) post_port_dom_threshold_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_dom_tbl(asic_index)) update_port_transceiver_status_table_hw(logical_port, self.port_mapping, self.xcvr_table_helper.get_status_tbl(asic_index)) + post_port_pm_info_to_db(logical_port, self.port_mapping, self.xcvr_table_helper.get_pm_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) @@ -2311,7 +2361,10 @@ def deinit(self): helper_logger.log_warning("Got invalid asic index for {}, ignored".format(logical_port_name)) continue - del_port_sfp_dom_info_from_db(logical_port_name, port_mapping_data, self.xcvr_table_helper.get_intf_tbl(asic_index), self.xcvr_table_helper.get_dom_tbl(asic_index)) + del_port_sfp_dom_info_from_db(logical_port_name, port_mapping_data, + self.xcvr_table_helper.get_intf_tbl(asic_index), + self.xcvr_table_helper.get_dom_tbl(asic_index), + self.xcvr_table_helper.get_pm_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)) @@ -2370,7 +2423,7 @@ def run(self): class XcvrTableHelper: def __init__(self, namespaces): self.int_tbl, self.dom_tbl, self.status_tbl, self.app_port_tbl, \ - self.cfg_port_tbl, self.state_port_tbl = {}, {}, {}, {}, {}, {} + self.cfg_port_tbl, self.state_port_tbl, self.pm_tbl = {}, {}, {}, {}, {}, {}, {} self.state_db = {} self.cfg_db = {} for namespace in namespaces: @@ -2379,6 +2432,7 @@ def __init__(self, namespaces): self.int_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_INFO_TABLE) self.dom_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_DOM_SENSOR_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.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) @@ -2394,6 +2448,9 @@ def get_dom_tbl(self, asic_id): def get_status_tbl(self, asic_id): return self.status_tbl[asic_id] + def get_pm_tbl(self, asic_id): + return self.pm_tbl[asic_id] + def get_app_port_tbl(self, asic_id): return self.app_port_tbl[asic_id] From 71efe734212fb1640e655fa24d59f90e9c8852e2 Mon Sep 17 00:00:00 2001 From: Longyin Huang Date: Tue, 8 Nov 2022 16:51:35 -0800 Subject: [PATCH 08/10] Add line break --- sonic-xcvrd/xcvrd/xcvrd.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index c652db623..ad0543526 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -2000,7 +2000,8 @@ def task_worker(self, stopping_event, sfp_error_event): # In this case EEPROM is not accessible. The DOM info will be removed since it can be out-of-date. # The interface info remains in the DB since it is static. if sfp_status_helper.is_error_block_eeprom_reading(error_bits): - del_port_sfp_dom_info_from_db(logical_port, self.port_mapping, + del_port_sfp_dom_info_from_db(logical_port, + self.port_mapping, None, self.xcvr_table_helper.get_dom_tbl(asic_index), self.xcvr_table_helper.get_pm_tbl(asic_index)) From d1f428936a8af13c543ba376c71892fe2d1ef6eb Mon Sep 17 00:00:00 2001 From: Longyin Huang Date: Wed, 23 Nov 2022 02:23:29 -0800 Subject: [PATCH 09/10] Remove unused exception handling and add skip for transceiver_status --- sonic-xcvrd/xcvrd/xcvrd.py | 75 +++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index ad0543526..7a755cce2 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -558,28 +558,23 @@ def post_port_pm_info_to_db(logical_port_name, port_mapping, table, stop_event=t if not _wrapper_get_presence(physical_port): continue - try: - if pm_info_cache is not None and physical_port in pm_info_cache: - # If cache is enabled and pm info is in cache, just read from cache, no need read from EEPROM - pm_info_dict = pm_info_cache[physical_port] - else: - pm_info_dict = _wrapper_get_transceiver_pm(physical_port) - if pm_info_cache is not None: - # If cache is enabled, put dom information to cache - pm_info_cache[physical_port] = pm_info_dict - if pm_info_dict is not None: - # ignore if empty - if not pm_info_dict: - continue - beautify_pm_info_dict(pm_info_dict, physical_port) - fvs = swsscommon.FieldValuePairs([(k, v) for k, v in pm_info_dict.items()]) - table.set(physical_port_name, fvs) - else: - return SFP_EEPROM_NOT_READY - - except NotImplementedError: - helper_logger.log_error("get_transceiver_pm is currently not implemented for this platform") - sys.exit(NOT_IMPLEMENTED_ERROR) + if pm_info_cache is not None and physical_port in pm_info_cache: + # If cache is enabled and pm info is in cache, just read from cache, no need read from EEPROM + pm_info_dict = pm_info_cache[physical_port] + else: + pm_info_dict = _wrapper_get_transceiver_pm(physical_port) + if pm_info_cache is not None: + # If cache is enabled, put dom information to cache + pm_info_cache[physical_port] = pm_info_dict + if pm_info_dict is not None: + # Skip if empty (i.e. get_transceiver_pm API is not applicable for this xcvr) + if not pm_info_dict: + continue + beautify_pm_info_dict(pm_info_dict, physical_port) + fvs = swsscommon.FieldValuePairs([(k, v) for k, v in pm_info_dict.items()]) + table.set(physical_port_name, fvs) + else: + return SFP_EEPROM_NOT_READY # Update port dom/sfp info in db @@ -886,25 +881,23 @@ def update_port_transceiver_status_table_hw(logical_port_name, port_mapping, if not _wrapper_get_presence(physical_port): continue - try: - if transceiver_status_cache is not None and physical_port in transceiver_status_cache: - # If cache is enabled and status info is in cache, just read from cache, no need read from EEPROM - transceiver_status_dict = transceiver_status_cache[physical_port] - else: - transceiver_status_dict = _wrapper_get_transceiver_status(physical_port) - if transceiver_status_cache is not None: - # If cache is enabled, put status info to cache - transceiver_status_cache[physical_port] = transceiver_status_dict - if transceiver_status_dict is not None: - beautify_transceiver_status_dict(transceiver_status_dict, physical_port) - fvs = swsscommon.FieldValuePairs([(k, v) for k, v in transceiver_status_dict.items()]) - table.set(physical_port_name, fvs) - else: - return SFP_EEPROM_NOT_READY - - except NotImplementedError: - helper_logger.log_error("get_transceiver_status is currently not implemented for this platform") - sys.exit(NOT_IMPLEMENTED_ERROR) + if transceiver_status_cache is not None and physical_port in transceiver_status_cache: + # If cache is enabled and status info is in cache, just read from cache, no need read from EEPROM + transceiver_status_dict = transceiver_status_cache[physical_port] + else: + transceiver_status_dict = _wrapper_get_transceiver_status(physical_port) + if transceiver_status_cache is not None: + # If cache is enabled, put status info to cache + transceiver_status_cache[physical_port] = transceiver_status_dict + if transceiver_status_dict is not None: + # Skip if empty (i.e. get_transceiver_status API is not applicable for this xcvr) + if not transceiver_status_dict: + continue + beautify_transceiver_status_dict(transceiver_status_dict, physical_port) + fvs = swsscommon.FieldValuePairs([(k, v) for k, v in transceiver_status_dict.items()]) + table.set(physical_port_name, fvs) + else: + return SFP_EEPROM_NOT_READY # Delete port from SFP status table From 07199358876bcf5f022726e0414db72e10bdbe64 Mon Sep 17 00:00:00 2001 From: Longyin Huang Date: Tue, 6 Dec 2022 22:37:22 +0000 Subject: [PATCH 10/10] Fixed mismatch in multiple assignment --- sonic-xcvrd/xcvrd/xcvrd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 8d021839e..d2bf44d73 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -2394,7 +2394,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.state_db = {} self.cfg_db = {} for namespace in namespaces: