diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index 20a1a6bd5..28340f3f2 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -401,33 +401,39 @@ def test_SfpStateUpdateTask_task_run_with_exception(self): @patch('xcvrd.xcvrd.SfpStateUpdateTask.is_alive', MagicMock(return_value = False)) @patch('xcvrd.xcvrd.DomInfoUpdateTask.is_alive', MagicMock(return_value = False)) + @patch('xcvrd.xcvrd.DomThermalInfoUpdateTask.is_alive', MagicMock(return_value = False)) @patch('xcvrd.cmis.CmisManagerTask.is_alive', MagicMock(return_value = False)) @patch('xcvrd.xcvrd.SffManagerTask.is_alive', MagicMock(return_value=False)) @patch('xcvrd.cmis.CmisManagerTask.join', MagicMock(side_effect=NotImplementedError)) @patch('xcvrd.cmis.CmisManagerTask.start', MagicMock()) @patch('xcvrd.xcvrd.SffManagerTask.start', MagicMock()) @patch('xcvrd.xcvrd.DomInfoUpdateTask.start', MagicMock()) + @patch('xcvrd.xcvrd.DomThermalInfoUpdateTask.start', MagicMock()) @patch('xcvrd.xcvrd.SfpStateUpdateTask.start', MagicMock()) @patch('xcvrd.xcvrd.DaemonXcvrd.deinit', MagicMock()) @patch('os.kill') @patch('xcvrd.xcvrd.DaemonXcvrd.init') @patch('xcvrd.xcvrd.DomInfoUpdateTask.join') + @patch('xcvrd.xcvrd.DomThermalInfoUpdateTask.join') @patch('xcvrd.xcvrd.SfpStateUpdateTask.join') @patch('xcvrd.xcvrd.SffManagerTask.join') def test_DaemonXcvrd_run_with_exception(self, mock_task_join_sff, mock_task_join_sfp, - mock_task_join_dom, mock_init, mock_os_kill): + mock_task_join_dom, mock_task_join_dom_thermal, + mock_init, mock_os_kill): mock_init.return_value = PortMapping() xcvrd = DaemonXcvrd(SYSLOG_IDENTIFIER) xcvrd.enable_sff_mgr = True + xcvrd.dom_temperature_poll_interval = 10 xcvrd.load_feature_flags = MagicMock() xcvrd.stop_event.wait = MagicMock() xcvrd.run() - assert len(xcvrd.threads) == 4 + assert len(xcvrd.threads) == 5 assert mock_init.call_count == 1 assert mock_task_join_sff.call_count == 1 assert mock_task_join_sfp.call_count == 1 assert mock_task_join_dom.call_count == 1 + assert mock_task_join_dom_thermal.call_count == 1 assert mock_os_kill.call_count == 1 class TestXcvrdScript(object): @@ -652,6 +658,64 @@ def mock_get_transceiver_dom_sensor_real_value(physical_port): dom_db_utils.post_port_dom_sensor_info_to_db(logical_port_name, db_cache=db_cache) assert dom_tbl.get_size_for_key(logical_port_name) == 27 + def test_post_port_dom_temperature_info_to_db(self): + def mock_get_transceiver_dom_temperature(physical_port): + return { + 'temperature': '68.75', + } + + logical_port_name = "Ethernet0" + port_mapping = PortMapping() + port_mapping.get_logical_to_physical = MagicMock(return_value=[0]) + xcvr_table_helper = XcvrTableHelper(DEFAULT_NAMESPACE) + stop_event = threading.Event() + mock_sfp_obj_dict = {0 : MagicMock()} + + dom_db_utils = DOMDBUtils(mock_sfp_obj_dict, port_mapping, xcvr_table_helper, stop_event, helper_logger) + dom_db_utils.dom_utils = MagicMock() + dom_db_utils.xcvrd_utils.get_transceiver_presence = MagicMock(return_value=False) + dom_db_utils.xcvrd_utils.is_transceiver_flat_memory = MagicMock(return_value=False) + dom_tbl = Table("STATE_DB", TRANSCEIVER_DOM_TEMPERATURE_TABLE) + dom_db_utils.xcvr_table_helper.get_dom_temperature_tbl = MagicMock(return_value=dom_tbl) + dom_db_utils.dom_utils.get_transceiver_dom_temperature = MagicMock(return_value=None) + assert dom_tbl.get_size() == 0 + + # Ensure table is empty asic_index is None + port_mapping.get_asic_id_for_logical_port = MagicMock(return_value=None) + dom_db_utils.post_port_dom_temperature_info_to_db(logical_port_name) + assert dom_tbl.get_size() == 0 + + # Set asic_index to 0 + port_mapping.get_asic_id_for_logical_port = MagicMock(return_value=0) + + # Ensure table is empty if stop_event is set + stop_event.set() + dom_db_utils.post_port_dom_temperature_info_to_db(logical_port_name) + assert dom_tbl.get_size() == 0 + stop_event.clear() + + # Ensure table is empty if transceiver is not present + dom_db_utils.post_port_dom_temperature_info_to_db(logical_port_name) + assert dom_tbl.get_size() == 0 + dom_db_utils.return_value = True + + # Ensure table is empty if get_values_func returns None + dom_db_utils.xcvrd_utils.get_transceiver_presence = MagicMock(return_value=True) + dom_db_utils.post_port_dom_temperature_info_to_db(logical_port_name) + assert dom_tbl.get_size() == 0 + + # Ensure table is populated if get_values_func returns valid values + db_cache = {} + dom_db_utils.dom_utils.get_transceiver_dom_temperature = MagicMock(side_effect=mock_get_transceiver_dom_temperature) + dom_db_utils.post_port_dom_temperature_info_to_db(logical_port_name, db_cache=db_cache) + assert dom_tbl.get_size_for_key(logical_port_name) == 2 + + # Ensure db_cache is populated correctly + assert db_cache.get(0) is not None + dom_db_utils.dom_utils.get_transceiver_dom_temperature = MagicMock(return_value=None) + dom_db_utils.post_port_dom_temperature_info_to_db(logical_port_name, db_cache=db_cache) + assert dom_tbl.get_size_for_key(logical_port_name) == 2 + def test_post_port_dom_flags_to_db(self): def mock_get_transceiver_dom_flags(physical_port): return { @@ -3809,6 +3873,37 @@ def test_beautify_info_dict(self): db_utils.beautify_info_dict(dom_info_dict) assert dom_info_dict == expected_dom_info_dict + @patch('xcvrd.xcvrd.XcvrTableHelper', MagicMock()) + @patch('xcvrd.xcvrd_utilities.common._wrapper_get_presence', MagicMock(return_value=True)) + @patch('xcvrd.xcvrd_utilities.sfp_status_helper.detect_port_in_error_status') + @patch('time.sleep', MagicMock()) + def test_DomThermalInfoUpdateTask_task_worker(self, mock_detect_error): + poll_interval = 10 + port_mapping = PortMapping() + port_mapping.physical_to_logical = { + 1: ['Ethernet0'], + 2: ['Ethernet4'], + 3: ['Ethernet8'], + } + port_mapping.logical_to_asic = { + 'Ethernet0': 0, + 'Ethernet4': 0, + 'Ethernet8': None, + } + dom_monitoring_disabled = { + 'Ethernet0': False, + 'Ethernet4': True, + 'Ethernet8': False, + } + mock_sfp_obj_dict = MagicMock() + stop_event = threading.Event() + task = DomThermalInfoUpdateTask(DEFAULT_NAMESPACE, port_mapping, mock_sfp_obj_dict, stop_event, poll_interval) + task.xcvr_table_helper = XcvrTableHelper(DEFAULT_NAMESPACE) + task.task_stopping_event.is_set = MagicMock(side_effect=[False, False, False, False, False, False, True]) + mock_detect_error.return_value = False + task.is_port_dom_monitoring_disabled = lambda p: dom_monitoring_disabled[p] + task.task_worker() + @patch('xcvrd.xcvrd.XcvrTableHelper', MagicMock()) @patch('xcvrd.xcvrd_utilities.common.del_port_sfp_dom_info_from_db') def test_DomInfoUpdateTask_handle_port_change_event(self, mock_del_port_sfp_dom_info_from_db): @@ -4549,6 +4644,16 @@ def test_wrapper_get_transceiver_firmware_info(self, mock_sfputil, mock_chassis) mock_chassis.get_sfp = MagicMock(side_effect=NotImplementedError) assert common._wrapper_get_transceiver_firmware_info(1) == {} + def test_get_transceiver_dom_temperature(self): + mock_sfp = MagicMock() + dom_utils = DOMUtils({1 : mock_sfp}, helper_logger) + + mock_sfp.get_temperature.return_value = 42. + assert 'temperature' in dom_utils.get_transceiver_dom_temperature(1) + + mock_sfp.get_temperature.side_effect = NotImplementedError + assert dom_utils.get_transceiver_dom_temperature(1) == {} + def test_get_transceiver_dom_sensor_real_value(self): mock_sfp = MagicMock() dom_utils = DOMUtils({1 : mock_sfp}, helper_logger) @@ -4760,6 +4865,7 @@ def test_DaemonXcvrd_init_deinit_fastboot_enabled(self, mock_del_port_sfp_dom_in status_sw_tbl = MagicMock() xcvrd.xcvr_table_helper.get_status_sw_tbl = MagicMock(return_value=status_sw_tbl) xcvrd.xcvr_table_helper.get_dom_tbl = MagicMock(return_value=MagicMock) + xcvrd.xcvr_table_helper.get_dom_temperature_tbl = MagicMock(return_value=MagicMock) xcvrd.xcvr_table_helper.get_dom_flag_tbl = MagicMock() xcvrd.xcvr_table_helper.get_dom_flag_change_count_tbl = MagicMock() xcvrd.xcvr_table_helper.get_dom_flag_set_time_tbl = MagicMock() @@ -4807,6 +4913,7 @@ def test_DaemonXcvrd_init_deinit_cold(self, mock_del_port_sfp_dom_info_from_db): status_sw_tbl = MagicMock() xcvrdaemon.xcvr_table_helper.get_status_sw_tbl = MagicMock(return_value=status_sw_tbl) xcvrdaemon.xcvr_table_helper.get_dom_tbl = MagicMock(return_value=MagicMock) + xcvrdaemon.xcvr_table_helper.get_dom_temperature_tbl = MagicMock(return_value=MagicMock) xcvrdaemon.xcvr_table_helper.get_dom_threshold_tbl = MagicMock(return_value=MagicMock) xcvrdaemon.xcvr_table_helper.get_dom_flag_tbl = MagicMock() xcvrdaemon.xcvr_table_helper.get_dom_flag_change_count_tbl = MagicMock() diff --git a/sonic-xcvrd/xcvrd/dom/dom_mgr.py b/sonic-xcvrd/xcvrd/dom/dom_mgr.py index f4135f35b..5dabdb02f 100644 --- a/sonic-xcvrd/xcvrd/dom/dom_mgr.py +++ b/sonic-xcvrd/xcvrd/dom/dom_mgr.py @@ -13,6 +13,7 @@ import copy import sys import re + import time from natsort import natsorted from sonic_py_common import syslogger @@ -33,32 +34,19 @@ SYSLOG_IDENTIFIER_DOMINFOUPDATETASK = "DomInfoUpdateTask" -class DomInfoUpdateTask(threading.Thread): - DOM_INFO_UPDATE_PERIOD_SECS = 60 - DIAG_DB_UPDATE_TIME_AFTER_LINK_CHANGE = 1 - DOM_PORT_CHG_OBSERVER_TBL_MAP = [ - {'APPL_DB': 'PORT_TABLE', 'FILTER': ['flap_count']}, - ] +class DomInfoUpdateBase(threading.Thread): - def __init__(self, namespaces, port_mapping, sfp_obj_dict, main_thread_stop_event, skip_cmis_mgr): + name = '' + + def __init__(self, namespaces, port_mapping, sfp_obj_dict, main_thread_stop_event): threading.Thread.__init__(self) - self.name = "DomInfoUpdateTask" self.exc = None self.task_stopping_event = threading.Event() self.main_thread_stop_event = main_thread_stop_event self.helper_logger = syslogger.SysLogger(SYSLOG_IDENTIFIER_DOMINFOUPDATETASK, enable_runtime_config=True) self.port_mapping = copy.deepcopy(port_mapping) self.namespaces = namespaces - self.skip_cmis_mgr = skip_cmis_mgr self.sfp_obj_dict = sfp_obj_dict - self.link_change_affected_ports = {} - self.xcvr_table_helper = XcvrTableHelper(self.namespaces) - self.xcvrd_utils = XCVRDUtils(self.sfp_obj_dict, helper_logger) - self.dom_db_utils = DOMDBUtils(self.sfp_obj_dict, self.port_mapping, self.xcvr_table_helper, self.task_stopping_event, self.helper_logger) - self.db_utils = self.dom_db_utils - self.vdm_utils = VDMUtils(self.sfp_obj_dict, self.helper_logger) - self.vdm_db_utils = VDMDBUtils(self.sfp_obj_dict, self.port_mapping, self.xcvr_table_helper, self.task_stopping_event, self.helper_logger) - self.status_db_utils = StatusDBUtils(self.sfp_obj_dict, self.port_mapping, self.xcvr_table_helper, self.task_stopping_event, self.helper_logger) def log_debug(self, message): self.helper_logger.log_debug("{}".format(message)) @@ -75,6 +63,14 @@ def log_warning(self, message): def log_error(self, message): self.helper_logger.log_error("{}".format(message)) + def on_port_config_change(self, port_change_event): + if port_change_event.event_type == port_event_helper.PortChangeEvent.PORT_REMOVE: + self.on_remove_logical_port(port_change_event) + self.port_mapping.handle_port_change_event(port_change_event) + + def on_remove_logical_port(self, port_change_event): + pass + def get_dom_polling_from_config_db(self, lport): """ Returns the value of dom_polling field from PORT table in CONFIG_DB @@ -110,6 +106,57 @@ def get_dom_polling_from_config_db(self, lport): return dom_polling + + def is_port_dom_monitoring_disabled(self, logical_port_name): + return self.get_dom_polling_from_config_db(logical_port_name) == 'disabled' + + def task_worker(self): + pass + + def run(self): + if self.task_stopping_event.is_set(): + return + try: + self.task_worker() + except Exception as e: + self.log_error("Exception occurred at {} thread due to {}".format(threading.current_thread().getName(), repr(e))) + common.log_exception_traceback() + self.exc = e + self.main_thread_stop_event.set() + + def join(self): + self.task_stopping_event.set() + threading.Thread.join(self) + if self.exc: + raise self.exc + + def update_log_level(self): + """Call the logger's update log level method. + """ + return self.helper_logger.update_log_level() + + +class DomInfoUpdateTask(DomInfoUpdateBase): + name = "DomInfoUpdateTask" + + DOM_INFO_UPDATE_PERIOD_SECS = 60 + DIAG_DB_UPDATE_TIME_AFTER_LINK_CHANGE = 1 + DOM_PORT_CHG_OBSERVER_TBL_MAP = [ + {'APPL_DB': 'PORT_TABLE', 'FILTER': ['flap_count']}, + ] + + def __init__(self, namespaces, port_mapping, sfp_obj_dict, main_thread_stop_event, skip_cmis_mgr): + super().__init__(namespaces, port_mapping, sfp_obj_dict, main_thread_stop_event) + self.skip_cmis_mgr = skip_cmis_mgr + self.link_change_affected_ports = {} + self.xcvr_table_helper = XcvrTableHelper(self.namespaces) + self.xcvrd_utils = XCVRDUtils(self.sfp_obj_dict, helper_logger) + self.dom_db_utils = DOMDBUtils(self.sfp_obj_dict, self.port_mapping, self.xcvr_table_helper, self.task_stopping_event, self.helper_logger) + self.db_utils = self.dom_db_utils + self.vdm_utils = VDMUtils(self.sfp_obj_dict, self.helper_logger) + self.vdm_db_utils = VDMDBUtils(self.sfp_obj_dict, self.port_mapping, self.xcvr_table_helper, self.task_stopping_event, self.helper_logger) + self.status_db_utils = StatusDBUtils(self.sfp_obj_dict, self.port_mapping, self.xcvr_table_helper, self.task_stopping_event, self.helper_logger) + """ Checks if the port is going through CMIS initialization process This API assumes CMIS_STATE_UNKNOWN as a transitional state since it is the @@ -339,23 +386,6 @@ def task_worker(self): self.log_notice("Stop DOM monitoring loop") - def run(self): - if self.task_stopping_event.is_set(): - return - try: - self.task_worker() - except Exception as e: - self.log_error("Exception occured at {} thread due to {}".format(threading.current_thread().getName(), repr(e))) - common.log_exception_traceback() - self.exc = e - self.main_thread_stop_event.set() - - def join(self): - self.task_stopping_event.set() - threading.Thread.join(self) - if self.exc: - raise self.exc - def on_port_update_event(self, port_change_event): """Called when a port change event is received @@ -427,11 +457,6 @@ def update_port_db_diagnostics_on_link_change(self, physical_port): self.log_warning(f"Update DB diagnostics during link change: Got exception {repr(e)} while processing vdm flags for port {first_logical_port}, ignored") return - def on_port_config_change(self, port_change_event): - if port_change_event.event_type == port_event_helper.PortChangeEvent.PORT_REMOVE: - self.on_remove_logical_port(port_change_event) - self.port_mapping.handle_port_change_event(port_change_event) - def on_remove_logical_port(self, port_change_event): """Called when a logical port is removed from CONFIG_DB @@ -444,6 +469,7 @@ def on_remove_logical_port(self, port_change_event): common.del_port_sfp_dom_info_from_db(port_change_event.port_name, self.port_mapping, [self.xcvr_table_helper.get_dom_tbl(port_change_event.asic_id), + self.xcvr_table_helper.get_dom_temperature_tbl(port_change_event.asic_id), self.xcvr_table_helper.get_dom_flag_tbl(port_change_event.asic_id), self.xcvr_table_helper.get_dom_flag_change_count_tbl(port_change_event.asic_id), self.xcvr_table_helper.get_dom_flag_set_time_tbl(port_change_event.asic_id), @@ -461,7 +487,59 @@ def on_remove_logical_port(self, port_change_event): self.xcvr_table_helper.get_pm_tbl(port_change_event.asic_id), self.xcvr_table_helper.get_firmware_info_tbl(port_change_event.asic_id) ]) - def update_log_level(self): - """Call the logger's update log level method. - """ - return self.helper_logger.update_log_level() + +class DomThermalInfoUpdateTask(DomInfoUpdateBase): + name = 'DomThermalInfoUpdateTask' + + def __init__(self, namespaces, port_mapping, sfp_obj_dict, main_thread_stop_event, poll_interval): + super().__init__(namespaces, port_mapping, sfp_obj_dict, main_thread_stop_event) + self.poll_interval = poll_interval + self.xcvr_table_helper = XcvrTableHelper(self.namespaces) + self.dom_db_utils = DOMDBUtils(self.sfp_obj_dict, self.port_mapping, self.xcvr_table_helper, self.task_stopping_event, self.helper_logger) + + def task_worker(self): + self.log_notice("Start DOM thermal monitoring loop") + + # Set the periodic db update time + dom_info_update_periodic_secs = self.poll_interval + + # Poll transceiver temperature as soon as possible + next_periodic_db_update_time = datetime.datetime.now() + + # Start loop to update dom info in DB periodically and handle port change events + while not self.task_stopping_event.is_set(): + # Check if periodic db update is needed + now = datetime.datetime.now() + if next_periodic_db_update_time > now: + # Sleep for 1 second or less depending on the remaining time + time.sleep(max(0, min(1, (next_periodic_db_update_time - now).total_seconds()))) + continue + + for physical_port, logical_ports in self.port_mapping.physical_to_logical.items(): + # Get the first logical port name since it corresponds to the first subport + # of the breakout group + logical_port_name = logical_ports[0] + + if self.is_port_dom_monitoring_disabled(logical_port_name): + continue + + # Get the asic to which this port belongs + asic_index = self.port_mapping.get_asic_id_for_logical_port(logical_port_name) + if asic_index is None: + self.log_warning("Got invalid asic index for {}, ignored".format(logical_port_name)) + continue + + if not sfp_status_helper.detect_port_in_error_status(logical_port_name, self.xcvr_table_helper.get_status_sw_tbl(asic_index)): + if not common._wrapper_get_presence(physical_port): + continue + + try: + self.dom_db_utils.post_port_dom_temperature_info_to_db(logical_port_name) + except (KeyError, TypeError) as e: + #continue to process next port since exception could be raised due to port reset, transceiver removal + self.log_warning("Got exception {} while processing dom info for port {}, ignored".format(repr(e), logical_port_name)) + + # Set the periodic db update time after all the ports are processed + next_periodic_db_update_time = now + datetime.timedelta(seconds=dom_info_update_periodic_secs) + + self.log_notice("Stop DOM thermal monitoring loop") diff --git a/sonic-xcvrd/xcvrd/dom/utilities/dom_sensor/db_utils.py b/sonic-xcvrd/xcvrd/dom/utilities/dom_sensor/db_utils.py index e5c38363e..323dad1a6 100644 --- a/sonic-xcvrd/xcvrd/dom/utilities/dom_sensor/db_utils.py +++ b/sonic-xcvrd/xcvrd/dom/utilities/dom_sensor/db_utils.py @@ -24,6 +24,19 @@ def __init__(self, sfp_obj_dict, port_mapping, xcvr_table_helper, task_stopping_ self.dom_utils = DOMUtils(self.sfp_obj_dict, logger) self.logger = logger + def post_port_dom_temperature_info_to_db(self, logical_port_name, db_cache=None): + asic_index = self.port_mapping.get_asic_id_for_logical_port(logical_port_name) + if asic_index is None: + self.logger.log_error(f"Post port dom sensor info to db failed for {logical_port_name} " + "as no asic index found") + return + + return self.post_diagnostic_values_to_db(logical_port_name, + self.xcvr_table_helper.get_dom_temperature_tbl(asic_index), + self.dom_utils.get_transceiver_dom_temperature, + db_cache=db_cache, + beautify_func=self._beautify_dom_info_dict) + def post_port_dom_sensor_info_to_db(self, logical_port_name, db_cache=None): asic_index = self.port_mapping.get_asic_id_for_logical_port(logical_port_name) if asic_index is None: diff --git a/sonic-xcvrd/xcvrd/dom/utilities/dom_sensor/utils.py b/sonic-xcvrd/xcvrd/dom/utilities/dom_sensor/utils.py index 5f56bcb3b..f305cfe36 100644 --- a/sonic-xcvrd/xcvrd/dom/utilities/dom_sensor/utils.py +++ b/sonic-xcvrd/xcvrd/dom/utilities/dom_sensor/utils.py @@ -7,6 +7,14 @@ def __init__(self, sfp_obj_dict, logger): self.sfp_obj_dict = sfp_obj_dict self.logger = logger + def get_transceiver_dom_temperature(self, physical_port): + try: + return { + 'temperature': self.sfp_obj_dict[physical_port].get_temperature(), + } + except (NotImplementedError): + return {} + def get_transceiver_dom_sensor_real_value(self, physical_port): try: return self.sfp_obj_dict[physical_port].get_transceiver_dom_real_value() diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index 5e35f95d9..d88f7d63d 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -28,7 +28,7 @@ from .xcvrd_utilities import sfp_status_helper from .sff_mgr import SffManagerTask - from .dom.dom_mgr import DomInfoUpdateTask + from .dom.dom_mgr import DomThermalInfoUpdateTask, DomInfoUpdateTask from .cmis.cmis_manager_task import CmisManagerTask from .xcvrd_utilities.xcvr_table_helper import * from .xcvrd_utilities import port_event_helper @@ -577,6 +577,7 @@ def task_worker(self, stopping_event, sfp_error_event): common.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_dom_temperature_tbl(asic_index), self.xcvr_table_helper.get_dom_flag_tbl(asic_index), self.xcvr_table_helper.get_dom_flag_change_count_tbl(asic_index), self.xcvr_table_helper.get_dom_flag_set_time_tbl(asic_index), @@ -620,6 +621,7 @@ def task_worker(self, stopping_event, sfp_error_event): common.del_port_sfp_dom_info_from_db(logical_port, self.port_mapping, [ self.xcvr_table_helper.get_dom_tbl(asic_index), + self.xcvr_table_helper.get_dom_temperature_tbl(asic_index), self.xcvr_table_helper.get_dom_flag_tbl(asic_index), self.xcvr_table_helper.get_dom_flag_change_count_tbl(asic_index), self.xcvr_table_helper.get_dom_flag_set_time_tbl(asic_index), @@ -729,6 +731,7 @@ 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), + self.xcvr_table_helper.get_dom_temperature_tbl(port_change_event.asic_id), self.xcvr_table_helper.get_dom_flag_tbl(port_change_event.asic_id), self.xcvr_table_helper.get_dom_flag_change_count_tbl(port_change_event.asic_id), self.xcvr_table_helper.get_dom_flag_set_time_tbl(port_change_event.asic_id), @@ -853,12 +856,13 @@ def update_log_level(self): class DaemonXcvrd(daemon_base.DaemonBase): - def __init__(self, log_identifier, skip_cmis_mgr=False, enable_sff_mgr=False): + def __init__(self, log_identifier, skip_cmis_mgr=False, enable_sff_mgr=False, dom_temperature_poll_interval=None): super(DaemonXcvrd, self).__init__(log_identifier, enable_runtime_log_config=True) self.stop_event = threading.Event() self.sfp_error_event = threading.Event() self.skip_cmis_mgr = skip_cmis_mgr self.enable_sff_mgr = enable_sff_mgr + self.dom_temperature_poll_interval = dom_temperature_poll_interval self.namespaces = [''] self.threads = [] self.sfp_obj_dict = {} @@ -1077,6 +1081,7 @@ def deinit(self): common.del_port_sfp_dom_info_from_db(logical_port_name, port_mapping_data, [ intf_tbl, self.xcvr_table_helper.get_dom_tbl(asic_index), + self.xcvr_table_helper.get_dom_temperature_tbl(asic_index), self.xcvr_table_helper.get_dom_flag_tbl(asic_index), self.xcvr_table_helper.get_dom_flag_change_count_tbl(asic_index), self.xcvr_table_helper.get_dom_flag_set_time_tbl(asic_index), @@ -1133,6 +1138,14 @@ def run(self): dom_info_update.start() self.threads.append(dom_info_update) + # Start the dom thermal sensor info update thread + dom_thermal_info_update = None + if self.dom_temperature_poll_interval is not None: + dom_thermal_info_update = DomThermalInfoUpdateTask(self.namespaces, port_mapping_data, self.sfp_obj_dict, self.stop_event, + self.dom_temperature_poll_interval) + dom_thermal_info_update.start() + self.threads.append(dom_thermal_info_update) + # Start the sfp state info update thread sfp_state_update = SfpStateUpdateTask(self.namespaces, port_mapping_data, self.sfp_obj_dict, self.stop_event, self.sfp_error_event) sfp_state_update.start() @@ -1175,6 +1188,11 @@ def run(self): if dom_info_update.is_alive(): dom_info_update.join() + # Stop the dom thermal sensor info update thread + if dom_thermal_info_update is not None: + if dom_thermal_info_update.is_alive(): + dom_thermal_info_update.join() + # Stop the sfp state info update thread if sfp_state_update.is_alive(): sfp_state_update.raise_exception() @@ -1200,9 +1218,11 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument('--skip_cmis_mgr', action='store_true') parser.add_argument('--enable_sff_mgr', action='store_true') + parser.add_argument('--dom_temperature_poll_interval', default=None, type=int) args = parser.parse_args() - xcvrd = DaemonXcvrd(SYSLOG_IDENTIFIER, args.skip_cmis_mgr, args.enable_sff_mgr) + xcvrd = DaemonXcvrd(SYSLOG_IDENTIFIER, args.skip_cmis_mgr, args.enable_sff_mgr, + args.dom_temperature_poll_interval) xcvrd.run() diff --git a/sonic-xcvrd/xcvrd/xcvrd_utilities/xcvr_table_helper.py b/sonic-xcvrd/xcvrd/xcvrd_utilities/xcvr_table_helper.py index 36cb38140..71d62b701 100644 --- a/sonic-xcvrd/xcvrd/xcvrd_utilities/xcvr_table_helper.py +++ b/sonic-xcvrd/xcvrd/xcvrd_utilities/xcvr_table_helper.py @@ -16,6 +16,7 @@ TRANSCEIVER_DOM_FLAG_SET_TIME_TABLE = 'TRANSCEIVER_DOM_FLAG_SET_TIME' TRANSCEIVER_DOM_FLAG_CLEAR_TIME_TABLE = 'TRANSCEIVER_DOM_FLAG_CLEAR_TIME' TRANSCEIVER_DOM_THRESHOLD_TABLE = 'TRANSCEIVER_DOM_THRESHOLD' +TRANSCEIVER_DOM_TEMPERATURE_TABLE = 'TRANSCEIVER_DOM_TEMPERATURE' TRANSCEIVER_STATUS_TABLE = 'TRANSCEIVER_STATUS' TRANSCEIVER_STATUS_FLAG_TABLE = 'TRANSCEIVER_STATUS_FLAG' TRANSCEIVER_STATUS_FLAG_CHANGE_COUNT_TABLE = 'TRANSCEIVER_STATUS_FLAG_CHANGE_COUNT' @@ -58,6 +59,7 @@ def __init__(self, namespaces): self.state_db = {} self.appl_db = {} self.cfg_db = {} + self.dom_temperature_tbl = {} self.dom_flag_tbl = {} self.dom_flag_change_count_tbl = {} self.dom_flag_set_time_tbl = {} @@ -84,6 +86,7 @@ def __init__(self, namespaces): self.dom_flag_set_time_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_DOM_FLAG_SET_TIME_TABLE) self.dom_flag_clear_time_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_DOM_FLAG_CLEAR_TIME_TABLE) self.dom_threshold_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_DOM_THRESHOLD_TABLE) + self.dom_temperature_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_DOM_TEMPERATURE_TABLE) self.status_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_STATUS_TABLE) self.status_flag_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_STATUS_FLAG_TABLE) self.status_flag_change_count_tbl[asic_id] = swsscommon.Table(self.state_db[asic_id], TRANSCEIVER_STATUS_FLAG_CHANGE_COUNT_TABLE) @@ -126,6 +129,9 @@ def get_dom_flag_clear_time_tbl(self, asic_id): def get_dom_threshold_tbl(self, asic_id): return self.dom_threshold_tbl[asic_id] + def get_dom_temperature_tbl(self, asic_id): + return self.dom_temperature_tbl[asic_id] + def get_status_tbl(self, asic_id): return self.status_tbl[asic_id]