From 2d820aec15ff765447d9bcbbad11a47a554e96a4 Mon Sep 17 00:00:00 2001 From: Sonic Build Admin Date: Tue, 2 Sep 2025 10:16:58 +0000 Subject: [PATCH] Check low power mode before vdm handling #### Description Skip VDM handling when the interface low power mode is on. #### Motivation and Context When the interface low power mode is on, we see following errors in the syslog: ERR pmon#xcvrd[76]: Failed to confirm VDM unfreeze status for port 63 ERR pmon#xcvrd[76]: Failed to unfreeze VDM stats in contextmanager for port 63 ERR pmon#xcvrd[76]: Failed to confirm VDM freeze status for port 63 ERR pmon#xcvrd[76]: Failed to freeze VDM stats in contextmanager for port 63 ERR pmon#xcvrd[76]: DOM-INFO-UPDATE: Failed to freeze VDM stats for port 63 ERR pmon#xcvrd[76]: Failed to confirm VDM unfreeze status for port 63 ERR pmon#xcvrd[76]: Failed to unfreeze VDM stats in contextmanager for port 63 To avoid the errors, we are skipping VDM handling when low power mode is on. To achieve this, a helper method is added to check for VDM status which is called before the VDM handling code block. #### How Has This Been Tested? 1. Turn on interface lpmode. 2. Verify that syslog has the above-mentioned errors for the interface. 3. Make the code changes in the pmon container. 4. Restart the xcvrd. 5. Once the interfaces are initialized, turn off and turn on the lpmode of the interface. 6. Check the syslog. Above-mentioned errors should not appear for the interface. 7. Check TRANSCEIVER_VDM_REAL_VALUE table of the interface. It should not update while the lpmode is on. 8. For 400ZR optics, TRANSCEIVER_PM table should not update while the lpmode is on. 9. Turn off lpmode of the interface. 10. See that TRANSCEIVER_VDM_REAL_VALUE and TRANSCEIVER_PM gets updated. This PR has been tested on 100G OSFP 8X Pluggable Transceiver and 400ZR QSFP-DD Double Density 8X Pluggable Transceiver. #### Additional Information (Optional) ADO: 32013738 --- sonic-xcvrd/tests/test_xcvrd.py | 29 ++++++++++++++++++++++ sonic-xcvrd/xcvrd/dom/dom_mgr.py | 2 +- sonic-xcvrd/xcvrd/xcvrd_utilities/utils.py | 7 ++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index 99ee66e..79a6d6c 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -3371,6 +3371,7 @@ def test_DomInfoUpdateTask_task_worker(self, mock_post_pm_info, task.status_db_utils.post_port_transceiver_hw_status_to_db = MagicMock() task.status_db_utils.post_port_transceiver_hw_status_flags_to_db = MagicMock() task.vdm_utils.is_transceiver_vdm_supported = MagicMock(return_value=True) + task.xcvrd_utils.is_transceiver_lpmode_on = MagicMock(return_value=False) task.vdm_db_utils = MagicMock() task.vdm_db_utils.post_port_vdm_real_values_to_db = MagicMock() task.task_worker() @@ -3435,6 +3436,7 @@ def test_DomInfoUpdateTask_task_worker_vdm_failure(self, mock_post_pm_info): task.vdm_utils._unfreeze_vdm_stats_and_confirm = MagicMock(return_value=True) task.vdm_db_utils.post_port_vdm_real_values_to_db = MagicMock() task.vdm_db_utils.post_port_vdm_flags_to_db = MagicMock() + task.xcvrd_utils.is_transceiver_lpmode_on = MagicMock(return_value=False) task.task_worker() assert task.vdm_utils._unfreeze_vdm_stats_and_confirm.call_count == 1 assert task.vdm_db_utils.post_port_vdm_real_values_to_db.call_count == 0 @@ -4396,6 +4398,33 @@ def test_is_transceiver_flat_memory(self): mock_api.is_flat_memory = MagicMock(side_effect=NotImplementedError) assert xcvrd_util.is_transceiver_flat_memory(1) + def test_is_transceiver_lpmode_on(self): + from xcvrd.xcvrd_utilities.utils import XCVRDUtils + mock_sfp = MagicMock() + xcvrd_util = XCVRDUtils({1: mock_sfp}, MagicMock()) + + # Test case where get_xcvr_api returns None + mock_sfp.get_lpmode = MagicMock(return_value=None) + assert not xcvrd_util.is_transceiver_lpmode_on(1) + + # Test case where get_lpmode returns True + mock_sfp.get_lpmode = MagicMock(return_value=True) + assert xcvrd_util.is_transceiver_lpmode_on(1) + + # Test case where get_lpmode returns False + + mock_sfp.get_lpmode = MagicMock(return_value=False) + assert not xcvrd_util.is_transceiver_lpmode_on(1) + + # Test case where get_xcvr_api raises KeyError + xcvrd_util.sfp_obj_dict = {} + assert not xcvrd_util.is_transceiver_lpmode_on(1) + + # Test case where is_flat_memory raises NotImplementedError + xcvrd_util.sfp_obj_dict = {1: mock_sfp} + mock_sfp.get_lpmode = MagicMock(side_effect=NotImplementedError) + assert not xcvrd_util.is_transceiver_lpmode_on(1) + @patch('time.sleep', MagicMock()) @patch('xcvrd.xcvrd.XcvrTableHelper', MagicMock()) @patch('xcvrd.xcvrd._wrapper_soak_sfp_insert_event', MagicMock()) diff --git a/sonic-xcvrd/xcvrd/dom/dom_mgr.py b/sonic-xcvrd/xcvrd/dom/dom_mgr.py index aefce77..9a57d0a 100644 --- a/sonic-xcvrd/xcvrd/dom/dom_mgr.py +++ b/sonic-xcvrd/xcvrd/dom/dom_mgr.py @@ -303,7 +303,7 @@ def task_worker(self): self.log_warning("Got exception {} while processing transceiver status hw flags for " "port {}, ignored".format(repr(e), logical_port_name)) continue - if self.vdm_utils.is_transceiver_vdm_supported(physical_port): + if self.vdm_utils.is_transceiver_vdm_supported(physical_port) and (not self.xcvrd_utils.is_transceiver_lpmode_on(physical_port)): # Freeze VDM stats before reading VDM values with self.vdm_utils.vdm_freeze_context(physical_port) as vdm_frozen: if not vdm_frozen: diff --git a/sonic-xcvrd/xcvrd/xcvrd_utilities/utils.py b/sonic-xcvrd/xcvrd/xcvrd_utilities/utils.py index a8b7365..51231bf 100644 --- a/sonic-xcvrd/xcvrd/xcvrd_utilities/utils.py +++ b/sonic-xcvrd/xcvrd/xcvrd_utilities/utils.py @@ -23,3 +23,10 @@ def is_transceiver_flat_memory(self, physical_port): except (KeyError, NotImplementedError): self.logger.log_error(f"Failed to check flat memory for port {physical_port}") return True + + def is_transceiver_lpmode_on(self, physical_port): + try: + return self.sfp_obj_dict[physical_port].get_lpmode() + except Exception as e: + self.logger.log_error(f"Failed to get low power mode for port {physical_port}. Exception: {e}") + return False