def main(): logger = Logger(SYSLOG_IDENTIFIER) logger.set_min_log_priority_info() if len(sys.argv) != 3: raise Exception('Pass service and valid asic-id as arguments') service = sys.argv[1] args_asic_id = sys.argv[2] # Get num asics num_asics = multi_asic.get_num_asics() if num_asics == 0: logger.log_error( 'Detected no asics on this platform for service {}'.format( service)) sys.exit(1) # Connect to STATE_DB and subscribe to chassis-module table notifications state_db = daemon_base.db_connect("CHASSIS_STATE_DB") sel = swsscommon.Select() sst = swsscommon.SubscriberStateTable(state_db, CHASSIS_ASIC_INFO_TABLE) sel.addSelectable(sst) while True: (state, c) = sel.select(SELECT_TIMEOUT_MSECS) if state == swsscommon.Select.TIMEOUT: continue if state != swsscommon.Select.OBJECT: continue (asic_key, asic_op, asic_fvp) = sst.pop() asic_id = re.search(r'\d+$', asic_key) global_asic_id = asic_id.group(0) if asic_op == 'SET': asic_fvs = dict(asic_fvp) asic_name = asic_fvs.get('name') if asic_name is None: logger.log_info('Unable to get asic_name for asic{}'.format( global_asic_id)) continue if asic_name.startswith('FABRIC-CARD') is False: logger.log_info( 'Skipping module with asic_name {} for asic{}'.format( asic_name, global_asic_id)) continue if (global_asic_id == args_asic_id): logger.log_info( 'Detected asic{} is online'.format(global_asic_id)) sys.exit(0) elif asic_op == 'DEL': logger.log_info( 'Detected asic{} is offline'.format(global_asic_id)) sys.exit(1) else: continue
def delete_ports_status_for_y_cable(): state_db, port_tbl, y_cable_tbl = {}, {}, {} y_cable_tbl_keys = {} 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) y_cable_tbl_keys[asic_id] = y_cable_tbl[asic_id].getKeys() # delete PORTS on Y cable table if ports on Y cable logical_port_list = y_cable_platform_sfputil.logical for logical_port_name in logical_port_list: # 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)) 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])
def test_power_budget(self): chassis = MockChassis() psu1 = MockPsu("PSU 1", 0, True, True) psu1_power = 510.0 psu1.set_maximum_supplied_power(psu1_power) chassis._psu_list.append(psu1) fan_drawer1 = MockFanDrawer("FanDrawer 1", 0, True, True) fan_drawer1_power = 510.0 fan_drawer1.set_maximum_consumed_power(fan_drawer1_power) chassis._fan_drawer_list.append(fan_drawer1) module1 = MockModule("Module 1", 0, True, True) module1_power = 700.0 module1.set_maximum_consumed_power(module1_power) chassis._module_list.append(module1) state_db = daemon_base.db_connect("STATE_DB") chassis_tbl = mock_swsscommon.Table(state_db, CHASSIS_INFO_TABLE) chassis_info = psud.PsuChassisInfo(SYSLOG_IDENTIFIER, chassis) chassis_info.first_run = False # Check case where supplied_power < consumed_power chassis_info.run_power_budget(chassis_tbl) chassis_info.update_master_status() fvs = chassis_tbl.get(CHASSIS_INFO_POWER_KEY_TEMPLATE.format(1)) assert float(fvs[CHASSIS_INFO_TOTAL_POWER_SUPPLIED_FIELD]) < float( fvs[CHASSIS_INFO_TOTAL_POWER_CONSUMED_FIELD]) assert chassis_info.master_status_good == False # We cannot call get_status_master_led() on our mocked PSUs, because # they are not instantiated from the same Psu class loaded in psud, # so we must call it on the class there. assert psud.Psu.get_status_master_led() == MockPsu.STATUS_LED_COLOR_RED # Add a PSU psu2 = MockPsu("PSU 2", 1, True, True) psu2_power = 800.0 psu2.set_maximum_supplied_power(psu2_power) chassis._psu_list.append(psu2) # Check case where supplied_power > consumed_power chassis_info.run_power_budget(chassis_tbl) chassis_info.update_master_status() fvs = chassis_tbl.get(CHASSIS_INFO_POWER_KEY_TEMPLATE.format(1)) assert float(fvs[CHASSIS_INFO_TOTAL_POWER_SUPPLIED_FIELD]) > float( fvs[CHASSIS_INFO_TOTAL_POWER_CONSUMED_FIELD]) assert chassis_info.master_status_good == True # We cannot call get_status_master_led() on our mocked PSUs, because # they are not instantiated from the same Psu class loaded in psud, # so we must call it on the class there. assert psud.Psu.get_status_master_led( ) == MockPsu.STATUS_LED_COLOR_GREEN
def task_worker(self, stopping_event, sfp_error_event, y_cable_presence): helper_logger.log_info("Start Ycable monitoring loop") # Connect to STATE_DB and listen to ycable transceiver status update tables state_db, status_tbl = {}, {} port_dict = {} sel = swsscommon.Select() # 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) status_tbl[asic_id] = swsscommon.SubscriberStateTable( state_db[asic_id], TRANSCEIVER_STATUS_TABLE) sel.addSelectable(status_tbl[asic_id]) while True: if self.task_stopping_event.is_set(): break (state, selectableObj) = sel.select(SELECT_TIMEOUT) if state == swsscommon.Select.TIMEOUT: # Do not flood log when select times out continue if state != swsscommon.Select.OBJECT: helper_logger.log_warning( "sel.select() did not return swsscommon.Select.OBJECT for sonic_y_cable updates" ) continue # Get the redisselect object from selectable object redisSelectObj = swsscommon.CastSelectableToRedisSelectObj( selectableObj) # Get the corresponding namespace from redisselect db connector object namespace = redisSelectObj.getDbConnector().getNamespace() asic_index = multi_asic.get_asic_index_from_namespace(namespace) while True: (port, op, fvp) = status_tbl[asic_index].pop() if not port: break if fvp: fvp_dict = dict(fvp) if not fvp_dict: continue port_dict[port] = fvp_dict.get('status', None) y_cable_helper.change_ports_status_for_y_cable_change_event( port_dict, y_cable_presence, stopping_event)
def main(): helper_logger.log_notice("Start port_notify") # Connect to APP_DB and create transceiver dom info table appl_db = daemon_base.db_connect("APPL_DB") app_status_port_tbl = swsscommon.ProducerStateTable( appl_db, swsscommon.APP_PORT_APP_STATUS_TABLE_NAME) state_db = daemon_base.db_connect("STATE_DB") state_port_tbl = swsscommon.Table(state_db, STATE_PORT_TABLE) # Wait for PortInitDone wait_for_port_init_done() for port in range(RJ45_PORT_START, RJ45_PORT_END + 1): #print("Ethernet{}".format(port)) notify_port_xcvr_status("Ethernet{}".format(port), app_status_port_tbl, state_port_tbl, XCVR_STATE_READY) helper_logger.log_notice("End port_notify")
def subscribe_port_config_change(): sel = swsscommon.Select() asic_context = {} namespaces = multi_asic.get_front_end_namespaces() for namespace in namespaces: config_db = daemon_base.db_connect("CONFIG_DB", namespace=namespace) asic_id = multi_asic.get_asic_index_from_namespace(namespace) port_tbl = swsscommon.SubscriberStateTable( config_db, swsscommon.CFG_PORT_TABLE_NAME) asic_context[port_tbl] = asic_id sel.addSelectable(port_tbl) return sel, asic_context
def test_psuchassis_check_power_budget(): chassis = MockChassis() psu = MockPsu(True, True, "PSU 1") psu1_power = 510.0 psu.set_maximum_supplied_power(psu1_power) chassis.psu_list.append(psu) fan_drawer1 = MockFanDrawer(True, True, "FanDrawer 1") fan_drawer1_power = 510.0 fan_drawer1.set_maximum_consumed_power(fan_drawer1_power) chassis.fan_drawer_list.append(fan_drawer1) module1 = MockFanDrawer(True, True, "Module 1") module1_power = 700.0 module1.set_maximum_consumed_power(module1_power) chassis.module_list.append(module1) state_db = daemon_base.db_connect("STATE_DB") chassis_tbl = swsscommon.Table(state_db, CHASSIS_INFO_TABLE) chassis_info = PsuChassisInfo(SYSLOG_IDENTIFIER, chassis) # Check if supplied_power < consumed_power chassis_info.run_power_budget(chassis_tbl) if chassis_info.update_master_status(): chassis_info._set_psu_master_led(chassis_info.master_status_good) fvs = chassis_tbl.get(CHASSIS_INFO_POWER_KEY_TEMPLATE.format(1)) assert float(fvs[CHASSIS_INFO_TOTAL_POWER_SUPPLIED_FIELD]) < float( fvs[CHASSIS_INFO_TOTAL_POWER_CONSUMED_FIELD]) assert chassis_info.master_status_good == False assert MockPsu.get_status_master_led() == MockPsu.STATUS_LED_COLOR_RED # Add a PSU psu = MockPsu(True, True, "PSU 2") psu2_power = 800.0 psu.set_maximum_supplied_power(psu2_power) chassis.psu_list.append(psu) # Check if supplied_power > consumed_power chassis_info.run_power_budget(chassis_tbl) if chassis_info.update_master_status(): chassis_info._set_psu_master_led(chassis_info.master_status_good) fvs = chassis_tbl.get(CHASSIS_INFO_POWER_KEY_TEMPLATE.format(1)) assert float(fvs[CHASSIS_INFO_TOTAL_POWER_SUPPLIED_FIELD]) > float( fvs[CHASSIS_INFO_TOTAL_POWER_CONSUMED_FIELD]) assert chassis_info.master_status_good == True assert MockPsu.get_status_master_led() == MockPsu.STATUS_LED_COLOR_GREEN
def init_ports_status_for_y_cable(platform_sfp, platform_chassis, y_cable_presence, stop_event=threading.Event()): global y_cable_platform_sfputil 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 = {}, {}, {}, {} port_table_keys = {} y_cable_platform_sfputil = platform_sfp y_cable_platform_chassis = platform_chassis # 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) config_db[asic_id] = daemon_base.db_connect("CONFIG_DB", namespace) port_tbl[asic_id] = swsscommon.Table(config_db[asic_id], "PORT") port_table_keys[asic_id] = port_tbl[asic_id].getKeys() # Init PORT_STATUS table if ports are on Y cable 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: helper_logger.log_warning( "Got invalid asic index for {}, ignored".format( logical_port_name)) continue 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) 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 # This should not happen helper_logger.log_warning( "Could not retreive port inside config_db PORT table ".format( logical_port_name))
def test_supplied_power(self): chassis = MockChassis() psu1 = MockPsu("PSU 1", 0, True, True) psu1_power = 510.0 psu1.set_maximum_supplied_power(psu1_power) chassis._psu_list.append(psu1) psu2 = MockPsu("PSU 2", 1, True, True) psu2_power = 800.0 psu2.set_maximum_supplied_power(psu2_power) chassis._psu_list.append(psu2) psu3 = MockPsu("PSU 3", 2, True, True) psu3_power = 350.0 psu3.set_maximum_supplied_power(psu3_power) chassis._psu_list.append(psu3) total_power = psu1_power + psu2_power + psu3_power state_db = daemon_base.db_connect("STATE_DB") chassis_tbl = mock_swsscommon.Table(state_db, CHASSIS_INFO_TABLE) chassis_info = psud.PsuChassisInfo(SYSLOG_IDENTIFIER, chassis) chassis_info.run_power_budget(chassis_tbl) fvs = chassis_tbl.get(CHASSIS_INFO_POWER_KEY_TEMPLATE.format(1)) # Check if supplied power is recorded in DB assert total_power == float( fvs[CHASSIS_INFO_TOTAL_POWER_SUPPLIED_FIELD]) # Check if psu1 is not present psu1.set_presence(False) total_power = psu2_power + psu3_power chassis_info.run_power_budget(chassis_tbl) fvs = chassis_tbl.get(CHASSIS_INFO_POWER_KEY_TEMPLATE.format(1)) assert total_power == float( fvs[CHASSIS_INFO_TOTAL_POWER_SUPPLIED_FIELD]) # Check if psu2 status is NOT_OK psu2.set_status(False) total_power = psu3_power chassis_info.run_power_budget(chassis_tbl) fvs = chassis_tbl.get(CHASSIS_INFO_POWER_KEY_TEMPLATE.format(1)) assert total_power == float( fvs[CHASSIS_INFO_TOTAL_POWER_SUPPLIED_FIELD])
def get_port_mapping(): """Get port mapping from CONFIG_DB """ port_mapping = PortMapping() namespaces = multi_asic.get_front_end_namespaces() for namespace in namespaces: asic_id = multi_asic.get_asic_index_from_namespace(namespace) config_db = daemon_base.db_connect("CONFIG_DB", namespace=namespace) port_table = swsscommon.Table(config_db, swsscommon.CFG_PORT_TABLE_NAME) for key in port_table.getKeys(): if not validate_port(key): continue _, port_config = port_table.get(key) port_config_dict = dict(port_config) port_change_event = PortChangeEvent(key, port_config_dict['index'], asic_id, PortChangeEvent.PORT_ADD) port_mapping.handle_port_change_event(port_change_event) return port_mapping
def subscribe_port_update_event(db_list=['APPL_DB', 'STATE_DB']): port_tbl_map = { 'APPL_DB': swsscommon.APP_PORT_TABLE_NAME, 'CONFIG_DB': swsscommon.CFG_PORT_TABLE_NAME, 'STATE_DB': 'TRANSCEIVER_INFO' } sel = swsscommon.Select() asic_context = {} namespaces = multi_asic.get_front_end_namespaces() for db_name in db_list: if db_name not in port_tbl_map: continue for namespace in namespaces: db = daemon_base.db_connect(db_name, namespace=namespace) asic_id = multi_asic.get_asic_index_from_namespace(namespace) port_tbl = swsscommon.SubscriberStateTable(db, port_tbl_map[db_name]) asic_context[port_tbl] = asic_id sel.addSelectable(port_tbl) return sel, asic_context
def check_identifier_presence_and_update_mux_table_entry( state_db, port_tbl, y_cable_tbl, asic_index, logical_port_name, y_cable_presence): (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": 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: # fill in the newly found entry read_y_cable_and_update_statedb_port_tbl( logical_port_name, y_cable_tbl[asic_index]) else: # first create the state db y cable table and then fill in the entry y_cable_presence[:] = [True] 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) # fill the newly found entry read_y_cable_and_update_statedb_port_tbl( logical_port_name, y_cable_tbl[asic_index])
def test_consumed_power(self): chassis = MockChassis() fan_drawer1 = MockFanDrawer("FanDrawer 1", 0, True, True) fan_drawer1_power = 510.0 fan_drawer1.set_maximum_consumed_power(fan_drawer1_power) chassis._fan_drawer_list.append(fan_drawer1) module1 = MockModule("Module 1", 0, True, True) module1_power = 700.0 module1.set_maximum_consumed_power(module1_power) chassis._module_list.append(module1) total_power = fan_drawer1_power + module1_power state_db = daemon_base.db_connect("STATE_DB") chassis_tbl = mock_swsscommon.Table(state_db, CHASSIS_INFO_TABLE) chassis_info = psud.PsuChassisInfo(SYSLOG_IDENTIFIER, chassis) chassis_info.run_power_budget(chassis_tbl) fvs = chassis_tbl.get(CHASSIS_INFO_POWER_KEY_TEMPLATE.format(1)) # Check if supplied power is recorded in DB assert total_power == float( fvs[CHASSIS_INFO_TOTAL_POWER_CONSUMED_FIELD]) # Check if fan_drawer1 present fan_drawer1.set_presence(False) total_power = module1_power chassis_info.run_power_budget(chassis_tbl) fvs = chassis_tbl.get(CHASSIS_INFO_POWER_KEY_TEMPLATE.format(1)) assert total_power == float( fvs[CHASSIS_INFO_TOTAL_POWER_CONSUMED_FIELD]) # Check if module1 present fan_drawer1.set_presence(True) module1.set_presence(False) total_power = fan_drawer1_power chassis_info.run_power_budget(chassis_tbl) fvs = chassis_tbl.get(CHASSIS_INFO_POWER_KEY_TEMPLATE.format(1)) assert total_power == float( fvs[CHASSIS_INFO_TOTAL_POWER_CONSUMED_FIELD])
def task_worker(self, y_cable_presence): helper_logger.log_info("Start Ycable monitoring loop") # Connect to STATE_DB and create transceiver ycable config table state_db = {} mux_tbl = {} status_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) status_tbl[asic_id] = swsscommon.Table(state_db[asic_id], TRANSCEIVER_STATUS_TABLE) time.sleep(0.1) # Start loop to update ycable info in DB periodically while not self.task_stopping_event.wait( YCABLE_INFO_UPDATE_PERIOD_SECS): logical_port_list = platform_sfputil.logical for logical_port_name in logical_port_list: # Get the asic to which this port belongs asic_index = 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 if not detect_port_in_error_status(logical_port_name, status_tbl[asic_index]): 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 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 = {} # if there is No Y cable do not do anything here if y_cable_presence[0] is False: return (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: if y_cable_presence[0] is True: # delete this entry in the y cable table found and update the delete event 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) # fill the newly found entry delete_port_from_y_cable_table(logical_port_name, y_cable_tbl[asic_index]) delete_change_event[:] = [True]
def wait_for_port_init_done(): # Connect to APPL_DB and subscribe to PORT table notifications appl_db = daemon_base.db_connect("APPL_DB") sel = swsscommon.Select() sst = swsscommon.SubscriberStateTable(appl_db, swsscommon.APP_PORT_TABLE_NAME) sel.addSelectable(sst) # Make sure this daemon started after all port configured while True: (state, c) = sel.select(1000) if state == swsscommon.Select.TIMEOUT: continue if state != swsscommon.Select.OBJECT: helper_logger.log_warning( "sel.select() did not return swsscommon.Select.OBJECT") continue (key, op, fvp) = sst.pop() # Wait until PortInitDone if key in ["PortInitDone"]: break
def task_worker(self): # Connect to STATE_DB and create transceiver dom info table app_db, state_db, status_tbl,y_cable_tbl = {}, {}, {},{} y_cable_tbl_keys = {} # Get the namespaces in the platform sel = swsscommon.Select() #logical_port_list = platform_sfputil.logical namespaces = multi_asic.get_front_end_namespaces() for namespace in namespaces: # Open a handle to the Application database, in all namespaces asic_id = multi_asic.get_asic_index_from_namespace(namespace) app_db[asic_id] = daemon_base.db_connect("APPL_DB", namespace) status_tbl[asic_id] = swsscommon.SubscriberStateTable(appl_db[asic_id], swsscommon.APP_HW_MUX_CABLE_TABLE_NAME) 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) sel.addSelectable(status_tbl[asic_id]) # Listen indefinitely for changes to the APP_MUX_CABLE_TABLE in the Application DB's while True: # Use timeout to prevent ignoring the signals we want to handle # in signal_handler() (e.g. SIGTERM for graceful shutdown) (state, selectableObj) = sel.select(SELECT_TIMEOUT) if state == swsscommon.Select.TIMEOUT: # Do not flood log when select times out continue if state != swsscommon.Select.OBJECT: self.log_warning("sel.select() did not return swsscommon.Select.OBJECT") continue # Get the redisselect object from selectable object redisSelectObj = swsscommon.CastSelectableToRedisSelectObj(selectableObj) # Get the corresponding namespace from redisselect db connector object namespace = redisSelectObj.getDbConnector().getNamespace() asic_index = multi_asic.get_asic_index_from_namespace(namespace) y_cable_tbl_keys[asic_id] = state_db[asic_index].get_keys(swsscommon.STATE_HW_MUX_CABLE_TABLE_NAME) (port, op, fvp) = status_tbl[asic_id].pop() if fvp: #Might need to check the presence of this Port #in logical_port_list but keep for now for coherency if port not in y_cable_table_keys[asic_id]: continue fvp_dict = dict(fvp) if op == "status" in fvp_dict: #got a status change new_status = fvp_dict["status"] (status, fvs) = y_cable_tbl[asic_index].get(port) if status is False: logger.log_warning("Could not retreive fieldvalue pairs for {}, inside config_db".format(logical_port_name)) continue mux_port_dict = dict(fvs) old_status = mux_port_dict.get("status") read_side = mux_port_dict.get("read_side") active_side = mux_port_dict.get("active_side") if old_status != new_staus: update_tor_active_side(read_side, new_status, port) fvs_updated = swsscommon.FieldValuePairs([('status', new_status), ('read_side', read_side), ('active_side',active_side)]) mux_config_tbl.set(logical_port_name, fvs_updated) #nothing to do since no status change else: logger.log_warning("Got a change event on _MUX_TABLE that does not update the current status".format(logical_port_name))
def init(self): global platform_sfputil global platform_chassis self.log_info("Start daemon init...") config_db, metadata_tbl, metadata_dict = {}, {}, {} is_vs = False 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) metadata_tbl[asic_id] = swsscommon.Table(config_db[asic_id], "DEVICE_METADATA") (status, fvs) = metadata_tbl[0].get("localhost") if status is False: helper_logger.log_debug( "Could not retreive fieldvalue pairs for {}, inside config_db table {}" .format('localhost', metadata_tbl[0].getTableName())) return else: # Convert list of tuples to a dictionary metadata_dict = dict(fvs) if "platform" in metadata_dict: val = metadata_dict.get("platform", None) if val == "x86_64-kvm_x86_64-r0": is_vs = True # Load new platform api class try: if is_vs is False: import sonic_platform.platform platform_chassis = sonic_platform.platform.Platform( ).get_chassis() self.log_info("chassis loaded {}".format(platform_chassis)) # we have to make use of sfputil for some features # even though when new platform api is used for all vendors. # in this sense, we treat it as a part of new platform api. # we have already moved sfputil to sonic_platform_base # which is the root of new platform api. import sonic_platform_base.sonic_sfp.sfputilhelper platform_sfputil = sonic_platform_base.sonic_sfp.sfputilhelper.SfpUtilHelper( ) except Exception as e: self.log_warning("Failed to load chassis due to {}".format( repr(e))) # Load platform specific sfputil class if platform_chassis is None or platform_sfputil is None: if is_vs is False: try: platform_sfputil = self.load_platform_util( PLATFORM_SPECIFIC_MODULE_NAME, PLATFORM_SPECIFIC_CLASS_NAME) except Exception as e: self.log_error("Failed to load sfputil: {}".format(str(e)), True) sys.exit(SFPUTIL_LOAD_ERROR) if multi_asic.is_multi_asic(): # Load the namespace details first from the database_global.json file. swsscommon.SonicDBConfig.initializeGlobalConfig() # Load port info try: if multi_asic.is_multi_asic(): # For multi ASIC platforms we pass DIR of port_config_file_path and the number of asics (platform_path, hwsku_path ) = device_info.get_paths_to_platform_and_hwsku_dirs() platform_sfputil.read_all_porttab_mappings( hwsku_path, self.num_asics) else: # For single ASIC platforms we pass port_config_file_path and the asic_inst as 0 port_config_file_path = device_info.get_path_to_port_config_file( ) platform_sfputil.read_porttab_mappings(port_config_file_path, 0) except Exception as e: self.log_error("Failed to read port info: {}".format(str(e)), True) sys.exit(PORT_CONFIG_LOAD_ERROR) # Connect to STATE_DB and create ycable tables state_db = {} # 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) """ # TODO need to decide if we need warm start capability in this ycabled daemon warmstart = swsscommon.WarmStart() warmstart.initialize("ycabled", "pmon") warmstart.checkWarmStart("ycabled", "pmon", False) is_warm_start = warmstart.isWarmStart() """ # Make sure this daemon started after all port configured self.log_info("Wait for port config is done") # Init port y_cable status table y_cable_helper.init_ports_status_for_y_cable(platform_sfputil, platform_chassis, self.y_cable_presence, self.stop_event, is_vs)
def collect(self, chassis): """ Collect thermal sensor temperature change status :param chassis: The chassis object :return: """ num_modules = chassis.get_num_modules() if chassis.get_supervisor_slot() != chassis.get_my_slot(): return chassis_state_db = daemon_base.db_connect("CHASSIS_STATE_DB") for module_index in range(1, num_modules + 1): # if chassis.get_module(module_index - 1).get_status() is not 'Online': # continue if chassis.get_module(module_index - 1).get_type() != ModuleBase.MODULE_TYPE_LINE: continue slot = chassis.get_module(module_index - 1).get_slot() table_name = 'TEMPERATURE_INFO_' + str(slot) lc_thermal_tbl = swsscommon.Table(chassis_state_db, table_name) # Find min, max, curr, margin temp for each module self.init_extreme() # Walk the table and store in the dictionary keys = lc_thermal_tbl.getKeys() if not keys: continue for key in keys: status, fvs = lc_thermal_tbl.get(key) fv_dict = dict(fvs) # Skip temperature sensors not valid for FAN reading. # Can convert this check into a RPC API if (float(fv_dict['minimum_temperature']) == self.NOKIA_INVALID_TEMP) and ( float(fv_dict['maximum_temperature']) == self.NOKIA_INVALID_TEMP): continue # For J2 temperatures, there is remote normalization normalize = 0.0 if (float(fv_dict['high_threshold']) == self.NOKIA_J2_TEMP_THRESHOLD): normalize = self.NOKIA_J2_TEMP_THRESHOLD - self.NOKIA_IMM_TEMP_THRESHOLD self.curr_temp = max(float(self.curr_temp), float(fv_dict['temperature']) - normalize) self.updateminmax( float(fv_dict['minimum_temperature']) - normalize) self.updateminmax( float(fv_dict['maximum_temperature']) - normalize) margin = float(fv_dict['high_threshold']) - float( fv_dict['temperature']) self.margin_temp = min(float(self.margin_temp), margin) slot_avg_dict = {} slot_avg_dict['curr_temp'] = int(self.curr_temp) slot_avg_dict['min_temp'] = int(self.min_temp) slot_avg_dict['max_temp'] = int(self.max_temp) slot_avg_dict['margin_temp'] = int(self.margin_temp) self.lc_thermal_dict[slot] = slot_avg_dict
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 = {}, {}, {}, {} port_table_keys = {} delete_change_event = [False] # Get the namespaces in the platform namespaces = multi_asic.get_front_end_namespaces() # Get the keys from PORT table inside config db to prepare check for mux_cable identifier 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") port_table_keys[asic_id] = port_tbl[asic_id].getKeys() # Init PORT_STATUS table if ports are on Y cable and an event is received for key, value in port_dict.iteritems(): 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)) continue for logical_port_name in logical_port_list: # 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: helper_logger.log_warning( "Got invalid asic index for {}, ignored".format( logical_port_name)) continue if logical_port_name in port_table_keys[asic_index]: 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) 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) else: # SFP return unkown event, just ignore for now. helper_logger.log_warning( "Got unknown event {}, ignored".format(value)) continue # If there was a delete event and y_cable_presence was true, reaccess the y_cable presence if y_cable_presence[0] is True and delete_change_event[0] is True: y_cable_presence[:] = [False] for namespace in namespaces: asic_id = multi_asic.get_asic_index_from_namespace(namespace) y_cable_tbl[asic_id] = swsscommon.Table( state_db[asic_id], swsscommon.STATE_HW_MUX_CABLE_TABLE_NAME) y_cable_table_size = len(y_cable_tbl[asic_id].getKeys()) if y_cable_table_size > 0: y_cable_presence[:] = [True] break
def task_worker(self): # Connect to STATE_DB and APPL_DB and get both the HW_MUX_STATUS_TABLE info appl_db, state_db, status_tbl, y_cable_tbl = {}, {}, {}, {} y_cable_tbl_keys = {} mux_cable_command_tbl = {} sel = swsscommon.Select() # Get the namespaces in the platform namespaces = multi_asic.get_front_end_namespaces() for namespace in namespaces: # Open a handle to the Application database, in all namespaces asic_id = multi_asic.get_asic_index_from_namespace(namespace) appl_db[asic_id] = daemon_base.db_connect("APPL_DB", namespace) status_tbl[asic_id] = swsscommon.SubscriberStateTable( appl_db[asic_id], swsscommon.APP_HW_MUX_CABLE_TABLE_NAME) mux_cable_command_tbl[asic_id] = swsscommon.SubscriberStateTable( appl_db[asic_id], swsscommon.APP_MUX_CABLE_COMMAND_TABLE_NAME) 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) y_cable_tbl_keys[asic_id] = y_cable_tbl[asic_id].getKeys() sel.addSelectable(status_tbl[asic_id]) sel.addSelectable(mux_cable_command_tbl[asic_id]) # Listen indefinitely for changes to the HW_MUX_CABLE_TABLE in the Application DB's while True: # Use timeout to prevent ignoring the signals we want to handle # in signal_handler() (e.g. SIGTERM for graceful shutdown) (state, selectableObj) = sel.select(SELECT_TIMEOUT) if state == swsscommon.Select.TIMEOUT: # Do not flood log when select times out continue if state != swsscommon.Select.OBJECT: helper_logger.log_warning( "sel.select() did not return swsscommon.Select.OBJECT for sonic_y_cable updates" ) continue # Get the redisselect object from selectable object redisSelectObj = swsscommon.CastSelectableToRedisSelectObj( selectableObj) # Get the corresponding namespace from redisselect db connector object namespace = redisSelectObj.getDbConnector().getNamespace() asic_index = multi_asic.get_asic_index_from_namespace(namespace) (port, op, fvp) = status_tbl[asic_index].pop() if fvp: # This check might be redundant, to check, the presence of this Port in keys # in logical_port_list but keep for now for coherency # also skip checking in logical_port_list inside sfp_util if port not in y_cable_tbl_keys[asic_index]: continue fvp_dict = dict(fvp) if "status" in fvp_dict: # got a status change new_status = fvp_dict["status"] (status, fvs) = y_cable_tbl[asic_index].get(port) if status is False: helper_logger.log_warning( "Could not retreive fieldvalue pairs for {}, inside state_db table {}" .format(port, y_cable_tbl[asic_index])) continue mux_port_dict = dict(fvs) old_status = mux_port_dict.get("status") read_side = mux_port_dict.get("read_side") prev_active_side = mux_port_dict.get("active_side") # Now if the old_status does not match new_status toggle the mux appropriately if old_status != new_status: active_side = update_tor_active_side( read_side, new_status, port) fvs_updated = swsscommon.FieldValuePairs([ ('status', new_status), ('read_side', read_side), ('active_side', str(active_side)) ]) y_cable_tbl[asic_index].set(port, fvs_updated) # nothing to do since no status change else: helper_logger.log_warning( "Got a change event on that does not toggle the TOR active side for port {} status {} active linked side = {} " .format(port, old_status, prev_active_side)) else: helper_logger.log_info( "Got a change event on port {} of table {} that does not contain status " .format(port, swsscommon.APP_HW_MUX_CABLE_TABLE_NAME)) (port_m, op_m, fvp_m) = mux_cable_command_tbl[asic_index].pop() if fvp_m: fvp_dict = dict(fvp_m) if "command" in fvp_dict: #check if xcvrd got a probe command probe_identifier = fvp_dict["command"] if probe_identifier == "probe": update_appdb_port_mux_cable_response_table( port_m, asic_index, appl_db)
def init_ports_status_for_y_cable(platform_sfp, stop_event=threading.Event()): global platform_sfputil # Connect to CONFIG_DB and create port status table inside state_db config_db, state_db, port_tbl , y_cable_tbl= {}, {}, {}, {} port_table_keys = {} state_db_created = False platform_sfputil = platform_sfp # 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) config_db[asic_id] = daemon_base.db_connect("CONFIG_DB", namespace) port_tbl[asic_id] = swsscommon.Table(config_db[asic_id], "PORT") port_table_keys[asic_id] = config_db[asic_id].get_keys("PORT") # Init PORT_STATUS table if ports are on Y cable logical_port_list = 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 = 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 if logical_port_name in port_table_keys[asic_index]: (status, fvs) = port_tbl[asic_index].get(logical_port_name) if status is False: logger.log_warning("Could not retreive fieldvalue pairs for {}, inside config_db".format(logical_port_name)) continue else: # Convert list of tuples to a dictionary mux_table_dict = dict(fvp) if "mux_cable" in mux_table_dict: if state_db_created: #fill in the newly found entry update_port_mux_status_table(logical_port_name,y_cable_tbl[asic_index]) else: #first create the db and then fill in the entry state_db_created = True 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) # fill the newly found entry update_port_mux_status_table(logical_port_name,y_cable_tbl[asic_index]) else: logger.log_info("Port is not connected on a Y cable") 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 This should not happen ''' logger.log_warning("Could not retreive port inside config_db PORT table ".format(logical_port_name)) return state_db_created