From 9c10c9d459503b0399559bf3162657d701ac7c62 Mon Sep 17 00:00:00 2001 From: Yair Raviv Date: Sun, 25 Jan 2026 11:19:39 +0200 Subject: [PATCH 1/5] Fast reboot | Added multi-ASIC support Signed-off-by: Yair Raviv --- sonic-xcvrd/tests/test_xcvrd.py | 64 +++++++++++++++++++++ sonic-xcvrd/xcvrd/cmis/cmis_manager_task.py | 16 ++---- sonic-xcvrd/xcvrd/xcvrd.py | 41 +++++++------ sonic-xcvrd/xcvrd/xcvrd_utilities/common.py | 8 ++- 4 files changed, 100 insertions(+), 29 deletions(-) diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index 9566612f0..b8e238c86 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -3141,6 +3141,29 @@ def test_CmisManagerTask_update_port_transceiver_status_table_sw_cmis_state(self task.update_port_transceiver_status_table_sw_cmis_state("Ethernet0", CMIS_STATE_INSERTED) assert mock_get_status_tbl.set.call_count == 1 + @patch('xcvrd.xcvrd_utilities.common.is_fast_reboot_enabled', MagicMock(return_value=True)) + @patch('xcvrd.xcvrd_utilities.common.get_namespace_from_asic_id', MagicMock(return_value='asic1')) + def test_CmisManagerTask_is_fast_reboot_enabled_for_lport(self): + port_mapping = PortMapping() + stop_event = threading.Event() + task = CmisManagerTask(DEFAULT_NAMESPACE, port_mapping, stop_event, platform_chassis=MagicMock()) + task.port_dict['Ethernet0'] = {'asic_id': 1} + + assert task.is_fast_reboot_enabled_for_lport('Ethernet0') is True + common.get_namespace_from_asic_id.assert_called_with(1) + common.is_fast_reboot_enabled.assert_called_with('asic1') + + @patch('xcvrd.xcvrd_utilities.common.is_fast_reboot_enabled', MagicMock(return_value=False)) + def test_CmisManagerTask_is_fast_reboot_enabled_for_lport_default_namespace(self): + port_mapping = PortMapping() + stop_event = threading.Event() + task = CmisManagerTask(DEFAULT_NAMESPACE, port_mapping, stop_event, platform_chassis=MagicMock()) + # Ethernet999 not in port_dict -> asic_id -1 -> namespace '' + with patch.object(common, 'get_namespace_from_asic_id', MagicMock()) as mock_get_ns: + assert task.is_fast_reboot_enabled_for_lport('Ethernet999') is False + mock_get_ns.assert_not_called() + common.is_fast_reboot_enabled.assert_called_with('') + @patch('xcvrd.xcvrd._wrapper_get_sfp_type', MagicMock(return_value='QSFP_DD')) def test_CmisManagerTask_handle_port_change_event(self): port_mapping = PortMapping() @@ -5560,6 +5583,47 @@ def test_SfpStateUpdateTask_mapping_event_from_change_event(self): port_dict = {1, SFP_STATUS_INSERTED} assert task._mapping_event_from_change_event(True, port_dict) == NORMAL_EVENT + @patch('xcvrd.xcvrd_utilities.common.get_namespace_from_asic_id', MagicMock(return_value='asic2')) + @patch('xcvrd.xcvrd_utilities.common.is_syncd_warm_restore_complete', MagicMock(return_value=False)) + @patch('xcvrd.xcvrd_utilities.common.is_fast_reboot_enabled', MagicMock(return_value=True)) + def test_SfpStateUpdateTask_is_warm_fast_reboot_for_lport(self): + port_mapping = PortMapping() + port_mapping.logical_to_asic = {'Ethernet0': 2} + mock_sfp_obj_dict = MagicMock() + stop_event = threading.Event() + sfp_error_event = threading.Event() + task = SfpStateUpdateTask(DEFAULT_NAMESPACE, port_mapping, mock_sfp_obj_dict, stop_event, sfp_error_event) + + assert task.is_warm_fast_reboot_for_lport('Ethernet0') is True + common.get_namespace_from_asic_id.assert_called_with(2) + common.is_syncd_warm_restore_complete.assert_called_with('asic2') + common.is_fast_reboot_enabled.assert_called_with('asic2') + + def test_SfpStateUpdateTask_is_warm_fast_reboot_for_lport_invalid_asic(self): + port_mapping = PortMapping() + mock_sfp_obj_dict = MagicMock() + stop_event = threading.Event() + sfp_error_event = threading.Event() + task = SfpStateUpdateTask(DEFAULT_NAMESPACE, port_mapping, mock_sfp_obj_dict, stop_event, sfp_error_event) + task.port_mapping.get_asic_id_for_logical_port = MagicMock(return_value=None) + + assert task.is_warm_fast_reboot_for_lport('Ethernet0') is False + + def test_SfpStateUpdateTask_should_notify_media_settings(self): + port_mapping = PortMapping() + mock_sfp_obj_dict = MagicMock() + stop_event = threading.Event() + sfp_error_event = threading.Event() + task = SfpStateUpdateTask(DEFAULT_NAMESPACE, port_mapping, mock_sfp_obj_dict, stop_event, sfp_error_event) + + task.is_warm_fast_reboot_for_lport = MagicMock(return_value=True) + assert task.should_notify_media_settings('Ethernet0') is False + task.is_warm_fast_reboot_for_lport.assert_called_with('Ethernet0') + + task.is_warm_fast_reboot_for_lport = MagicMock(return_value=False) + assert task.should_notify_media_settings('Ethernet0') is True + task.is_warm_fast_reboot_for_lport.assert_called_with('Ethernet0') + @patch('time.sleep', MagicMock()) @patch('xcvrd.xcvrd.XcvrTableHelper', MagicMock()) @patch('xcvrd.xcvrd._wrapper_soak_sfp_insert_event', MagicMock()) diff --git a/sonic-xcvrd/xcvrd/cmis/cmis_manager_task.py b/sonic-xcvrd/xcvrd/cmis/cmis_manager_task.py index 373fc2fbd..1eb80cd45 100644 --- a/sonic-xcvrd/xcvrd/cmis/cmis_manager_task.py +++ b/sonic-xcvrd/xcvrd/cmis/cmis_manager_task.py @@ -60,7 +60,6 @@ def __init__(self, namespaces, port_mapping, main_thread_stop_event, skip_cmis_m self.namespaces = namespaces self.platform_chassis = platform_chassis self.xcvr_table_helper = XcvrTableHelper(self.namespaces) - self._is_fast_reboot_enabled = None # Cache of gearbox line lanes dict, refreshed once per task_worker iteration. self._gearbox_lanes_dict = None @@ -73,15 +72,14 @@ def log_notice(self, message): def log_error(self, message): helper_logger.log_error(message) - def is_fast_reboot_enabled(self): - """Check if fast reboot is enabled, caching the result""" - if self._is_fast_reboot_enabled is None: - self._is_fast_reboot_enabled = common.is_fast_reboot_enabled() - return self._is_fast_reboot_enabled - def get_asic_id(self, lport): return self.port_dict.get(lport, {}).get("asic_id", -1) + def is_fast_reboot_enabled_for_lport(self, lport): + asic_id = self.get_asic_id(lport) + namespace = common.get_namespace_from_asic_id(asic_id) if asic_id >= 0 else '' + return bool(common.is_fast_reboot_enabled(namespace)) + def update_port_transceiver_status_table_sw_cmis_state(self, lport, cmis_state_to_set): status_table = self.xcvr_table_helper.get_status_sw_tbl(self.get_asic_id(lport)) if status_table is None: @@ -862,7 +860,7 @@ def handle_cmis_inserted_state(self, lport): speed = port_info.get('speed') subport = port_info.get('subport') appl = port_info.get('appl', 0) - is_fast_reboot = self.is_fast_reboot_enabled() + is_fast_reboot = self.is_fast_reboot_enabled_for_lport(lport) self.port_dict[lport]['appl'] = common.get_cmis_application_desired(api, host_lane_count, speed) if self.port_dict[lport]['appl'] is None: @@ -1058,7 +1056,6 @@ def process_cmis_state_machine(self, lport): subport = port_info.get('subport') pport = port_info.get('pport') sfp = port_info.get('sfp') - is_fast_reboot = self.is_fast_reboot_enabled() # CMIS expiration and retries # @@ -1367,4 +1364,3 @@ def join(self): threading.Thread.join(self) if self.exc: raise self.exc - diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index a9051b1e4..62a616bf4 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -281,6 +281,16 @@ def __init__(self, namespaces, port_mapping, sfp_obj_dict, main_thread_stop_even self.dom_db_utils = DOMDBUtils(sfp_obj_dict, self.port_mapping, self.xcvr_table_helper, self.task_stopping_event, self.logger) self.vdm_db_utils = VDMDBUtils(sfp_obj_dict, self.port_mapping, self.xcvr_table_helper, self.task_stopping_event, self.logger) + def is_warm_fast_reboot_for_lport(self, logical_port): + asic_index = self.port_mapping.get_asic_id_for_logical_port(logical_port) + if asic_index is None: + return False + namespace = common.get_namespace_from_asic_id(asic_index) + return bool(common.is_syncd_warm_restore_complete(namespace) or common.is_fast_reboot_enabled(namespace)) + + def should_notify_media_settings(self, logical_port): + return not self.is_warm_fast_reboot_for_lport(logical_port) + def _mapping_event_from_change_event(self, status, port_dict): """ mapping from what get_transceiver_change_event returns to event defined in the state machine @@ -311,10 +321,10 @@ def _post_port_sfp_info_and_dom_thr_to_db_once(self, port_mapping, xcvr_table_he transceiver_dict = {} retry_eeprom_set = set() - # Pre-fetch warm start status for all namespaces/ASICs - warm_start_status = {} + # Pre-fetch warm/fast reboot status for all namespaces/ASICs + warm_fast_reboot_status = {} for namespace in self.namespaces: - warm_start_status[namespace] = common.is_syncd_warm_restore_complete(namespace) + warm_fast_reboot_status[namespace] = common.is_syncd_warm_restore_complete(namespace) or common.is_fast_reboot_enabled(namespace) # Post all the current interface sfp/dom threshold info to STATE_DB logical_port_list = port_mapping.logical_port_list @@ -328,13 +338,13 @@ def _post_port_sfp_info_and_dom_thr_to_db_once(self, port_mapping, xcvr_table_he helper_logger.log_warning("Got invalid asic index for {}, ignored while posting SFP info during boot-up".format(logical_port_name)) continue - # Get warm start status for this ASIC's namespace + # Get warm/fast reboot status for this ASIC's namespace namespace = common.get_namespace_from_asic_id(asic_index) - is_warm_start = warm_start_status.get(namespace, False) + is_warm_fast_reboot = warm_fast_reboot_status.get(namespace, False) 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: - if is_warm_start == False: + if is_warm_fast_reboot == False: media_settings_parser.notify_media_setting(logical_port_name, transceiver_dict, xcvr_table_helper, port_mapping) else: retry_eeprom_set.add(logical_port_name) @@ -568,7 +578,8 @@ def task_worker(self, stopping_event, sfp_error_event): self.dom_db_utils.post_port_dom_thresholds_to_db(logical_port) self.vdm_db_utils.post_port_vdm_thresholds_to_db(logical_port) - media_settings_parser.notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper, self.port_mapping) + if self.should_notify_media_settings(logical_port): + media_settings_parser.notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper, self.port_mapping) transceiver_dict.clear() elif value == sfp_status_helper.SFP_STATUS_REMOVED: # Remove the SFP API object for this physical port @@ -828,7 +839,8 @@ def on_add_logical_port(self, port_change_event): else: self.dom_db_utils.post_port_dom_thresholds_to_db(port_change_event.port_name) self.vdm_db_utils.post_port_vdm_thresholds_to_db(port_change_event.port_name) - media_settings_parser.notify_media_setting(port_change_event.port_name, transceiver_dict, self.xcvr_table_helper, self.port_mapping) + if self.should_notify_media_settings(port_change_event.port_name): + media_settings_parser.notify_media_setting(port_change_event.port_name, transceiver_dict, self.xcvr_table_helper, self.port_mapping) else: status = sfp_status_helper.SFP_STATUS_REMOVED if not status else status common.update_port_transceiver_status_table_sw(port_change_event.port_name, status_sw_tbl, status, error_description) @@ -856,7 +868,8 @@ def retry_eeprom_reading(self): self.dom_db_utils.post_port_dom_thresholds_to_db(logical_port) self.vdm_db_utils.post_port_vdm_thresholds_to_db(logical_port) - media_settings_parser.notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper, self.port_mapping) + if self.should_notify_media_settings(logical_port): + media_settings_parser.notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper, self.port_mapping) transceiver_dict.clear() retry_success_set.add(logical_port) # Update retry EEPROM set @@ -1052,11 +1065,8 @@ def init(self): # Initialize xcvr table helper self.xcvr_table_helper = XcvrTableHelper(self.namespaces) - if common.is_fast_reboot_enabled(): - self.log_info("Skip loading media_settings.json and optics_si_settings.json in case of fast-reboot") - else: - media_settings_parser.load_media_settings() - optics_si_parser.load_optics_si_settings() + media_settings_parser.load_media_settings() + optics_si_parser.load_optics_si_settings() # Make sure this daemon started after all port configured self.log_notice("XCVRD INIT: Wait for port config is done") @@ -1082,10 +1092,9 @@ def deinit(self): self.log_info("Start daemon deinit...") # Pre-fetch warm/fast reboot status for all namespaces/ASICs - is_fast_reboot = common.is_fast_reboot_enabled() warm_fast_reboot_status = {} for namespace in self.namespaces: - warm_fast_reboot_status[namespace] = common.is_syncd_warm_restore_complete(namespace) or is_fast_reboot + warm_fast_reboot_status[namespace] = common.is_syncd_warm_restore_complete(namespace) or common.is_fast_reboot_enabled(namespace) # Delete all the information from DB and then exit port_mapping_data = port_event_helper.get_port_mapping(self.namespaces) diff --git a/sonic-xcvrd/xcvrd/xcvrd_utilities/common.py b/sonic-xcvrd/xcvrd/xcvrd_utilities/common.py index 31f1c28b2..c5e98aab9 100644 --- a/sonic-xcvrd/xcvrd/xcvrd_utilities/common.py +++ b/sonic-xcvrd/xcvrd/xcvrd_utilities/common.py @@ -145,10 +145,12 @@ def _wrapper_get_presence(physical_port): pass return False -def is_fast_reboot_enabled(): +def is_fast_reboot_enabled(namespace=''): """Check if fast reboot is enabled""" - fastboot_enabled = subprocess.check_output('sonic-db-cli STATE_DB hget "FAST_RESTART_ENABLE_TABLE|system" enable', shell=True, universal_newlines=True) - return "true" in fastboot_enabled + state_db = daemon_base.db_connect("STATE_DB", namespace=namespace) + fastboot_enabled = state_db.hget("FAST_RESTART_ENABLE_TABLE|system", "enable") + if isinstance(fastboot_enabled, str): + return fastboot_enabled.strip().lower() == "true" def is_warm_reboot_enabled(): """Check if warm reboot is enabled""" From 51ed81585d0808fd9c442f7b0a8a5202f41405d7 Mon Sep 17 00:00:00 2001 From: Yair Raviv Date: Wed, 29 Apr 2026 17:43:16 +0300 Subject: [PATCH 2/5] Check fast/warm reboot per ASIC instead of for each port Signed-off-by: Yair Raviv --- sonic-xcvrd/tests/test_xcvrd.py | 17 +++++++++++------ sonic-xcvrd/xcvrd/cmis/cmis_manager_task.py | 9 ++++++++- sonic-xcvrd/xcvrd/xcvrd.py | 17 ++++++++++------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index b8e238c86..00581be4d 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -3145,13 +3145,14 @@ def test_CmisManagerTask_update_port_transceiver_status_table_sw_cmis_state(self @patch('xcvrd.xcvrd_utilities.common.get_namespace_from_asic_id', MagicMock(return_value='asic1')) def test_CmisManagerTask_is_fast_reboot_enabled_for_lport(self): port_mapping = PortMapping() + port_mapping.logical_to_asic = {'Ethernet0': 1} stop_event = threading.Event() - task = CmisManagerTask(DEFAULT_NAMESPACE, port_mapping, stop_event, platform_chassis=MagicMock()) - task.port_dict['Ethernet0'] = {'asic_id': 1} + task = CmisManagerTask(['asic1'], port_mapping, stop_event, platform_chassis=MagicMock()) + common.is_fast_reboot_enabled.reset_mock() assert task.is_fast_reboot_enabled_for_lport('Ethernet0') is True common.get_namespace_from_asic_id.assert_called_with(1) - common.is_fast_reboot_enabled.assert_called_with('asic1') + common.is_fast_reboot_enabled.assert_not_called() @patch('xcvrd.xcvrd_utilities.common.is_fast_reboot_enabled', MagicMock(return_value=False)) def test_CmisManagerTask_is_fast_reboot_enabled_for_lport_default_namespace(self): @@ -5592,12 +5593,16 @@ def test_SfpStateUpdateTask_is_warm_fast_reboot_for_lport(self): mock_sfp_obj_dict = MagicMock() stop_event = threading.Event() sfp_error_event = threading.Event() - task = SfpStateUpdateTask(DEFAULT_NAMESPACE, port_mapping, mock_sfp_obj_dict, stop_event, sfp_error_event) + task = SfpStateUpdateTask(['asic2'], port_mapping, mock_sfp_obj_dict, stop_event, sfp_error_event) + common.is_syncd_warm_restore_complete.assert_called_once_with('asic2') + common.is_fast_reboot_enabled.assert_called_once_with('asic2') + common.is_syncd_warm_restore_complete.reset_mock() + common.is_fast_reboot_enabled.reset_mock() assert task.is_warm_fast_reboot_for_lport('Ethernet0') is True common.get_namespace_from_asic_id.assert_called_with(2) - common.is_syncd_warm_restore_complete.assert_called_with('asic2') - common.is_fast_reboot_enabled.assert_called_with('asic2') + common.is_syncd_warm_restore_complete.assert_not_called() + common.is_fast_reboot_enabled.assert_not_called() def test_SfpStateUpdateTask_is_warm_fast_reboot_for_lport_invalid_asic(self): port_mapping = PortMapping() diff --git a/sonic-xcvrd/xcvrd/cmis/cmis_manager_task.py b/sonic-xcvrd/xcvrd/cmis/cmis_manager_task.py index 1eb80cd45..4fb3da595 100644 --- a/sonic-xcvrd/xcvrd/cmis/cmis_manager_task.py +++ b/sonic-xcvrd/xcvrd/cmis/cmis_manager_task.py @@ -62,6 +62,13 @@ def __init__(self, namespaces, port_mapping, main_thread_stop_event, skip_cmis_m self.xcvr_table_helper = XcvrTableHelper(self.namespaces) # Cache of gearbox line lanes dict, refreshed once per task_worker iteration. self._gearbox_lanes_dict = None + self.fast_reboot_status = self.initialize_fast_reboot_status() + + def initialize_fast_reboot_status(self): + fast_reboot_status = {} + for namespace in self.namespaces: + fast_reboot_status[namespace] = bool(common.is_fast_reboot_enabled(namespace)) + return fast_reboot_status def log_debug(self, message): helper_logger.log_debug(message) @@ -78,7 +85,7 @@ def get_asic_id(self, lport): def is_fast_reboot_enabled_for_lport(self, lport): asic_id = self.get_asic_id(lport) namespace = common.get_namespace_from_asic_id(asic_id) if asic_id >= 0 else '' - return bool(common.is_fast_reboot_enabled(namespace)) + return self.fast_reboot_status.get(namespace, False) def update_port_transceiver_status_table_sw_cmis_state(self, lport, cmis_state_to_set): status_table = self.xcvr_table_helper.get_status_sw_tbl(self.get_asic_id(lport)) diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 62a616bf4..26cfdb865 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -278,15 +278,23 @@ def __init__(self, namespaces, port_mapping, sfp_obj_dict, main_thread_stop_even self.sfp_obj_dict = sfp_obj_dict self.logger = syslogger.SysLogger(SYSLOG_IDENTIFIER_SFPSTATEUPDATETASK, enable_runtime_config=True) self.xcvr_table_helper = XcvrTableHelper(self.namespaces) + self.warm_fast_reboot_status = self.initialize_warm_fast_reboot_status() self.dom_db_utils = DOMDBUtils(sfp_obj_dict, self.port_mapping, self.xcvr_table_helper, self.task_stopping_event, self.logger) self.vdm_db_utils = VDMDBUtils(sfp_obj_dict, self.port_mapping, self.xcvr_table_helper, self.task_stopping_event, self.logger) + def initialize_warm_fast_reboot_status(self): + warm_fast_reboot_status = {} + for namespace in self.namespaces: + warm_fast_reboot_status[namespace] = bool(common.is_syncd_warm_restore_complete(namespace) or + common.is_fast_reboot_enabled(namespace)) + return warm_fast_reboot_status + def is_warm_fast_reboot_for_lport(self, logical_port): asic_index = self.port_mapping.get_asic_id_for_logical_port(logical_port) if asic_index is None: return False namespace = common.get_namespace_from_asic_id(asic_index) - return bool(common.is_syncd_warm_restore_complete(namespace) or common.is_fast_reboot_enabled(namespace)) + return self.warm_fast_reboot_status.get(namespace, False) def should_notify_media_settings(self, logical_port): return not self.is_warm_fast_reboot_for_lport(logical_port) @@ -321,11 +329,6 @@ def _post_port_sfp_info_and_dom_thr_to_db_once(self, port_mapping, xcvr_table_he transceiver_dict = {} retry_eeprom_set = set() - # Pre-fetch warm/fast reboot status for all namespaces/ASICs - warm_fast_reboot_status = {} - for namespace in self.namespaces: - warm_fast_reboot_status[namespace] = common.is_syncd_warm_restore_complete(namespace) or common.is_fast_reboot_enabled(namespace) - # Post all the current interface sfp/dom threshold info to STATE_DB logical_port_list = port_mapping.logical_port_list for logical_port_name in logical_port_list: @@ -340,7 +343,7 @@ def _post_port_sfp_info_and_dom_thr_to_db_once(self, port_mapping, xcvr_table_he # Get warm/fast reboot status for this ASIC's namespace namespace = common.get_namespace_from_asic_id(asic_index) - is_warm_fast_reboot = warm_fast_reboot_status.get(namespace, False) + is_warm_fast_reboot = self.warm_fast_reboot_status.get(namespace, False) 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: From 0a88e2eebd20a49632df34bbe002c753895983e0 Mon Sep 17 00:00:00 2001 From: Yair Raviv Date: Sun, 19 Jul 2026 16:59:41 +0300 Subject: [PATCH 3/5] Ensure is_fast_reboot_enabled return value Signed-off-by: Yair Raviv --- sonic-xcvrd/xcvrd/xcvrd_utilities/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sonic-xcvrd/xcvrd/xcvrd_utilities/common.py b/sonic-xcvrd/xcvrd/xcvrd_utilities/common.py index c5e98aab9..3eed30063 100644 --- a/sonic-xcvrd/xcvrd/xcvrd_utilities/common.py +++ b/sonic-xcvrd/xcvrd/xcvrd_utilities/common.py @@ -151,6 +151,7 @@ def is_fast_reboot_enabled(namespace=''): fastboot_enabled = state_db.hget("FAST_RESTART_ENABLE_TABLE|system", "enable") if isinstance(fastboot_enabled, str): return fastboot_enabled.strip().lower() == "true" + return False def is_warm_reboot_enabled(): """Check if warm reboot is enabled""" From b3ae63676375b8165c09411b87eaa66e25dbbccf Mon Sep 17 00:00:00 2001 From: Yair Raviv Date: Tue, 4 Aug 2026 13:54:34 +0300 Subject: [PATCH 4/5] Skip loading media settings in case of fast-reboot on all ASICs Signed-off-by: Yair Raviv --- sonic-xcvrd/xcvrd/xcvrd.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 26cfdb865..1c50db0df 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -296,9 +296,6 @@ def is_warm_fast_reboot_for_lport(self, logical_port): namespace = common.get_namespace_from_asic_id(asic_index) return self.warm_fast_reboot_status.get(namespace, False) - def should_notify_media_settings(self, logical_port): - return not self.is_warm_fast_reboot_for_lport(logical_port) - def _mapping_event_from_change_event(self, status, port_dict): """ mapping from what get_transceiver_change_event returns to event defined in the state machine @@ -581,7 +578,7 @@ def task_worker(self, stopping_event, sfp_error_event): self.dom_db_utils.post_port_dom_thresholds_to_db(logical_port) self.vdm_db_utils.post_port_vdm_thresholds_to_db(logical_port) - if self.should_notify_media_settings(logical_port): + if not self.is_warm_fast_reboot_for_lport(logical_port): media_settings_parser.notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper, self.port_mapping) transceiver_dict.clear() elif value == sfp_status_helper.SFP_STATUS_REMOVED: @@ -842,7 +839,7 @@ def on_add_logical_port(self, port_change_event): else: self.dom_db_utils.post_port_dom_thresholds_to_db(port_change_event.port_name) self.vdm_db_utils.post_port_vdm_thresholds_to_db(port_change_event.port_name) - if self.should_notify_media_settings(port_change_event.port_name): + if not self.is_warm_fast_reboot_for_lport(port_change_event.port_name): media_settings_parser.notify_media_setting(port_change_event.port_name, transceiver_dict, self.xcvr_table_helper, self.port_mapping) else: status = sfp_status_helper.SFP_STATUS_REMOVED if not status else status @@ -871,7 +868,7 @@ def retry_eeprom_reading(self): self.dom_db_utils.post_port_dom_thresholds_to_db(logical_port) self.vdm_db_utils.post_port_vdm_thresholds_to_db(logical_port) - if self.should_notify_media_settings(logical_port): + if not self.is_warm_fast_reboot_for_lport(logical_port): media_settings_parser.notify_media_setting(logical_port, transceiver_dict, self.xcvr_table_helper, self.port_mapping) transceiver_dict.clear() retry_success_set.add(logical_port) @@ -1068,8 +1065,11 @@ def init(self): # Initialize xcvr table helper self.xcvr_table_helper = XcvrTableHelper(self.namespaces) - media_settings_parser.load_media_settings() - optics_si_parser.load_optics_si_settings() + if all(common.is_fast_reboot_enabled(ns) for ns in self.namespaces): + self.log_notice("Skip loading media_settings.json and optics_si_settings.json in case of fast-reboot") + else: + media_settings_parser.load_media_settings() + optics_si_parser.load_optics_si_settings() # Make sure this daemon started after all port configured self.log_notice("XCVRD INIT: Wait for port config is done") From b5131e7b75af73b0472f4c92e4c59d79ef2573c6 Mon Sep 17 00:00:00 2001 From: Yair Raviv Date: Tue, 4 Aug 2026 14:19:29 +0300 Subject: [PATCH 5/5] Removed unnecessary test Signed-off-by: Yair Raviv --- sonic-xcvrd/tests/test_xcvrd.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index 00581be4d..be8292f25 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -5614,21 +5614,6 @@ def test_SfpStateUpdateTask_is_warm_fast_reboot_for_lport_invalid_asic(self): assert task.is_warm_fast_reboot_for_lport('Ethernet0') is False - def test_SfpStateUpdateTask_should_notify_media_settings(self): - port_mapping = PortMapping() - mock_sfp_obj_dict = MagicMock() - stop_event = threading.Event() - sfp_error_event = threading.Event() - task = SfpStateUpdateTask(DEFAULT_NAMESPACE, port_mapping, mock_sfp_obj_dict, stop_event, sfp_error_event) - - task.is_warm_fast_reboot_for_lport = MagicMock(return_value=True) - assert task.should_notify_media_settings('Ethernet0') is False - task.is_warm_fast_reboot_for_lport.assert_called_with('Ethernet0') - - task.is_warm_fast_reboot_for_lport = MagicMock(return_value=False) - assert task.should_notify_media_settings('Ethernet0') is True - task.is_warm_fast_reboot_for_lport.assert_called_with('Ethernet0') - @patch('time.sleep', MagicMock()) @patch('xcvrd.xcvrd.XcvrTableHelper', MagicMock()) @patch('xcvrd.xcvrd._wrapper_soak_sfp_insert_event', MagicMock())