def get_route_entries(): """ helper to read present route entries from ASIC-DB and as well initiate selector for ASIC-DB:ASIC-state updates. :return (selector, subscriber, <list of sorted routes>) """ db = swsscommon.DBConnector(ASIC_DB_NAME, 0) subs = swsscommon.SubscriberStateTable(db, ASIC_TABLE_NAME) print_message(syslog.LOG_DEBUG, "ASIC DB connected") rt = [] while True: k, _, _ = subs.pop() if not k: break res, e = checkout_rt_entry(k) if res: rt.append(e) print_message(syslog.LOG_DEBUG, json.dumps({"ASIC_ROUTE_ENTRY": sorted(rt)}, indent=4)) selector = swsscommon.Select() selector.addSelectable(subs) return (selector, subs, sorted(rt))
def get_transceiver_change_event(self, timeout=0): phy_port_dict = {} status = True if self.db_sel == None: from swsscommon import swsscommon self.state_db = swsscommon.DBConnector(swsscommon.STATE_DB, REDIS_HOSTNAME, REDIS_PORT, REDIS_TIMEOUT_USECS) # Subscribe to state table for SFP change notifications self.db_sel = swsscommon.Select() self.db_sel_tbl = swsscommon.NotificationConsumer( self.state_db, 'TRANSCEIVER_NOTIFY') self.db_sel.addSelectable(self.db_sel_tbl) self.db_sel_timeout = swsscommon.Select.TIMEOUT self.db_sel_object = swsscommon.Select.OBJECT self.sfpd_status_tbl = swsscommon.Table(self.state_db, 'MLNX_SFPD_TASK') # Check the liveness of mlnx-sfpd, if it failed, return false keys = self.sfpd_status_tbl.getKeys() if 'LIVENESS' not in keys: return False, phy_port_dict (state, c) = self.db_sel.select(timeout) if state == self.db_sel_timeout: status = True elif state != self.db_sel_object: status = False else: (key, op, fvp) = self.db_sel_tbl.pop() phy_port_dict[key] = op return status, phy_port_dict
def get_transceiver_change_event(self, timeout=0): phy_port_dict = {} status = True if self.db_sel == None: from swsscommon import swsscommon self.state_db = swsscommon.DBConnector(swsscommon.STATE_DB, REDIS_HOSTNAME, REDIS_PORT, REDIS_TIMEOUT_USECS) # Subscribe to state table for SFP change notifications self.db_sel = swsscommon.Select() self.db_sel_tbl = swsscommon.NotificationConsumer( self.state_db, 'TRANSCEIVER_NOTIFY') self.db_sel.addSelectable(self.db_sel_tbl) self.db_sel_timeout = swsscommon.Select.TIMEOUT self.db_sel_object = swsscommon.Select.OBJECT (state, c) = self.db_sel.select(timeout) if state == self.db_sel_timeout: status = True elif state != self.db_sel_object: status = False else: (key, op, fvp) = self.db_sel_tbl.pop() phy_port_dict[key] = op return status, phy_port_dict
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 __init__(self): """ Constructor """ self.db_connectors = {} self.selector = swsscommon.Select() self.callbacks = defaultdict( lambda: defaultdict(list)) # db -> table -> handlers[] self.subscribers = set()
def test_SelectMemoryLeak(): N = 50000 def table_set(t, state): fvs = swsscommon.FieldValuePairs([("status", state)]) t.set("123", fvs) def generator_SelectMemoryLeak(): app_db = swsscommon.DBConnector("APPL_DB", 0, True) t = swsscommon.Table(app_db, "TABLE") for i in range(int(N / 2)): table_set(t, "up") table_set(t, "down") tracker = SummaryTracker() appl_db = swsscommon.DBConnector("APPL_DB", 0, True) sel = swsscommon.Select() sst = swsscommon.SubscriberStateTable(appl_db, "TABLE") sel.addSelectable(sst) thr = Thread(target=generator_SelectMemoryLeak) thr.daemon = True thr.start() time.sleep(5) for _ in range(N): state, c = sel.select(1000) diff = tracker.diff() cases = [] for name, count, _ in diff: if count >= N: cases.append("%s - %d objects for %d repeats" % (name, count, N)) thr.join() assert not cases
def test_SelectYield(): db = swsscommon.DBConnector("APPL_DB", 0, True) db.flushdb() sel = swsscommon.Select() cst = swsscommon.SubscriberStateTable(db, "testsst") sel.addSelectable(cst) print("Spawning thread: thread_test_func") test_thread = Thread(target=thread_test_func) test_thread.start() while True: # timeout 10s is too long and indicates thread hanging (state, c) = sel.select(10000) if state == swsscommon.Select.OBJECT: break elif state == swsscommon.Select.TIMEOUT: assert False test_thread.join() (key, op, cfvs) = cst.pop() assert key == "aaa" assert op == "SET" assert len(cfvs) == 1 assert cfvs[0] == ('a', 'b')
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 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 get_transceiver_change_event(self, timeout=0): phy_port_dict = {} status = True if self.db_sel is None: from swsscommon import swsscommon self.state_db = swsscommon.DBConnector("STATE_DB", REDIS_TIMEOUT_USECS, True) # Subscribe to state table for SFP change notifications self.db_sel = swsscommon.Select() self.db_sel_tbl = swsscommon.NotificationConsumer( self.state_db, 'TRANSCEIVER_NOTIFY') self.db_sel.addSelectable(self.db_sel_tbl) self.db_sel_timeout = swsscommon.Select.TIMEOUT self.db_sel_object = swsscommon.Select.OBJECT self.sfpd_status_tbl = swsscommon.Table(self.state_db, 'MLNX_SFPD_TASK') # Check the liveness of mlnx-sfpd, if it failed, return system_fail event # If mlnx-sfpd not started, return system_not_ready event keys = self.sfpd_status_tbl.getKeys() if 'LIVENESS' not in keys: if self.mlnx_sfpd_started: log_err("mlnx-sfpd exited, return false to notify xcvrd.") phy_port_dict[EVENT_ON_ALL_SFP] = SYSTEM_FAIL return False, phy_port_dict else: log_info("mlnx-sfpd not ready, return false to notify xcvrd.") phy_port_dict[EVENT_ON_ALL_SFP] = SYSTEM_NOT_READY return False, phy_port_dict else: if not self.mlnx_sfpd_started: self.mlnx_sfpd_started = True log_info("mlnx-sfpd is running") phy_port_dict[EVENT_ON_ALL_SFP] = SYSTEM_READY return False, phy_port_dict if timeout: (state, c) = self.db_sel.select(timeout) else: (state, c) = self.db_sel.select() if state == self.db_sel_timeout: status = True elif state != self.db_sel_object: status = False else: (key, op, fvp) = self.db_sel_tbl.pop() phy_port_dict[key] = op return status, phy_port_dict
def set_feature_state(cfgdb_clients, name, state, block): """Enable/disable a feature""" entry_data_set = set() for ns, cfgdb in cfgdb_clients.items(): entry_data = cfgdb.get_entry('FEATURE', name) if not entry_data: raise Exception("Feature '{}' doesn't exist".format(name)) entry_data_set.add(entry_data['state']) if len(entry_data_set) > 1: raise Exception( "Feature '{}' state is not consistent across namespaces".format( name)) if entry_data['state'] == "always_enabled": raise Exception( "Feature '{}' state is always enabled and can not be modified". format(name)) for ns, cfgdb in cfgdb_clients.items(): cfgdb.mod_entry('FEATURE', name, {'state': state}) if block: db = swsscommon.DBConnector('STATE_DB', 0) tbl = swsscommon.SubscriberStateTable(db, 'FEATURE') sel = swsscommon.Select() sel.addSelectable(tbl) while True: rc, _ = sel.select(SELECT_TIMEOUT) if rc == swsscommon.Select.TIMEOUT: continue elif rc == swsscommon.Select.ERROR: raise Exception( 'Failed to wait till feature reaches desired state: select() failed' ) else: feature, _, fvs = tbl.pop() if feature != name: continue actual_state = dict(fvs).get('state') if actual_state == 'failed': raise Exception('Feature failed to be {}'.format(state)) elif actual_state == state: break
def test_SubscriberStateTable(): db = swsscommon.DBConnector("APPL_DB", 0, True) t = swsscommon.Table(db, "testsst") sel = swsscommon.Select() cst = swsscommon.SubscriberStateTable(db, "testsst") sel.addSelectable(cst) fvs = swsscommon.FieldValuePairs([('a', 'b')]) t.set("aaa", fvs) (state, c) = sel.select() assert state == swsscommon.Select.OBJECT (key, op, cfvs) = cst.pop() assert key == "aaa" assert op == "SET" assert len(cfvs) == 1 assert cfvs[0] == ('a', 'b')
def test_Notification(): db = swsscommon.DBConnector("APPL_DB", 0, True) ntfc = swsscommon.NotificationConsumer(db, "testntf") sel = swsscommon.Select() sel.addSelectable(ntfc) fvs = swsscommon.FieldValuePairs([('a', 'b')]) ntfp = swsscommon.NotificationProducer(db, "testntf") ntfp.send("aaa", "bbb", fvs) (state, c) = sel.select() assert state == swsscommon.Select.OBJECT (op, data, cfvs) = ntfc.pop() assert op == "aaa" assert data == "bbb" assert len(cfvs) == 1 assert cfvs[0] == ('a', 'b')
def subscribe_statedb(self): state_db = swsscommon.DBConnector("STATE_DB", REDIS_TIMEOUT_MS, True) sel = swsscommon.Select() cst = swsscommon.SubscriberStateTable(state_db, "FEATURE") sel.addSelectable(cst) while not self.task_stopping_event.is_set(): (state, c) = sel.select(SELECT_TIMEOUT_MSECS) if state == swsscommon.Select.TIMEOUT: continue if state != swsscommon.Select.OBJECT: logger.log_warning( "sel.select() did not return swsscommon.Select.OBJECT") continue (key, op, cfvs) = cst.pop() key_ext = key + ".service" timestamp = "{}".format( datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) msg = {"unit": key_ext, "evt_src": "feature", "time": timestamp} self.task_notify(msg)
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 __init__(self): REDIS_TIMEOUT_MS = 0 # Update this list to support more interfaces tbl_lst = [ swsscommon.STATE_PORT_TABLE_NAME, swsscommon.STATE_VLAN_TABLE_NAME ] self.appl_db = swsscommon.DBConnector("STATE_DB", REDIS_TIMEOUT_MS, True) self.state_db = SonicV2Connector(host='127.0.0.1', decode_responses=True) self.state_db.connect(self.state_db.STATE_DB, False) self.sel = swsscommon.Select() self.tbls = [ swsscommon.SubscriberStateTable(self.appl_db, t) for t in tbl_lst ] self.cur_interfaces = {} for t in self.tbls: self.sel.addSelectable(t)
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 get_single_port_firmware_version(port, res_dict, mux_info_dict): state_db, appl_db = {}, {} xcvrd_show_fw_rsp_sts_tbl_keys = {} xcvrd_show_fw_rsp_sts_tbl = {} xcvrd_show_fw_rsp_tbl = {} xcvrd_show_fw_cmd_tbl, xcvrd_show_fw_res_tbl = {}, {} sel = swsscommon.Select() 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] = db_connect("STATE_DB", namespace) appl_db[asic_id] = db_connect("APPL_DB", namespace) xcvrd_show_fw_cmd_tbl[asic_id] = swsscommon.Table(appl_db[asic_id], "XCVRD_SHOW_FW_CMD") xcvrd_show_fw_rsp_tbl[asic_id] = swsscommon.SubscriberStateTable(state_db[asic_id], "XCVRD_SHOW_FW_RSP") xcvrd_show_fw_rsp_sts_tbl[asic_id] = swsscommon.Table(state_db[asic_id], "XCVRD_SHOW_FW_RSP") xcvrd_show_fw_res_tbl[asic_id] = swsscommon.Table(state_db[asic_id], "XCVRD_SHOW_FW_RES") xcvrd_show_fw_rsp_sts_tbl_keys[asic_id] = xcvrd_show_fw_rsp_sts_tbl[asic_id].getKeys() for key in xcvrd_show_fw_rsp_sts_tbl_keys[asic_id]: xcvrd_show_fw_rsp_sts_tbl[asic_id]._del(key) sel.addSelectable(xcvrd_show_fw_rsp_tbl[asic_id]) rc = 0 res_dict[0] = 'unknown' logical_port_list = platform_sfputil_helper.get_logical_list() if port not in logical_port_list: click.echo("ERR: This is not a valid port, valid ports ({})".format(", ".join(logical_port_list))) rc = EXIT_FAIL res_dict[1] = rc return asic_index = None if platform_sfputil is not None: asic_index = platform_sfputil_helper.get_asic_id_for_logical_port(port) if asic_index is None: # TODO this import is only for unit test purposes, and should be removed once sonic_platform_base # is fully mocked import sonic_platform_base.sonic_sfp.sfputilhelper asic_index = sonic_platform_base.sonic_sfp.sfputilhelper.SfpUtilHelper().get_asic_id_for_logical_port(port) if asic_index is None: click.echo("Got invalid asic index for port {}, cant retreive mux status".format(port)) rc = CONFIG_FAIL res_dict[1] = rc return fvs = swsscommon.FieldValuePairs([('firmware_version', 'probe')]) xcvrd_show_fw_cmd_tbl[asic_index].set(port, fvs) # 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: click.echo("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_m, op_m, fvp_m) = xcvrd_show_fw_rsp_tbl[asic_index].pop() if not port_m: click.echo("Did not receive a port response {}".format(port)) res_dict[0] = 'False' res_dict[1] = EXIT_FAIL xcvrd_show_fw_rsp_sts_tbl[asic_index]._del(port) break if port_m != port: res_dict[0] = 'False' res_dict[1] = EXIT_FAIL xcvrd_show_fw_rsp_sts_tbl[asic_index]._del(port) continue if fvp_m: fvp_dict = dict(fvp_m) if "status" in fvp_dict: # check if xcvrd got a probe command state = fvp_dict["status"] res_dict[0] = state res_dict[1] = EXIT_FAIL xcvrd_show_fw_rsp_sts_tbl[asic_index]._del(port) (status, fvp) = xcvrd_show_fw_res_tbl[asic_index].get(port) res_dir = dict(fvp) mux_info_dict["version_nic_active"] = res_dir.get("version_nic_active", None) mux_info_dict["version_nic_inactive"] = res_dir.get("version_nic_inactive", None) mux_info_dict["version_nic_next"] = res_dir.get("version_nic_next", None) mux_info_dict["version_peer_active"] = res_dir.get("version_peer_active", None) mux_info_dict["version_peer_inactive"] = res_dir.get("version_peer_inactive", None) mux_info_dict["version_peer_next"] = res_dir.get("version_peer_next", None) mux_info_dict["version_self_active"] = res_dir.get("version_self_active", None) mux_info_dict["version_self_inactive"] = res_dir.get("version_self_inactive", None) mux_info_dict["version_self_next"] = res_dir.get("version_self_next", None) break else: res_dict[0] = 'False' res_dict[1] = EXIT_FAIL xcvrd_show_fw_rsp_sts_tbl[asic_index]._del(port) break else: res_dict[0] = 'False' res_dict[1] = EXIT_FAIL xcvrd_show_fw_rsp_sts_tbl[asic_index]._del(port) break delete_all_keys_in_db_table("STATE_DB", "XCVRD_SHOW_FW_RSP") delete_all_keys_in_db_table("STATE_DB", "XCVRD_SHOW_FW_RES") return
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 update_and_get_response_for_xcvr_cmd(cmd_name, rsp_name, exp_rsp, cmd_table_name, rsp_table_name, port, cmd_timeout_secs, arg=None): res_dict = {} state_db, appl_db = {}, {} firmware_rsp_tbl, firmware_rsp_tbl_keys = {}, {} firmware_rsp_sub_tbl = {} firmware_cmd_tbl = {} CMD_TIMEOUT_SECS = cmd_timeout_secs time_start = time.time() sel = swsscommon.Select() 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] = db_connect("STATE_DB", namespace) appl_db[asic_id] = db_connect("APPL_DB", namespace) firmware_cmd_tbl[asic_id] = swsscommon.Table(appl_db[asic_id], cmd_table_name) firmware_rsp_sub_tbl[asic_id] = swsscommon.SubscriberStateTable( state_db[asic_id], rsp_table_name) firmware_rsp_tbl[asic_id] = swsscommon.Table(state_db[asic_id], rsp_table_name) firmware_rsp_tbl_keys[asic_id] = firmware_rsp_tbl[asic_id].getKeys() for key in firmware_rsp_tbl_keys[asic_id]: firmware_rsp_tbl[asic_id]._del(key) sel.addSelectable(firmware_rsp_sub_tbl[asic_id]) rc = CONFIG_FAIL res_dict[0] = CONFIG_FAIL res_dict[1] = 'unknown' logical_port_list = platform_sfputil_helper.get_logical_list() if port not in logical_port_list: click.echo("ERR: This is not a valid port, valid ports ({})".format( ", ".join(logical_port_list))) res_dict[0] = rc return res_dict asic_index = None if platform_sfputil is not None: asic_index = platform_sfputil_helper.get_asic_id_for_logical_port(port) if asic_index is None: # TODO this import is only for unit test purposes, and should be removed once sonic_platform_base # is fully mocked import sonic_platform_base.sonic_sfp.sfputilhelper asic_index = sonic_platform_base.sonic_sfp.sfputilhelper.SfpUtilHelper( ).get_asic_id_for_logical_port(port) if asic_index is None: click.echo( "Got invalid asic index for port {}, cant perform firmware cmd" .format(port)) res_dict[0] = rc return res_dict if arg is None: cmd_arg = "null" else: cmd_arg = str(arg) fvs = swsscommon.FieldValuePairs([(cmd_name, cmd_arg)]) firmware_cmd_tbl[asic_index].set(port, fvs) # 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) time_now = time.time() time_diff = time_now - time_start if time_diff >= CMD_TIMEOUT_SECS: return res_dict if state == swsscommon.Select.TIMEOUT: # Do not flood log when select times out continue if state != swsscommon.Select.OBJECT: click.echo( "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_m, op_m, fvp_m) = firmware_rsp_sub_tbl[asic_index].pop() if not port_m: click.echo("Did not receive a port response {}".format(port)) res_dict[1] = 'unknown' res_dict[0] = CONFIG_FAIL firmware_rsp_tbl[asic_index]._del(port) break if port_m != port: res_dict[1] = 'unknown' res_dict[0] = CONFIG_FAIL firmware_rsp_tbl[asic_index]._del(port) continue if fvp_m: fvp_dict = dict(fvp_m) if rsp_name in fvp_dict: # check if xcvrd got a probe command result = fvp_dict[rsp_name] if result == exp_rsp: res_dict[1] = result res_dict[0] = 0 else: res_dict[1] = result res_dict[0] = CONFIG_FAIL firmware_rsp_tbl[asic_index]._del(port) break else: res_dict[1] = 'unknown' res_dict[0] = CONFIG_FAIL firmware_rsp_tbl[asic_index]._del(port) break else: res_dict[1] = 'unknown' res_dict[0] = CONFIG_FAIL firmware_rsp_tbl[asic_index]._del(port) break delete_all_keys_in_db_table("STATE_DB", rsp_table_name) return res_dict