From 068bcccf1f3057607b8f37709033d7f44a6ff844 Mon Sep 17 00:00:00 2001 From: vdahiya12 <67608553+vdahiya12@users.noreply.github.com> Date: Wed, 17 Feb 2021 18:09:59 -0800 Subject: [PATCH] [xcvrd] Store mux_cable telemetry data in State DB (#148) * [xcvrd] adding mux_cable data for sonic-telemetry inside state db Summary: This PR provides the necessary infrastructure to initialize the mux_cable info and static tables and post them within state db as part of xcvrd. The data is posted every 60 secs and streaming telemetry can utilize this info. Approach Added changes in the sonic_xcvrd directory of sonic-platform-daemons What is the motivation for this PR? To add the necessary infrastructure for Credo Y cable support for posting streaming telemetry data inside state-db Signed-off-by: vaibhav-dahiya --- sonic-xcvrd/tests/test_xcvrd.py | 110 +++- sonic-xcvrd/xcvrd/xcvrd.py | 11 +- .../xcvrd/xcvrd_utilities/y_cable_helper.py | 582 +++++++++++++++++- 3 files changed, 681 insertions(+), 22 deletions(-) diff --git a/sonic-xcvrd/tests/test_xcvrd.py b/sonic-xcvrd/tests/test_xcvrd.py index 724b01e7bae9..fbc9b0f7a7ce 100644 --- a/sonic-xcvrd/tests/test_xcvrd.py +++ b/sonic-xcvrd/tests/test_xcvrd.py @@ -69,7 +69,7 @@ def test_xcvrd_helper_class_run(self): def test_post_port_dom_info_to_db(self): logical_port_name = "Ethernet0" stop_event = threading.Event() - dom_tbl = Table("state_db", "dom_info_tbl") + dom_tbl = Table("STATE_DB", TRANSCEIVER_DOM_SENSOR_TABLE) post_port_dom_info_to_db(logical_port_name, dom_tbl, stop_event) @patch('xcvrd.xcvrd.logical_port_name_to_physical_port_list', MagicMock(return_value=[0])) @@ -77,8 +77,8 @@ def test_post_port_dom_info_to_db(self): def test_del_port_sfp_dom_info_from_db(self): logical_port_name = "Ethernet0" stop_event = threading.Event() - dom_tbl = Table("state_db", "dom_info_tbl") - init_tbl = Table("state_db", "init_info_tbl") + 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, init_tbl, dom_tbl) @patch('xcvrd.xcvrd.logical_port_name_to_physical_port_list', MagicMock(return_value=[0])) @@ -106,7 +106,7 @@ def test_del_port_sfp_dom_info_from_db(self): def test_post_port_dom_threshold_info_to_db(self): logical_port_name = "Ethernet0" stop_event = threading.Event() - dom_tbl = Table("state_db", "dom_info_tbl") + dom_tbl = Table("STATE_DB", TRANSCEIVER_DOM_SENSOR_TABLE) post_port_dom_threshold_info_to_db(logical_port_name, dom_tbl, stop_event) @patch('xcvrd.xcvrd.logical_port_name_to_physical_port_list', MagicMock(return_value=[0])) @@ -132,7 +132,7 @@ def test_post_port_dom_threshold_info_to_db(self): def test_post_port_sfp_info_to_db(self): logical_port_name = "Ethernet0" stop_event = threading.Event() - dom_tbl = Table("state_db", "dom_info_tbl") + dom_tbl = Table("STATE_DB", TRANSCEIVER_DOM_SENSOR_TABLE) transceiver_dict = {} post_port_sfp_info_to_db(logical_port_name, dom_tbl, transceiver_dict, stop_event) @@ -215,3 +215,103 @@ def test_post_port_sfp_dom_info_to_db(self): def test_init_port_sfp_status_tbl(self): stop_event = threading.Event() init_port_sfp_status_tbl(stop_event) + + @patch('xcvrd.xcvrd_utilities.y_cable_helper.y_cable_platform_sfputil', MagicMock(return_value=[0])) + @patch('y_cable_helper.logical_port_name_to_physical_port_list', MagicMock(return_value=[0])) + @patch('y_cable_helper._wrapper_get_presence', MagicMock(return_value=True)) + @patch('y_cable_helper.get_muxcable_info', MagicMock(return_value={'tor_active': 'self', + 'mux_direction': 'self', + 'manual_switch_count': '7', + 'auto_switch_count': '71', + 'link_status_self': 'up', + 'link_status_peer': 'up', + 'link_status_nic': 'up', + 'nic_lane1_active': 'True', + 'nic_lane2_active': 'True', + 'nic_lane3_active': 'True', + 'nic_lane4_active': 'True', + 'self_eye_height_lane1': '500', + 'self_eye_height_lane2': '510', + 'peer_eye_height_lane1': '520', + 'peer_eye_height_lane2': '530', + 'nic_eye_height_lane1': '742', + 'nic_eye_height_lane2': '750', + 'internal_temperature': '28', + 'internal_voltage': '3.3', + 'nic_temperature': '20', + 'nic_voltage': '2.7', + 'build_slot1_nic': 'MS', + 'build_slot2_nic': 'MS', + 'version_slot1_nic': '1.7', + 'version_slot2_nic': '1.7', + 'run_slot1_nic': 'True', + 'run_slot2_nic': 'False', + 'commit_slot1_nic': 'True', + 'commit_slot2_nic': 'False', + 'empty_slot1_nic': 'True', + 'empty_slot2_nic': 'False', + 'build_slot1_tor1': 'MS', + 'build_slot2_tor1': 'MS', + 'version_slot1_tor1': '1.7', + 'version_slot2_tor1': '1.7', + 'run_slot1_tor1': 'True', + 'run_slot2_tor1': 'False', + 'commit_slot1_tor1': 'True', + 'commit_slot2_tor1': 'False', + 'empty_slot1_tor1': 'True', + 'empty_slot2_tor1': 'False', + 'build_slot1_tor2': 'MS', + 'build_slot2_tor2': 'MS', + 'version_slot1_tor2': '1.7', + 'version_slot2_tor2': '1.7', + 'run_slot1_tor2': 'True', + 'run_slot2_tor2': 'False', + 'commit_slot1_tor2': 'True', + 'commit_slot2_tor2': 'False', + 'empty_slot1_tor2': 'True', + 'empty_slot2_tor2': 'False'})) + def test_post_port_mux_info_to_db(self): + logical_port_name = "Ethernet0" + mux_tbl = Table("STATE_DB", y_cable_helper.MUX_CABLE_INFO_TABLE) + rc = post_port_mux_info_to_db(logical_port_name, mux_tbl) + assert(rc != -1) + + @patch('xcvrd.xcvrd_utilities.y_cable_helper.y_cable_platform_sfputil', MagicMock(return_value=[0])) + @patch('y_cable_helper.logical_port_name_to_physical_port_list', MagicMock(return_value=[0])) + @patch('y_cable_helper._wrapper_get_presence', MagicMock(return_value=True)) + @patch('y_cable_helper.get_muxcable_static_info', MagicMock(return_value={'read_side': 'self', + 'nic_lane1_precursor1': '1', + 'nic_lane1_precursor2': '-7', + 'nic_lane1_maincursor': '-1', + 'nic_lane1_postcursor1': '11', + 'nic_lane1_postcursor2': '11', + 'nic_lane2_precursor1': '12', + 'nic_lane2_precursor2': '7', + 'nic_lane2_maincursor': '7', + 'nic_lane2_postcursor1': '7', + 'nic_lane2_postcursor2': '7', + 'tor_self_lane1_precursor1': '17', + 'tor_self_lane1_precursor2': '17', + 'tor_self_lane1_maincursor': '17', + 'tor_self_lane1_postcursor1': '17', + 'tor_self_lane1_postcursor2': '17', + 'tor_self_lane2_precursor1': '7', + 'tor_self_lane2_precursor2': '7', + 'tor_self_lane2_maincursor': '7', + 'tor_self_lane2_postcursor1': '7', + 'tor_self_lane2_postcursor2': '7', + 'tor_peer_lane1_precursor1': '7', + 'tor_peer_lane1_precursor2': '7', + 'tor_peer_lane1_maincursor': '17', + 'tor_peer_lane1_postcursor1': '7', + 'tor_peer_lane1_postcursor2': '17', + 'tor_peer_lane2_precursor1': '7', + 'tor_peer_lane2_precursor2': '7', + 'tor_peer_lane2_maincursor': '17', + 'tor_peer_lane2_postcursor1': '7', + 'tor_peer_lane2_postcursor2': '17'})) + def test_post_port_mux_static_info_to_db(self): + logical_port_name = "Ethernet0" + mux_tbl = Table("STATE_DB", y_cable_helper.MUX_CABLE_STATIC_INFO_TABLE) + rc = post_port_mux_static_info_to_db(logical_port_name, mux_tbl) + assert(rc != -1) diff --git a/sonic-xcvrd/xcvrd/xcvrd.py b/sonic-xcvrd/xcvrd/xcvrd.py index fa45779bc384..fdac852416b8 100644 --- a/sonic-xcvrd/xcvrd/xcvrd.py +++ b/sonic-xcvrd/xcvrd/xcvrd.py @@ -832,11 +832,12 @@ def __init__(self): self.task_thread = None self.task_stopping_event = threading.Event() - def task_worker(self): + def task_worker(self, y_cable_presence): helper_logger.log_info("Start DOM monitoring loop") # Connect to STATE_DB and create transceiver dom info table state_db, dom_tbl, status_tbl = {}, {}, {} + mux_tbl = {} # Get the namespaces in the platform namespaces = multi_asic.get_front_end_namespaces() @@ -859,14 +860,16 @@ def task_worker(self): if not detect_port_in_error_status(logical_port_name, status_tbl[asic_index]): post_port_dom_info_to_db(logical_port_name, dom_tbl[asic_index], self.task_stopping_event) post_port_dom_threshold_info_to_db(logical_port_name, dom_tbl[asic_index], self.task_stopping_event) + if y_cable_presence[0] is True: + y_cable_helper.check_identifier_presence_and_update_mux_info_entry(state_db, mux_tbl, asic_index, logical_port_name) helper_logger.log_info("Stop DOM monitoring loop") - def task_run(self): + def task_run(self, y_cable_presence): if self.task_stopping_event.is_set(): return - self.task_thread = threading.Thread(target=self.task_worker) + self.task_thread = threading.Thread(target=self.task_worker, args=(y_cable_presence,)) self.task_thread.start() def task_stop(self): @@ -1325,7 +1328,7 @@ def run(self): # Start the dom sensor info update thread dom_info_update = DomInfoUpdateTask() - dom_info_update.task_run() + dom_info_update.task_run(self.y_cable_presence) # Start the sfp state info update process sfp_state_update = SfpStateUpdateTask() diff --git a/sonic-xcvrd/xcvrd/xcvrd_utilities/y_cable_helper.py b/sonic-xcvrd/xcvrd/xcvrd_utilities/y_cable_helper.py index a729fc289531..96424f6f37a7 100644 --- a/sonic-xcvrd/xcvrd/xcvrd_utilities/y_cable_helper.py +++ b/sonic-xcvrd/xcvrd/xcvrd_utilities/y_cable_helper.py @@ -3,15 +3,13 @@ helper utlities configuring y_cable for xcvrd daemon """ -try: - import threading +import threading +import time - from sonic_py_common import daemon_base, logger - from sonic_py_common import multi_asic - from sonic_y_cable import y_cable - from swsscommon import swsscommon -except ImportError as e: - raise ImportError(str(e) + " - required module not found") +from sonic_py_common import daemon_base, logger +from sonic_py_common import multi_asic +from sonic_y_cable import y_cable +from swsscommon import swsscommon SELECT_TIMEOUT = 1000 @@ -54,6 +52,9 @@ Y_CABLE_STATUS_TORB_ACTIVE } +MUX_CABLE_STATIC_INFO_TABLE = "MUX_CABLE_STATIC_INFO" +MUX_CABLE_INFO_TABLE = "MUX_CABLE_INFO" + # Find out the underneath physical port list by logical name @@ -79,7 +80,8 @@ def _wrapper_get_presence(physical_port): # Delete port from Y cable status table def delete_port_from_y_cable_table(logical_port_name, y_cable_tbl): - y_cable_tbl._del(logical_port_name) + if y_cable_tbl is not None: + y_cable_tbl._del(logical_port_name) def update_table_mux_status_for_response_tbl(table_name, status, logical_port_name): @@ -269,7 +271,7 @@ def read_y_cable_and_update_statedb_port_tbl(logical_port_name, mux_config_tbl): "Error: Retreived multiple ports for a Y cable port {}".format(logical_port_name)) -def check_identifier_presence_and_update_mux_table_entry(state_db, port_tbl, y_cable_tbl, asic_index, logical_port_name, y_cable_presence): +def check_identifier_presence_and_update_mux_table_entry(state_db, port_tbl, y_cable_tbl, static_tbl, mux_tbl, asic_index, logical_port_name, y_cable_presence): (status, fvs) = port_tbl[asic_index].get(logical_port_name) if status is False: @@ -285,10 +287,14 @@ def check_identifier_presence_and_update_mux_table_entry(state_db, port_tbl, y_c if val == "true": y_cable_asic_table = y_cable_tbl.get(asic_index, None) - if y_cable_presence[0] is True and y_cable_asic_table is not None: + mux_asic_table = mux_tbl.get(asic_index, None) + static_mux_asic_table = static_tbl.get(asic_index, None) + if y_cable_presence[0] is True and y_cable_asic_table is not None and mux_asic_table is not None and static_mux_asic_table is not None: # fill in the newly found entry read_y_cable_and_update_statedb_port_tbl( logical_port_name, y_cable_tbl[asic_index]) + post_port_mux_info_to_db(logical_port_name, mux_tbl[asic_index]) + post_port_mux_static_info_to_db(logical_port_name, static_tbl[asic_index]) else: # first create the state db y cable table and then fill in the entry @@ -301,14 +307,19 @@ def check_identifier_presence_and_update_mux_table_entry(state_db, port_tbl, y_c "STATE_DB", namespace) y_cable_tbl[asic_id] = swsscommon.Table( state_db[asic_id], swsscommon.STATE_HW_MUX_CABLE_TABLE_NAME) + static_tbl[asic_id] = swsscommon.Table(state_db[asic_id], MUX_CABLE_STATIC_INFO_TABLE) + mux_tbl[asic_id] = swsscommon.Table(state_db[asic_id], MUX_CABLE_INFO_TABLE) # fill the newly found entry read_y_cable_and_update_statedb_port_tbl( logical_port_name, y_cable_tbl[asic_index]) + post_port_mux_info_to_db(logical_port_name, mux_tbl[asic_index]) + post_port_mux_static_info_to_db(logical_port_name, static_tbl[asic_index]) def check_identifier_presence_and_delete_mux_table_entry(state_db, port_tbl, asic_index, logical_port_name, y_cable_presence, delete_change_event): y_cable_tbl = {} + static_tbl, mux_tbl = {}, {} # if there is No Y cable do not do anything here if y_cable_presence[0] is False: @@ -334,9 +345,15 @@ def check_identifier_presence_and_delete_mux_table_entry(state_db, port_tbl, asi "STATE_DB", namespace) y_cable_tbl[asic_id] = swsscommon.Table( state_db[asic_id], swsscommon.STATE_HW_MUX_CABLE_TABLE_NAME) + static_tbl[asic_id] = swsscommon.Table(state_db[asic_id], MUX_CABLE_STATIC_INFO_TABLE) + mux_tbl[asic_id] = swsscommon.Table(state_db[asic_id], MUX_CABLE_INFO_TABLE) # fill the newly found entry delete_port_from_y_cable_table( logical_port_name, y_cable_tbl[asic_index]) + delete_port_from_y_cable_table( + logical_port_name, static_tbl[asic_index]) + delete_port_from_y_cable_table( + logical_port_name, mux_tbl[asic_index]) delete_change_event[:] = [True] @@ -345,6 +362,7 @@ def init_ports_status_for_y_cable(platform_sfp, platform_chassis, y_cable_presen global y_cable_platform_chassis # Connect to CONFIG_DB and create port status table inside state_db config_db, state_db, port_tbl, y_cable_tbl = {}, {}, {}, {} + static_tbl, mux_tbl = {}, {} port_table_keys = {} y_cable_platform_sfputil = platform_sfp @@ -374,7 +392,7 @@ def init_ports_status_for_y_cable(platform_sfp, platform_chassis, y_cable_presen if logical_port_name in port_table_keys[asic_index]: check_identifier_presence_and_update_mux_table_entry( - state_db, port_tbl, y_cable_tbl, asic_index, logical_port_name, y_cable_presence) + state_db, port_tbl, y_cable_tbl, static_tbl, mux_tbl, asic_index, logical_port_name, y_cable_presence) else: # This port does not exist in Port table of config but is present inside # logical_ports after loading the port_mappings from port_config_file @@ -386,6 +404,7 @@ def init_ports_status_for_y_cable(platform_sfp, platform_chassis, y_cable_presen def change_ports_status_for_y_cable_change_event(port_dict, y_cable_presence, stop_event=threading.Event()): # Connect to CONFIG_DB and create port status table inside state_db config_db, state_db, port_tbl, y_cable_tbl = {}, {}, {}, {} + static_tbl, mux_tbl = {}, {} port_table_keys = {} delete_change_event = [False] @@ -400,6 +419,8 @@ def change_ports_status_for_y_cable_change_event(port_dict, y_cable_presence, st # Init PORT_STATUS table if ports are on Y cable and an event is received for key, value in port_dict.items(): + if stop_event.is_set(): + break logical_port_list = y_cable_platform_sfputil.get_physical_to_logical(int(key)) if logical_port_list is None: helper_logger.log_warning("Got unknown FP port index {}, ignored".format(key)) @@ -417,7 +438,7 @@ def change_ports_status_for_y_cable_change_event(port_dict, y_cable_presence, st if value == SFP_STATUS_INSERTED: helper_logger.log_info("Got SFP inserted event") check_identifier_presence_and_update_mux_table_entry( - state_db, port_tbl, y_cable_tbl, asic_index, logical_port_name, y_cable_presence) + state_db, port_tbl, y_cable_tbl, static_tbl, mux_tbl, asic_index, logical_port_name, y_cable_presence) elif value == SFP_STATUS_REMOVED or value in errors_block_eeprom_reading: check_identifier_presence_and_delete_mux_table_entry( state_db, port_tbl, asic_index, logical_port_name, y_cable_presence, delete_change_event) @@ -446,6 +467,7 @@ def delete_ports_status_for_y_cable(): state_db, port_tbl, y_cable_tbl = {}, {}, {} y_cable_tbl_keys = {} + static_tbl, mux_tbl = {}, {} namespaces = multi_asic.get_front_end_namespaces() for namespace in namespaces: asic_id = multi_asic.get_asic_index_from_namespace(namespace) @@ -453,6 +475,8 @@ def delete_ports_status_for_y_cable(): y_cable_tbl[asic_id] = swsscommon.Table( state_db[asic_id], swsscommon.STATE_HW_MUX_CABLE_TABLE_NAME) y_cable_tbl_keys[asic_id] = y_cable_tbl[asic_id].getKeys() + static_tbl[asic_id] = swsscommon.Table(state_db[asic_id], MUX_CABLE_STATIC_INFO_TABLE) + mux_tbl[asic_id] = swsscommon.Table(state_db[asic_id], MUX_CABLE_INFO_TABLE) # delete PORTS on Y cable table if ports on Y cable logical_port_list = y_cable_platform_sfputil.logical @@ -468,6 +492,532 @@ def delete_ports_status_for_y_cable(): if logical_port_name in y_cable_tbl_keys[asic_index]: delete_port_from_y_cable_table( logical_port_name, y_cable_tbl[asic_index]) + delete_port_from_y_cable_table( + logical_port_name, static_tbl[asic_index]) + delete_port_from_y_cable_table( + logical_port_name, mux_tbl[asic_index]) + + +def check_identifier_presence_and_update_mux_info_entry(state_db, mux_tbl, asic_index, logical_port_name): + + # Get the namespaces in the platform + config_db, port_tbl = {}, {} + namespaces = multi_asic.get_front_end_namespaces() + for namespace in namespaces: + asic_id = multi_asic.get_asic_index_from_namespace(namespace) + config_db[asic_id] = daemon_base.db_connect("CONFIG_DB", namespace) + port_tbl[asic_id] = swsscommon.Table(config_db[asic_id], "PORT") + + (status, fvs) = port_tbl[asic_index].get(logical_port_name) + + if status is False: + helper_logger.log_warning( + "Could not retreive fieldvalue pairs for {}, inside config_db".format(logical_port_name)) + return + + else: + # Convert list of tuples to a dictionary + mux_table_dict = dict(fvs) + if "mux_cable" in mux_table_dict: + val = mux_table_dict.get("mux_cable", None) + if val == "true": + + if mux_tbl.get(asic_index, None) is not None: + # fill in the newly found entry + post_port_mux_info_to_db(logical_port_name, mux_tbl[asic_index]) + + else: + # first create the state db y cable table and then fill in the entry + namespaces = multi_asic.get_front_end_namespaces() + for namespace in namespaces: + asic_id = multi_asic.get_asic_index_from_namespace( + namespace) + mux_tbl[asic_id] = swsscommon.Table(state_db[asic_id], MUX_CABLE_INFO_TABLE) + # fill the newly found entry + post_port_mux_info_to_db(logical_port_name, mux_tbl[asic_index]) + + +def get_firmware_dict(physical_port, target, side, mux_info_dict): + + result = y_cable.get_firmware_version(physical_port, target) + + if result is not None and isinstance(result, dict): + mux_info_dict[("build_slot1_{}".format(side))] = result.get("build_slot1", None) + mux_info_dict[("version_slot1_{}".format(side))] = result.get("version_slot1", None) + mux_info_dict[("build_slot2_{}".format(side))] = result.get("build_slot2", None) + mux_info_dict[("version_slot2_{}".format(side))] = result.get("version_slot2", None) + mux_info_dict[("run_slot1_{}".format(side))] = result.get("run_slot1", None) + mux_info_dict[("run_slot2_{}".format(side))] = result.get("run_slot2", None) + mux_info_dict[("commit_slot1_{}".format(side))] = result.get("commit_slot1", None) + mux_info_dict[("commit_slot2_{}".format(side))] = result.get("commit_slot2", None) + mux_info_dict[("empty_slot1_{}".format(side))] = result.get("empty_slot1", None) + mux_info_dict[("empty_slot2_{}".format(side))] = result.get("empty_slot2", None) + else: + mux_info_dict[("build_slot1_{}".format(side))] = "N/A" + mux_info_dict[("version_slot1_{}".format(side))] = "N/A" + mux_info_dict[("build_slot2_{}".format(side))] = "N/A" + mux_info_dict[("version_slot2_{}".format(side))] = "N/A" + mux_info_dict[("run_slot1_{}".format(side))] = "N/A" + mux_info_dict[("run_slot2_{}".format(side))] = "N/A" + mux_info_dict[("commit_slot1_{}".format(side))] = "N/A" + mux_info_dict[("commit_slot2_{}".format(side))] = "N/A" + mux_info_dict[("empty_slot1_{}".format(side))] = "N/A" + mux_info_dict[("empty_slot2_{}".format(side))] = "N/A" + + +def get_muxcable_info(physical_port, logical_port_name): + + mux_info_dict = {} + y_cable_tbl, state_db = {}, {} + + namespaces = multi_asic.get_front_end_namespaces() + for namespace in namespaces: + asic_id = multi_asic.get_asic_index_from_namespace(namespace) + state_db[asic_id] = daemon_base.db_connect("STATE_DB", namespace) + y_cable_tbl[asic_id] = swsscommon.Table( + state_db[asic_id], swsscommon.STATE_HW_MUX_CABLE_TABLE_NAME) + + asic_index = y_cable_platform_sfputil.get_asic_id_for_logical_port( + logical_port_name) + if asic_index is None: + helper_logger.log_warning( + "Got invalid asic index for {}, ignored".format(logical_port_name)) + return -1 + + (status, fvs) = y_cable_tbl[asic_index].get(logical_port_name) + if status is False: + helper_logger.log_warning("Could not retreive fieldvalue pairs for {}, inside state_db table {}".format( + logical_port_name, y_cable_tbl[asic_index])) + return -1 + + mux_port_dict = dict(fvs) + read_side = int(mux_port_dict.get("read_side")) + + active_side = y_cable.check_active_linked_tor_side(physical_port) + + if active_side is None or active_side == y_cable.EEPROM_ERROR: + tor_active = 'unknown' + elif read_side == active_side and (active_side == 1 or active_side == 2): + tor_active = 'active' + elif read_side != active_side and (active_side == 1 or active_side == 2): + tor_active = 'standby' + else: + tor_active = 'unknown' + + mux_info_dict["tor_active"] = tor_active + + mux_dir_val = y_cable.check_mux_direction(physical_port) + if mux_dir_val is None or mux_dir_val == y_cable.EEPROM_ERROR: + mux_direction = 'unknown' + elif read_side == mux_dir_val and (active_side == 1 or active_side == 2): + mux_direction = 'self' + elif read_side != mux_dir_val and (active_side == 1 or active_side == 2): + mux_direction = 'peer' + else: + mux_direction = 'unknown' + + mux_info_dict["mux_direction"] = mux_direction + + manual_switch_cnt = y_cable.get_switch_count(physical_port, y_cable.SWITCH_COUNT_MANUAL) + auto_switch_cnt = y_cable.get_switch_count(physical_port, y_cable.SWITCH_COUNT_AUTO) + + if manual_switch_cnt is not y_cable.EEPROM_ERROR: + mux_info_dict["manual_switch_count"] = manual_switch_cnt + else: + mux_info_dict["manual_switch_count"] = "N/A" + + if auto_switch_cnt is not y_cable.EEPROM_ERROR: + mux_info_dict["auto_switch_count"] = auto_switch_cnt + else: + mux_info_dict["auto_switch_count"] = "N/A" + + lane_active = y_cable.check_if_nic_lanes_active(physical_port) + + if lane_active is not y_cable.EEPROM_ERROR: + if (lane_active & 0x1): + mux_info_dict["nic_lane1_active"] = "True" + else: + mux_info_dict["nic_lane1_active"] = "False" + + if ((lane_active >> 1) & 0x1): + mux_info_dict["nic_lane2_active"] = "True" + else: + mux_info_dict["nic_lane2_active"] = "False" + + if ((lane_active >> 2) & 0x1): + mux_info_dict["nic_lane3_active"] = "True" + else: + mux_info_dict["nic_lane3_active"] = "False" + + if ((lane_active >> 3) & 0x1): + mux_info_dict["nic_lane4_active"] = "True" + else: + mux_info_dict["nic_lane4_active"] = "False" + else: + mux_info_dict["nic_lane1_active"] = "N/A" + mux_info_dict["nic_lane2_active"] = "N/A" + mux_info_dict["nic_lane3_active"] = "N/A" + mux_info_dict["nic_lane4_active"] = "N/A" + + if read_side == 1: + eye_result_self = y_cable.get_eye_info(physical_port, 1) + eye_result_peer = y_cable.get_eye_info(physical_port, 2) + else: + eye_result_self = y_cable.get_eye_info(physical_port, 2) + eye_result_peer = y_cable.get_eye_info(physical_port, 1) + + eye_result_nic = y_cable.get_eye_info(physical_port, 3) + + if eye_result_self is not None and eye_result_self is not y_cable.EEPROM_ERROR and isinstance(eye_result_self, list): + mux_info_dict["self_eye_height_lane1"] = eye_result_self[0] + mux_info_dict["self_eye_height_lane2"] = eye_result_self[1] + else: + mux_info_dict["self_eye_height_lane1"] = "N/A" + mux_info_dict["self_eye_height_lane2"] = "N/A" + + if eye_result_peer is not None and eye_result_peer is not y_cable.EEPROM_ERROR and isinstance(eye_result_peer, list): + mux_info_dict["peer_eye_height_lane1"] = eye_result_peer[0] + mux_info_dict["peer_eye_height_lane2"] = eye_result_peer[1] + else: + mux_info_dict["peer_eye_height_lane1"] = "N/A" + mux_info_dict["peer_eye_height_lane2"] = "N/A" + + if eye_result_nic is not None and eye_result_nic is not y_cable.EEPROM_ERROR and isinstance(eye_result_nic, list): + mux_info_dict["nic_eye_height_lane1"] = eye_result_nic[0] + mux_info_dict["nic_eye_height_lane2"] = eye_result_nic[1] + else: + mux_info_dict["nic_eye_height_lane1"] = "N/A" + mux_info_dict["nic_eye_height_lane2"] = "N/A" + + if read_side == 1: + if y_cable.check_if_link_is_active_for_torA(physical_port): + mux_info_dict["link_status_self"] = "up" + else: + mux_info_dict["link_status_self"] = "down" + if y_cable.check_if_link_is_active_for_torB(physical_port): + mux_info_dict["link_status_peer"] = "up" + else: + mux_info_dict["link_status_peer"] = "down" + else: + if y_cable.check_if_link_is_active_for_torB(physical_port): + mux_info_dict["link_status_self"] = "up" + else: + mux_info_dict["link_status_self"] = "down" + if y_cable.check_if_link_is_active_for_torA(physical_port): + mux_info_dict["link_status_peer"] = "up" + else: + mux_info_dict["link_status_peer"] = "down" + + if y_cable.check_if_link_is_active_for_NIC(physical_port): + mux_info_dict["link_status_nic"] = "up" + else: + mux_info_dict["link_status_nic"] = "down" + + get_firmware_dict(physical_port, 0, "nic", mux_info_dict) + get_firmware_dict(physical_port, 1, "tor1", mux_info_dict) + get_firmware_dict(physical_port, 2, "tor2", mux_info_dict) + + res = y_cable.get_internal_voltage_temp(physical_port) + + if res is not y_cable.EEPROM_ERROR and isinstance(res, tuple): + mux_info_dict["internal_temperature"] = res[0] + mux_info_dict["internal_voltage"] = res[1] + else: + mux_info_dict["internal_temperature"] = "N/A" + mux_info_dict["internal_voltage"] = "N/A" + + res = y_cable.get_nic_voltage_temp(physical_port) + + if res is not y_cable.EEPROM_ERROR and isinstance(res, tuple): + mux_info_dict["nic_temperature"] = res[0] + mux_info_dict["nic_voltage"] = res[1] + else: + mux_info_dict["nic_temperature"] = "N/A" + mux_info_dict["nic_voltage"] = "N/A" + + return mux_info_dict + + +def get_muxcable_static_info(physical_port, logical_port_name): + + mux_static_info_dict = {} + y_cable_tbl, state_db = {}, {} + + namespaces = multi_asic.get_front_end_namespaces() + for namespace in namespaces: + asic_id = multi_asic.get_asic_index_from_namespace(namespace) + state_db[asic_id] = daemon_base.db_connect("STATE_DB", namespace) + y_cable_tbl[asic_id] = swsscommon.Table( + state_db[asic_id], swsscommon.STATE_HW_MUX_CABLE_TABLE_NAME) + + asic_index = y_cable_platform_sfputil.get_asic_id_for_logical_port( + logical_port_name) + if asic_index is None: + helper_logger.log_warning( + "Got invalid asic index for {}, ignored".format(logical_port_name)) + return -1 + + (status, fvs) = y_cable_tbl[asic_index].get(logical_port_name) + if status is False: + helper_logger.log_warning("Could not retreive fieldvalue pairs for {}, inside state_db table {}".format( + logical_port_name, y_cable_tbl[asic_index])) + return -1 + mux_port_dict = dict(fvs) + read_side = int(mux_port_dict.get("read_side")) + + if read_side == 1: + mux_static_info_dict["read_side"] = "tor1" + else: + mux_static_info_dict["read_side"] = "tor2" + + dummy_list = ["N/A", "N/A", "N/A", "N/A", "N/A"] + cursor_nic_values = [] + cursor_tor1_values = [] + cursor_tor2_values = [] + for i in range(1, 3): + cursor_values_nic = y_cable.get_target_cursor_values(physical_port, i, y_cable.TARGET_NIC) + if cursor_values_nic is not None and cursor_values_nic is not y_cable.EEPROM_ERROR and isinstance(cursor_values_nic, list): + cursor_nic_values.append(cursor_values_nic) + else: + cursor_nic_values.append(dummy_list) + cursor_values_tor1 = y_cable.get_target_cursor_values(physical_port, i, y_cable.TARGET_TOR1) + if cursor_values_tor1 is not None and cursor_values_tor1 is not y_cable.EEPROM_ERROR and isinstance(cursor_values_tor1, list): + cursor_tor1_values.append(cursor_values_tor1) + else: + cursor_tor1_values.append(dummy_list) + + cursor_values_tor2 = y_cable.get_target_cursor_values(physical_port, i, y_cable.TARGET_TOR2) + if cursor_values_tor2 is not None and cursor_values_tor2 is not y_cable.EEPROM_ERROR and isinstance(cursor_values_tor2, list): + cursor_tor2_values.append(cursor_values_tor2) + else: + cursor_tor2_values.append(dummy_list) + + for i in range(1, 3): + mux_static_info_dict[("nic_lane{}_precursor1".format(i))] = cursor_nic_values[i-1][0] + mux_static_info_dict[("nic_lane{}_precursor2".format(i))] = cursor_nic_values[i-1][1] + mux_static_info_dict[("nic_lane{}_maincursor".format(i))] = cursor_nic_values[i-1][2] + mux_static_info_dict[("nic_lane{}_postcursor1".format(i))] = cursor_nic_values[i-1][3] + mux_static_info_dict[("nic_lane{}_postcursor2".format(i))] = cursor_nic_values[i-1][4] + + if read_side == 1: + for i in range(1, 3): + mux_static_info_dict[("tor_self_lane{}_precursor1".format(i))] = cursor_tor1_values[i-1][0] + mux_static_info_dict[("tor_self_lane{}_precursor2".format(i))] = cursor_tor1_values[i-1][1] + mux_static_info_dict[("tor_self_lane{}_maincursor".format(i))] = cursor_tor1_values[i-1][2] + mux_static_info_dict[("tor_self_lane{}_postcursor1".format(i))] = cursor_tor1_values[i-1][3] + mux_static_info_dict[("tor_self_lane{}_postcursor2".format(i))] = cursor_tor1_values[i-1][4] + + for i in range(1, 3): + mux_static_info_dict[("tor_peer_lane{}_precursor1".format(i))] = cursor_tor2_values[i-1][0] + mux_static_info_dict[("tor_peer_lane{}_precursor2".format(i))] = cursor_tor2_values[i-1][1] + mux_static_info_dict[("tor_peer_lane{}_maincursor".format(i))] = cursor_tor2_values[i-1][2] + mux_static_info_dict[("tor_peer_lane{}_postcursor1".format(i))] = cursor_tor2_values[i-1][3] + mux_static_info_dict[("tor_peer_lane{}_postcursor2".format(i))] = cursor_tor2_values[i-1][4] + else: + for i in range(1, 3): + mux_static_info_dict[("tor_self_lane{}_precursor1".format(i))] = cursor_tor2_values[i-1][0] + mux_static_info_dict[("tor_self_lane{}_precursor2".format(i))] = cursor_tor2_values[i-1][1] + mux_static_info_dict[("tor_self_lane{}_maincursor".format(i))] = cursor_tor2_values[i-1][2] + mux_static_info_dict[("tor_self_lane{}_postcursor1".format(i))] = cursor_tor2_values[i-1][3] + mux_static_info_dict[("tor_self_lane{}_postcursor2".format(i))] = cursor_tor2_values[i-1][4] + + for i in range(1, 3): + mux_static_info_dict[("tor_peer_lane{}_precursor1".format(i))] = cursor_tor1_values[i-1][0] + mux_static_info_dict[("tor_peer_lane{}_precursor2".format(i))] = cursor_tor1_values[i-1][1] + mux_static_info_dict[("tor_peer_lane{}_maincursor".format(i))] = cursor_tor1_values[i-1][2] + mux_static_info_dict[("tor_peer_lane{}_postcursor1".format(i))] = cursor_tor1_values[i-1][3] + mux_static_info_dict[("tor_peer_lane{}_postcursor2".format(i))] = cursor_tor1_values[i-1][4] + + return mux_static_info_dict + + +def post_port_mux_info_to_db(logical_port_name, table): + + physical_port_list = 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 -1 + + if len(physical_port_list) > 1: + helper_logger.log_warning( + "Error: Retreived multiple ports for a Y cable port {}".format(logical_port_name)) + return -1 + + for physical_port in physical_port_list: + + if not _wrapper_get_presence(physical_port): + helper_logger.log_warning( + "Error: trying to post mux info without presence of port {}".format(logical_port_name)) + continue + + mux_info_dict = get_muxcable_info(physical_port, logical_port_name) + if mux_info_dict is not None and mux_info_dict is not -1: + #transceiver_dict[physical_port] = port_info_dict + fvs = swsscommon.FieldValuePairs( + [('tor_active', mux_info_dict["tor_active"]), + ('mux_direction', str(mux_info_dict["mux_direction"])), + ('manual_switch_count', str(mux_info_dict["manual_switch_count"])), + ('auto_switch_count', str(mux_info_dict["auto_switch_count"])), + ('link_status_self', mux_info_dict["link_status_self"]), + ('link_status_peer', mux_info_dict["link_status_peer"]), + ('link_status_nic', mux_info_dict["link_status_nic"]), + ('nic_lane1_active', mux_info_dict["nic_lane1_active"]), + ('nic_lane2_active', mux_info_dict["nic_lane2_active"]), + ('nic_lane3_active', mux_info_dict["nic_lane3_active"]), + ('nic_lane4_active', mux_info_dict["nic_lane4_active"]), + ('self_eye_height_lane1', str(mux_info_dict["self_eye_height_lane1"])), + ('self_eye_height_lane2', str(mux_info_dict["self_eye_height_lane2"])), + ('peer_eye_height_lane1', str(mux_info_dict["peer_eye_height_lane1"])), + ('peer_eye_height_lane2', str(mux_info_dict["peer_eye_height_lane1"])), + ('nic_eye_height_lane1', str(mux_info_dict["nic_eye_height_lane1"])), + ('nic_eye_height_lane2', str(mux_info_dict["nic_eye_height_lane2"])), + ('internal_temperature', str(mux_info_dict["internal_temperature"])), + ('internal_voltage', str(mux_info_dict["internal_voltage"])), + ('nic_temperature', str(mux_info_dict["nic_temperature"])), + ('nic_voltage', str(mux_info_dict["nic_voltage"])), + ('build_slot1_nic', str(mux_info_dict["build_slot1_nic"])), + ('build_slot2_nic', str(mux_info_dict["build_slot2_nic"])), + ('version_slot1_nic', str(mux_info_dict["version_slot1_nic"])), + ('version_slot2_nic', str(mux_info_dict["version_slot2_nic"])), + ('run_slot1_nic', str(mux_info_dict["run_slot1_nic"])), + ('run_slot2_nic', str(mux_info_dict["run_slot2_nic"])), + ('commit_slot1_nic', str(mux_info_dict["commit_slot1_nic"])), + ('commit_slot2_nic', str(mux_info_dict["commit_slot2_nic"])), + ('empty_slot1_nic', str(mux_info_dict["empty_slot1_nic"])), + ('empty_slot2_nic', str(mux_info_dict["empty_slot2_nic"])), + ('build_slot1_tor1', str(mux_info_dict["build_slot1_tor1"])), + ('build_slot2_tor1', str(mux_info_dict["build_slot2_tor1"])), + ('version_slot1_tor1', str(mux_info_dict["version_slot1_tor1"])), + ('version_slot2_tor1', str(mux_info_dict["version_slot2_tor1"])), + ('run_slot1_tor1', str(mux_info_dict["run_slot1_tor1"])), + ('run_slot2_tor1', str(mux_info_dict["run_slot2_tor1"])), + ('commit_slot1_tor1', str(mux_info_dict["commit_slot1_tor1"])), + ('commit_slot2_tor1', str(mux_info_dict["commit_slot2_tor1"])), + ('empty_slot1_tor1', str(mux_info_dict["empty_slot1_tor1"])), + ('empty_slot2_tor1', str(mux_info_dict["empty_slot2_tor1"])), + ('build_slot1_tor2', str(mux_info_dict["build_slot1_tor2"])), + ('build_slot2_tor2', str(mux_info_dict["build_slot2_tor2"])), + ('version_slot1_tor2', str(mux_info_dict["version_slot1_tor2"])), + ('version_slot2_tor2', str(mux_info_dict["version_slot2_tor2"])), + ('run_slot1_tor2', str(mux_info_dict["run_slot1_tor2"])), + ('run_slot2_tor2', str(mux_info_dict["run_slot2_tor2"])), + ('commit_slot1_tor2', str(mux_info_dict["commit_slot1_tor2"])), + ('commit_slot2_tor2', str(mux_info_dict["commit_slot2_tor2"])), + ('empty_slot1_tor2', str(mux_info_dict["empty_slot1_tor2"])), + ('empty_slot2_tor2', str(mux_info_dict["empty_slot2_tor2"])) + ]) + table.set(logical_port_name, fvs) + else: + return -1 + + +def post_port_mux_static_info_to_db(logical_port_name, static_table): + + physical_port_list = 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 -1 + + if len(physical_port_list) > 1: + helper_logger.log_warning( + "Error: Retreived multiple ports for a Y cable port {}".format(logical_port_name)) + return -1 + + for physical_port in physical_port_list: + + if not _wrapper_get_presence(physical_port): + continue + + mux_static_info_dict = get_muxcable_static_info(physical_port, logical_port_name) + + if mux_static_info_dict is not None and mux_static_info_dict is not -1: + #transceiver_dict[physical_port] = port_info_dict + fvs = swsscommon.FieldValuePairs( + [('read_side', mux_static_info_dict["read_side"]), + ('nic_lane1_precursor1', str(mux_static_info_dict["nic_lane1_precursor1"])), + ('nic_lane1_precursor2', str(mux_static_info_dict["nic_lane1_precursor2"])), + ('nic_lane1_maincursor', str(mux_static_info_dict["nic_lane1_maincursor"])), + ('nic_lane1_postcursor1', str(mux_static_info_dict["nic_lane1_postcursor1"])), + ('nic_lane1_postcursor2', str(mux_static_info_dict["nic_lane1_postcursor2"])), + ('nic_lane2_precursor1', str(mux_static_info_dict["nic_lane2_precursor1"])), + ('nic_lane2_precursor2', str(mux_static_info_dict["nic_lane2_precursor2"])), + ('nic_lane2_maincursor', str(mux_static_info_dict["nic_lane2_maincursor"])), + ('nic_lane2_postcursor1', str(mux_static_info_dict["nic_lane2_postcursor1"])), + ('nic_lane2_postcursor2', str(mux_static_info_dict["nic_lane2_postcursor2"])), + ('tor_self_lane1_precursor1', str(mux_static_info_dict["tor_self_lane1_precursor1"])), + ('tor_self_lane1_precursor2', str(mux_static_info_dict["tor_self_lane1_precursor2"])), + ('tor_self_lane1_maincursor', str(mux_static_info_dict["tor_self_lane1_maincursor"])), + ('tor_self_lane1_postcursor1', str(mux_static_info_dict["tor_self_lane1_postcursor1"])), + ('tor_self_lane1_postcursor2', str(mux_static_info_dict["tor_self_lane1_postcursor2"])), + ('tor_self_lane2_precursor1', str(mux_static_info_dict["tor_self_lane2_precursor1"])), + ('tor_self_lane2_precursor2', str(mux_static_info_dict["tor_self_lane2_precursor2"])), + ('tor_self_lane2_maincursor', str(mux_static_info_dict["tor_self_lane2_maincursor"])), + ('tor_self_lane2_postcursor1', str(mux_static_info_dict["tor_self_lane2_postcursor1"])), + ('tor_self_lane2_postcursor2', str(mux_static_info_dict["tor_self_lane2_postcursor2"])), + ('tor_peer_lane1_precursor1', str(mux_static_info_dict["tor_peer_lane1_precursor1"])), + ('tor_peer_lane1_precursor2', str(mux_static_info_dict["tor_peer_lane1_precursor2"])), + ('tor_peer_lane1_maincursor', str(mux_static_info_dict["tor_peer_lane1_maincursor"])), + ('tor_peer_lane1_postcursor1', str(mux_static_info_dict["tor_peer_lane1_postcursor1"])), + ('tor_peer_lane1_postcursor2', str(mux_static_info_dict["tor_peer_lane1_postcursor2"])), + ('tor_peer_lane2_precursor1', str(mux_static_info_dict["tor_peer_lane2_precursor1"])), + ('tor_peer_lane2_precursor2', str(mux_static_info_dict["tor_peer_lane2_precursor2"])), + ('tor_peer_lane2_maincursor', str(mux_static_info_dict["tor_peer_lane2_maincursor"])), + ('tor_peer_lane2_postcursor1', str(mux_static_info_dict["tor_peer_lane2_postcursor1"])), + ('tor_peer_lane2_postcursor2', str(mux_static_info_dict["tor_peer_lane2_postcursor2"])) + ]) + static_table.set(logical_port_name, fvs) + else: + return -1 + + +def post_mux_static_info_to_db(is_warm_start, stop_event=threading.Event()): + # Connect to STATE_DB and create transceiver mux/static info tables + state_db, static_tbl = {}, {} + + # Get the namespaces in the platform + namespaces = multi_asic.get_front_end_namespaces() + for namespace in namespaces: + asic_id = multi_asic.get_asic_index_from_namespace(namespace) + state_db[asic_id] = daemon_base.db_connect("STATE_DB", namespace) + static_tbl[asic_id] = swsscommon.Table(state_db[asic_id], MUX_CABLE_STATIC_INFO_TABLE) + + # Post all the current interface dom/sfp info to STATE_DB + logical_port_list = y_cable_platform_sfputil.logical + for logical_port_name in logical_port_list: + if stop_event.is_set(): + break + + # Get the asic to which this port belongs + asic_index = y_cable_platform_sfputil.get_asic_id_for_logical_port(logical_port_name) + if asic_index is None: + logger.log_warning("Got invalid asic index for {}, ignored".format(logical_port_name)) + continue + post_port_mux_static_info_to_db(logical_port_name, mux_tbl[asic_index]) + + +def post_mux_info_to_db(is_warm_start, stop_event=threading.Event()): + # Connect to STATE_DB and create transceiver mux/static info tables + state_db, mux_tbl, static_tbl = {}, {}, {} + + # Get the namespaces in the platform + namespaces = multi_asic.get_front_end_namespaces() + for namespace in namespaces: + asic_id = multi_asic.get_asic_index_from_namespace(namespace) + state_db[asic_id] = daemon_base.db_connect("STATE_DB", namespace) + mux_tbl[asic_id] = swsscommon.Table(state_db[asic_id], MUX_CABLE_INFO_TABLE) + + # Post all the current interface dom/sfp info to STATE_DB + logical_port_list = y_cable_platform_sfputil.logical + for logical_port_name in logical_port_list: + if stop_event.is_set(): + break + + # Get the asic to which this port belongs + asic_index = y_cable_platform_sfputil.get_asic_id_for_logical_port(logical_port_name) + if asic_index is None: + logger.log_warning("Got invalid asic index for {}, ignored".format(logical_port_name)) + continue + post_port_mux_info_to_db(logical_port_name, mux_tbl[asic_index]) # Thread wrapper class to update y_cable status periodically @@ -511,6 +1061,12 @@ def task_worker(self): while True: # Use timeout to prevent ignoring the signals we want to handle # in signal_handler() (e.g. SIGTERM for graceful shutdown) + + # A brief sleep appears necessary in this loop or any spawned + # update threads will get stuck. Appears to be due to the sel.select() call. + # TODO: Eliminate the need for this sleep. + time.sleep(0.1) + (state, selectableObj) = sel.select(SELECT_TIMEOUT) if state == swsscommon.Select.TIMEOUT: