From f29a5db6ed72c92e6de374fd2e1c57af27601c53 Mon Sep 17 00:00:00 2001 From: chiourung_huang Date: Tue, 22 Oct 2024 09:12:33 +0000 Subject: [PATCH 1/3] reset active application code as 'N/A' when port shutdown Signed-off-by: chiourung_huang --- sonic-xcvrd/tests/test_xcvrd.py | 20 ++++++++++++++++++++ sonic-xcvrd/xcvrd/xcvrd.py | 22 ++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index d259862c5..ca421665a 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -1870,6 +1870,26 @@ def get_host_lane_assignment_option_side_effect(app): appl = get_cmis_application_desired(mock_xcvr_api, host_lane_count, speed) assert task.get_cmis_host_lanes_mask(mock_xcvr_api, appl, host_lane_count, subport) == expected + @patch('swsscommon.swsscommon.FieldValuePairs') + def test_CmisManagerTask_reset_port_active_apsel_to_db_error_cases(self, mock_field_value_pairs): + port_mapping = PortMapping() + stop_event = threading.Event() + task = CmisManagerTask(DEFAULT_NAMESPACE, port_mapping, stop_event) + lport = "Ethernet0" + host_lanes_mask = 0xff + + # Case: table does not exist + task.xcvr_table_helper.get_intf_tbl = MagicMock(return_value=None) + task.reset_port_active_apsel_to_db(lport, host_lanes_mask) + assert mock_field_value_pairs.call_count == 0 + + # Case: lport is not in the table + int_tbl = MagicMock() + int_tbl.get = MagicMock(return_value=(False, dict)) + task.xcvr_table_helper.get_intf_tbl = MagicMock(return_value=int_tbl) + task.reset_port_active_apsel_to_db(lport, host_lanes_mask) + assert mock_field_value_pairs.call_count == 0 + @patch('swsscommon.swsscommon.FieldValuePairs') def test_CmisManagerTask_post_port_active_apsel_to_db_error_cases(self, mock_field_value_pairs): mock_xcvr_api = MagicMock() diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index fbb31269f..7a5e2801c 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -1281,6 +1281,27 @@ def post_port_active_apsel_to_db(self, api, lport, host_lanes_mask): intf_tbl.set(lport, fvs) self.log_notice("{}: updated TRANSCEIVER_INFO_TABLE {}".format(lport, tuple_list)) + def reset_port_active_apsel_to_db(self, lport, host_lanes_mask): + tuple_list = [] + for lane in range(self.CMIS_MAX_HOST_LANES): + if ((1 << lane) & host_lanes_mask) == 0: + continue + tuple_list.append(('active_apsel_hostlane{}'.format(lane + 1), 'N/A')) + tuple_list.append(('host_lane_count', 'N/A')) + tuple_list.append(('media_lane_count', 'N/A')) + asic_index = self.port_mapping.get_asic_id_for_logical_port(lport) + intf_tbl = self.xcvr_table_helper.get_intf_tbl(asic_index) + if not intf_tbl: + helper_logger.log_warning("Active ApSel db update: TRANSCEIVER_INFO table not found for {}".format(lport)) + return + found, _ = intf_tbl.get(lport) + if not found: + helper_logger.log_warning("Active ApSel db update: {} not found in INTF_TABLE".format(lport)) + return + fvs = swsscommon.FieldValuePairs(tuple_list) + intf_tbl.set(lport, fvs) + self.log_notice("{}: updated TRANSCEIVER_INFO_TABLE {}".format(lport, tuple_list)) + def wait_for_port_config_done(self, namespace): # Connect to APPL_DB and subscribe to PORT table notifications appl_db = daemon_base.db_connect("APPL_DB", namespace=namespace) @@ -1468,6 +1489,7 @@ def task_worker(self): self.log_notice("{} Forcing Tx laser OFF".format(lport)) # Force DataPath re-init api.tx_disable_channel(media_lanes_mask, True) + self.reset_port_active_apsel_to_db(lport, host_lanes_mask) self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY) continue # Configure the target output power if ZR module From 6128836ceaab2ee7669c86188d8c3f68513e582d Mon Sep 17 00:00:00 2001 From: chiourung_huang Date: Wed, 23 Oct 2024 02:54:27 +0000 Subject: [PATCH 2/3] Fix unit test error --- sonic-xcvrd/tests/test_xcvrd.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index ca421665a..64994ba68 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -1879,6 +1879,7 @@ def test_CmisManagerTask_reset_port_active_apsel_to_db_error_cases(self, mock_fi host_lanes_mask = 0xff # Case: table does not exist + task.xcvr_table_helper = XcvrTableHelper(DEFAULT_NAMESPACE) task.xcvr_table_helper.get_intf_tbl = MagicMock(return_value=None) task.reset_port_active_apsel_to_db(lport, host_lanes_mask) assert mock_field_value_pairs.call_count == 0 @@ -2404,10 +2405,13 @@ def test_CmisManagerTask_task_worker_fastboot(self, mock_chassis, mock_get_statu task.get_configured_laser_freq_from_db = MagicMock(return_value=193100) task.configure_tx_output_power = MagicMock(return_value=1) task.configure_laser_frequency = MagicMock(return_value=1) + task.reset_port_active_apsel_to_db = MagicMock() task.task_stopping_event.is_set = MagicMock(side_effect=[False, False, True]) task.task_worker() + assert mock_xcvr_api.tx_disable_channel.call_count == 1 + assert task.reset_port_active_apsel_to_db.call_count == 1 assert get_cmis_state_from_state_db('Ethernet0', task.xcvr_table_helper.get_status_tbl(task.port_mapping.get_asic_id_for_logical_port('Ethernet0'))) == CMIS_STATE_READY @patch('xcvrd.xcvrd.XcvrTableHelper.get_status_tbl') @@ -2539,10 +2543,12 @@ def test_CmisManagerTask_task_worker_host_tx_ready_false(self, mock_chassis, moc task.get_configured_laser_freq_from_db = MagicMock(return_value=193100) task.configure_tx_output_power = MagicMock(return_value=1) task.configure_laser_frequency = MagicMock(return_value=1) + task.reset_port_active_apsel_to_db = MagicMock() task.task_stopping_event.is_set = MagicMock(side_effect=[False, False, True]) task.task_worker() + assert task.reset_port_active_apsel_to_db.call_count == 1 assert mock_xcvr_api.tx_disable_channel.call_count == 1 assert get_cmis_state_from_state_db('Ethernet0', task.xcvr_table_helper.get_status_tbl(task.port_mapping.get_asic_id_for_logical_port('Ethernet0'))) == CMIS_STATE_READY From 89000a58e2ef1338c4ebd9a06f182d6a857a18b9 Mon Sep 17 00:00:00 2001 From: chiourung_huang Date: Wed, 4 Dec 2024 06:38:05 +0000 Subject: [PATCH 3/3] reuse post_port_active_apsel_to_db function to reset active application code as 'N/A' --- sonic-xcvrd/tests/test_xcvrd.py | 55 +++++++++++++++-------------- sonic-xcvrd/xcvrd/xcvrd.py | 61 +++++++++++++-------------------- 2 files changed, 54 insertions(+), 62 deletions(-) diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index 64994ba68..6666ca926 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -1870,27 +1870,6 @@ def get_host_lane_assignment_option_side_effect(app): appl = get_cmis_application_desired(mock_xcvr_api, host_lane_count, speed) assert task.get_cmis_host_lanes_mask(mock_xcvr_api, appl, host_lane_count, subport) == expected - @patch('swsscommon.swsscommon.FieldValuePairs') - def test_CmisManagerTask_reset_port_active_apsel_to_db_error_cases(self, mock_field_value_pairs): - port_mapping = PortMapping() - stop_event = threading.Event() - task = CmisManagerTask(DEFAULT_NAMESPACE, port_mapping, stop_event) - lport = "Ethernet0" - host_lanes_mask = 0xff - - # Case: table does not exist - task.xcvr_table_helper = XcvrTableHelper(DEFAULT_NAMESPACE) - task.xcvr_table_helper.get_intf_tbl = MagicMock(return_value=None) - task.reset_port_active_apsel_to_db(lport, host_lanes_mask) - assert mock_field_value_pairs.call_count == 0 - - # Case: lport is not in the table - int_tbl = MagicMock() - int_tbl.get = MagicMock(return_value=(False, dict)) - task.xcvr_table_helper.get_intf_tbl = MagicMock(return_value=int_tbl) - task.reset_port_active_apsel_to_db(lport, host_lanes_mask) - assert mock_field_value_pairs.call_count == 0 - @patch('swsscommon.swsscommon.FieldValuePairs') def test_CmisManagerTask_post_port_active_apsel_to_db_error_cases(self, mock_field_value_pairs): mock_xcvr_api = MagicMock() @@ -1994,6 +1973,32 @@ def test_CmisManagerTask_post_port_active_apsel_to_db(self): 'host_lane_count': '2', 'media_lane_count': '1'} + # case: partial lanes update (reset to 'N/A') + lport = "Ethernet16" + host_lanes_mask = 0xc + ret = task.post_port_active_apsel_to_db(mock_xcvr_api, lport, host_lanes_mask, reset_apsel=True) + assert int_tbl.getKeys() == ["Ethernet0", "Ethernet8", "Ethernet16"] + assert dict(int_tbl.mock_dict["Ethernet16"]) == {'active_apsel_hostlane3': 'N/A', + 'active_apsel_hostlane4': 'N/A', + 'host_lane_count': 'N/A', + 'media_lane_count': 'N/A'} + + # case: full lanes update (reset to 'N/A') + lport = "Ethernet32" + host_lanes_mask = 0xff + task.post_port_active_apsel_to_db(mock_xcvr_api, lport, host_lanes_mask, reset_apsel=True) + assert int_tbl.getKeys() == ["Ethernet0", "Ethernet8", "Ethernet16", "Ethernet32"] + assert dict(int_tbl.mock_dict["Ethernet32"]) == {'active_apsel_hostlane1': 'N/A', + 'active_apsel_hostlane2': 'N/A', + 'active_apsel_hostlane3': 'N/A', + 'active_apsel_hostlane4': 'N/A', + 'active_apsel_hostlane5': 'N/A', + 'active_apsel_hostlane6': 'N/A', + 'active_apsel_hostlane7': 'N/A', + 'active_apsel_hostlane8': 'N/A', + 'host_lane_count': 'N/A', + 'media_lane_count': 'N/A'} + # case: NotImplementedError int_tbl = Table("STATE_DB", TRANSCEIVER_INFO_TABLE) # a new empty table lport = "Ethernet0" @@ -2405,13 +2410,13 @@ def test_CmisManagerTask_task_worker_fastboot(self, mock_chassis, mock_get_statu task.get_configured_laser_freq_from_db = MagicMock(return_value=193100) task.configure_tx_output_power = MagicMock(return_value=1) task.configure_laser_frequency = MagicMock(return_value=1) - task.reset_port_active_apsel_to_db = MagicMock() + task.post_port_active_apsel_to_db = MagicMock() task.task_stopping_event.is_set = MagicMock(side_effect=[False, False, True]) task.task_worker() assert mock_xcvr_api.tx_disable_channel.call_count == 1 - assert task.reset_port_active_apsel_to_db.call_count == 1 + assert task.post_port_active_apsel_to_db.call_count == 1 assert get_cmis_state_from_state_db('Ethernet0', task.xcvr_table_helper.get_status_tbl(task.port_mapping.get_asic_id_for_logical_port('Ethernet0'))) == CMIS_STATE_READY @patch('xcvrd.xcvrd.XcvrTableHelper.get_status_tbl') @@ -2543,12 +2548,12 @@ def test_CmisManagerTask_task_worker_host_tx_ready_false(self, mock_chassis, moc task.get_configured_laser_freq_from_db = MagicMock(return_value=193100) task.configure_tx_output_power = MagicMock(return_value=1) task.configure_laser_frequency = MagicMock(return_value=1) - task.reset_port_active_apsel_to_db = MagicMock() + task.post_port_active_apsel_to_db = MagicMock() task.task_stopping_event.is_set = MagicMock(side_effect=[False, False, True]) task.task_worker() - assert task.reset_port_active_apsel_to_db.call_count == 1 + assert task.post_port_active_apsel_to_db.call_count == 1 assert mock_xcvr_api.tx_disable_channel.call_count == 1 assert get_cmis_state_from_state_db('Ethernet0', task.xcvr_table_helper.get_status_tbl(task.port_mapping.get_asic_id_for_logical_port('Ethernet0'))) == CMIS_STATE_READY diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 7a5e2801c..2a1b0bec9 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -1244,51 +1244,38 @@ def configure_laser_frequency(self, api, lport, freq, grid=75): self.log_error("{} Tuning in progress, subport selection may fail!".format(lport)) return api.set_laser_freq(freq, grid) - def post_port_active_apsel_to_db(self, api, lport, host_lanes_mask): - try: - act_apsel = api.get_active_apsel_hostlane() - appl_advt = api.get_application_advertisement() - except NotImplementedError: - helper_logger.log_error("Required feature is not implemented") - return + def post_port_active_apsel_to_db(self, api, lport, host_lanes_mask, reset_apsel=False): + if reset_apsel == False: + try: + act_apsel = api.get_active_apsel_hostlane() + appl_advt = api.get_application_advertisement() + except NotImplementedError: + helper_logger.log_error("Required feature is not implemented") + return tuple_list = [] for lane in range(self.CMIS_MAX_HOST_LANES): if ((1 << lane) & host_lanes_mask) == 0: continue - act_apsel_lane = act_apsel.get('ActiveAppSelLane{}'.format(lane + 1), 'N/A') - tuple_list.append(('active_apsel_hostlane{}'.format(lane + 1), - str(act_apsel_lane))) + if reset_apsel == False: + act_apsel_lane = act_apsel.get('ActiveAppSelLane{}'.format(lane + 1), 'N/A') + tuple_list.append(('active_apsel_hostlane{}'.format(lane + 1), + str(act_apsel_lane))) + else: + tuple_list.append(('active_apsel_hostlane{}'.format(lane + 1), 'N/A')) # also update host_lane_count and media_lane_count if len(tuple_list) > 0: - appl_advt_act = appl_advt.get(act_apsel_lane) - host_lane_count = appl_advt_act.get('host_lane_count', 'N/A') if appl_advt_act else 'N/A' - tuple_list.append(('host_lane_count', str(host_lane_count))) - media_lane_count = appl_advt_act.get('media_lane_count', 'N/A') if appl_advt_act else 'N/A' - tuple_list.append(('media_lane_count', str(media_lane_count))) - - asic_index = self.port_mapping.get_asic_id_for_logical_port(lport) - intf_tbl = self.xcvr_table_helper.get_intf_tbl(asic_index) - if not intf_tbl: - helper_logger.log_warning("Active ApSel db update: TRANSCEIVER_INFO table not found for {}".format(lport)) - return - found, _ = intf_tbl.get(lport) - if not found: - helper_logger.log_warning("Active ApSel db update: {} not found in INTF_TABLE".format(lport)) - return - fvs = swsscommon.FieldValuePairs(tuple_list) - intf_tbl.set(lport, fvs) - self.log_notice("{}: updated TRANSCEIVER_INFO_TABLE {}".format(lport, tuple_list)) + if reset_apsel == False: + appl_advt_act = appl_advt.get(act_apsel_lane) + host_lane_count = appl_advt_act.get('host_lane_count', 'N/A') if appl_advt_act else 'N/A' + tuple_list.append(('host_lane_count', str(host_lane_count))) + media_lane_count = appl_advt_act.get('media_lane_count', 'N/A') if appl_advt_act else 'N/A' + tuple_list.append(('media_lane_count', str(media_lane_count))) + else: + tuple_list.append(('host_lane_count', 'N/A')) + tuple_list.append(('media_lane_count', 'N/A')) - def reset_port_active_apsel_to_db(self, lport, host_lanes_mask): - tuple_list = [] - for lane in range(self.CMIS_MAX_HOST_LANES): - if ((1 << lane) & host_lanes_mask) == 0: - continue - tuple_list.append(('active_apsel_hostlane{}'.format(lane + 1), 'N/A')) - tuple_list.append(('host_lane_count', 'N/A')) - tuple_list.append(('media_lane_count', 'N/A')) asic_index = self.port_mapping.get_asic_id_for_logical_port(lport) intf_tbl = self.xcvr_table_helper.get_intf_tbl(asic_index) if not intf_tbl: @@ -1489,7 +1476,7 @@ def task_worker(self): self.log_notice("{} Forcing Tx laser OFF".format(lport)) # Force DataPath re-init api.tx_disable_channel(media_lanes_mask, True) - self.reset_port_active_apsel_to_db(lport, host_lanes_mask) + self.post_port_active_apsel_to_db(lport, host_lanes_mask, reset_apsel=True) self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_READY) continue # Configure the target output power if ZR module