From 961fc2073b0df9c7ceb0f97d4d9ba78716486fbc Mon Sep 17 00:00:00 2001 From: SuvarnaMeenakshi Date: Tue, 26 May 2020 17:21:52 -0700 Subject: [PATCH 1/4] Changes in below MIB tables implementation to support multi-asic platform: LLDPRemManAddrTable PhysicalTableMIB PhysicalSensorTableMIB QBridgeMIBObjects Signed-off-by: SuvarnaMeenakshi --- src/sonic_ax_impl/mibs/__init__.py | 176 +++++++++++++++-- src/sonic_ax_impl/mibs/ieee802_1ab.py | 81 ++++---- src/sonic_ax_impl/mibs/ietf/rfc2737.py | 36 ++-- src/sonic_ax_impl/mibs/ietf/rfc3433.py | 9 +- src/sonic_ax_impl/mibs/ietf/rfc4363.py | 16 +- tests/mock_tables/asic0/state_db.json | 25 +++ tests/mock_tables/asic1/state_db.json | 25 +++ tests/namespace/test_lldp.py | 260 +++++++++++++++++++++++++ tests/namespace/test_sensor.py | 230 ++++++++++++++++++++++ 9 files changed, 785 insertions(+), 73 deletions(-) create mode 100644 tests/mock_tables/asic0/state_db.json create mode 100644 tests/mock_tables/asic1/state_db.json create mode 100644 tests/namespace/test_lldp.py create mode 100644 tests/namespace/test_sensor.py diff --git a/src/sonic_ax_impl/mibs/__init__.py b/src/sonic_ax_impl/mibs/__init__.py index 7e199644c..0e91c6295 100644 --- a/src/sonic_ax_impl/mibs/__init__.py +++ b/src/sonic_ax_impl/mibs/__init__.py @@ -1,7 +1,9 @@ import pprint import re +import os from swsssdk import SonicV2Connector +from swsssdk import SonicDBConfig from swsssdk import port_util from swsssdk.port_util import get_index, get_index_from_str from ax_interface.mib import MIBUpdater @@ -148,7 +150,7 @@ def init_db(): """ # SyncD database connector. THIS MUST BE INITIALIZED ON A PER-THREAD BASIS. # Redis PubSub objects (such as those within swsssdk) are NOT thread-safe. - db_conn = SonicV2Connector(**redis_kwargs) + db_conn = SonicV2Connector(**redis_kwargs) return db_conn @@ -182,8 +184,6 @@ def init_mgmt_interface_tables(db_conn): return oid_name_map, if_alias_map - -# TODO: the function name include interface, but only return port by design. Fix the design or the name def init_sync_d_interface_tables(db_conn): """ Initializes interface maps for SyncD-connected MIB(s). @@ -196,9 +196,12 @@ def init_sync_d_interface_tables(db_conn): # { if_name (SONiC) -> sai_id } # ex: { "Ethernet76" : "1000000000023" } if_name_map, if_id_map = port_util.get_interface_oid_map(db_conn) - if_name_map = {if_name: sai_id for if_name, sai_id in if_name_map.items() if re.match(port_util.SONIC_ETHERNET_RE_PATTERN, if_name.decode())} - if_id_map = {sai_id: if_name for sai_id, if_name in if_id_map.items() if re.match(port_util.SONIC_ETHERNET_RE_PATTERN, if_name.decode())} - + if_name_map = {if_name: sai_id for if_name, sai_id in if_name_map.items() if \ + (re.match(port_util.SONIC_ETHERNET_RE_PATTERN, if_name.decode()) or \ + re.match(port_util.SONIC_ETHERNET_BP_RE_PATTERN, if_name.decode()))} + if_id_map = {sai_id: if_name for sai_id, if_name in if_id_map.items() if \ + (re.match(port_util.SONIC_ETHERNET_RE_PATTERN, if_name.decode()) or \ + re.match(port_util.SONIC_ETHERNET_BP_RE_PATTERN, if_name.decode()))} logger.debug("Port name map:\n" + pprint.pformat(if_name_map, indent=2)) logger.debug("Interface name map:\n" + pprint.pformat(if_id_map, indent=2)) @@ -241,7 +244,6 @@ def init_sync_d_interface_tables(db_conn): return if_name_map, if_alias_map, if_id_map, oid_sai_map, oid_name_map - def init_sync_d_lag_tables(db_conn): """ Helper method. Connects to and initializes LAG interface maps for SyncD-connected MIB(s). @@ -391,7 +393,7 @@ class RedisOidTreeUpdater(MIBUpdater): def __init__(self, prefix_str): super().__init__() - self.db_conn = init_db() + self.db_conn = Namespace.init_namespace_dbs() if prefix_str.startswith('.'): prefix_str = prefix_str[1:] self.prefix_str = prefix_str @@ -417,8 +419,7 @@ def update_data(self): self.oid_list = [] self.oid_map = {} - self.db_conn.connect(SNMP_OVERLAY_DB) - keys = self.db_conn.keys(SNMP_OVERLAY_DB, self.prefix_str + '*') + keys = Namespace.get_dbs_keys(self.db_conn, SNMP_OVERLAY_DB, self.prefix_str + '*') # TODO: fix db_conn.keys to return empty list instead of None if there is no match if keys is None: keys = [] @@ -427,7 +428,7 @@ def update_data(self): key = key.decode() oid = oid2tuple(key, dot_prefix=False) self.oid_list.append(oid) - value = self.db_conn.get_all(SNMP_OVERLAY_DB, key) + value = Namespace.get_all_dbs(self.db_conn, SNMP_OVERLAY_DB, key) if value[b'type'] in [b'COUNTER_32', b'COUNTER_64']: self.oid_map[oid] = int(value[b'data']) else: @@ -439,3 +440,156 @@ def get_oidvalue(self, oid): if oid not in self.oid_map: return None return self.oid_map[oid] + +class Namespace: + @staticmethod + def init_namespace_dbs(): + db_conn= [] + SonicDBConfig.load_sonic_global_db_config() + for namespace in SonicDBConfig.get_ns_list(): + db = SonicV2Connector(use_unix_socket_path=True, namespace=namespace) + db_conn.append(db) + + return db_conn + + @staticmethod + def connect_all_dbs(dbs, db_name): + for db_conn in dbs: + db_conn.connect(db_name) + + @staticmethod + def get_dbs_keys(dbs, db_name, pattern='*'): + """ + db keys function execute on global and all namespace DBs. + """ + result_keys=[] + for db_conn in dbs: + db_conn.connect(db_name) + keys = db_conn.keys(db_name, pattern) + if keys is not None: + result_keys.extend(keys) + return result_keys + + @staticmethod + def get_all_dbs(dbs, db_name, _hash, *args, **kwargs): + """ + db get_all function executed on global and all namespace DBs. + """ + for db_conn in dbs: + db_conn.connect(db_name) + if(db_conn.exists(db_name, _hash)): + return db_conn.get_all(db_name, _hash, *args, **kwargs) + return {} + + @staticmethod + def get_non_host_dbs(dbs): + """ + From the list of all dbs, return the list of dbs + which will have interface related tables. + For single namespace db, return the single db. + For multiple namespace dbs, return all dbs except the + host namespace db which is the first db in the list. + """ + if len(dbs) == 1: + return dbs + else: + return dbs[1:] + + + @staticmethod + def init_namespace_sync_d_interface_tables(dbs): + if_name_map = {} + if_alias_map = {} + if_id_map = {} + oid_sai_map = {} + oid_name_map = {} + + """ + all_ns_db - will have db_conn to all namespace DBs and + global db. First db in the list is global db. + Ignore first global db to get interface tables if there + are multiple namespaces. + """ + for db_conn in Namespace.get_non_host_dbs(dbs): + if_name_map_ns, \ + if_alias_map_ns, \ + if_id_map_ns, \ + oid_sai_map_ns, \ + oid_name_map_ns = init_sync_d_interface_tables(db_conn) + if_name_map.update(if_name_map_ns) + if_alias_map.update(if_alias_map_ns) + if_id_map.update(if_id_map_ns) + oid_sai_map.update(oid_sai_map_ns) + oid_name_map.update(oid_name_map_ns) + + return if_name_map, if_alias_map, if_id_map, oid_sai_map, oid_name_map + + @staticmethod + def init_namespace_sync_d_lag_tables(dbs): + + lag_name_if_name_map = {} + if_name_lag_name_map = {} + oid_lag_name_map = {} + + """ + all_ns_db - will have db_conn to all namespace DBs and + global db. First db in the list is global db. + Ignore first global db to get lag tables if + there are multiple namespaces. + """ + for db_conn in Namespace.get_non_host_dbs(dbs): + lag_name_if_name_map_ns, \ + if_name_lag_name_map_ns, \ + oid_lag_name_map_ns = init_sync_d_lag_tables(db_conn) + lag_name_if_name_map.update(lag_name_if_name_map_ns) + if_name_lag_name_map.update(if_name_lag_name_map_ns) + oid_lag_name_map.update(oid_lag_name_map_ns) + + return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map + + @staticmethod + def init_namespace_sync_d_queue_tables(dbs): + port_queues_map = {} + queue_stat_map = {} + port_queue_list_map = {} + + """ + all_ns_db - will have db_conn to all namespace DBs and + global db. First db in the list is global db. + Ignore first global db to get queue tables if there + are multiple namespaces. + """ + for db_conn in Namespace.get_non_host_dbs(dbs): + port_queues_map_ns, \ + queue_stat_map_ns, \ + port_queue_list_map_ns = init_sync_d_queue_tables(db_conn) + port_queues_map.update(port_queues_map_ns) + queue_stat_map.update(queue_stat_map_ns) + port_queue_list_map.update(port_queue_list_map_ns) + + return port_queues_map, queue_stat_map, port_queue_list_map + + @staticmethod + def get_bridge_port_map_from_namespace_dbs(all_ns_db, db_name): + """ + get_bridge_port_map from all namespace DBs + """ + if_br_oid_map = {} + if len(all_ns_db) == 1: + if_br_oid_map = port_util.get_bridge_port_map(all_ns_db[0]) + else: + for db_conn in all_ns_db[1:]: + if_br_oid_map_ns = port_util.get_bridge_port_map(db_conn) + if_br_oid_map.update(if_br_oid_map_ns) + return if_br_oid_map + + @staticmethod + def get_vlan_id_from_bvid_from_namespace_dbs(all_ns_db, bvid): + if len(all_ns_db) == 1: + return port_util.get_vlan_id_from_bvid(all_ns_db[0], bvid) + else: + for db_conn in all_ns_db[1:]: + db_conn.connect('ASIC_DB') + vlan_obj = db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:" + bvid) + if vlan_obj is not None: + return port_util.get_vlan_id_from_bvid(db_conn, bvid) diff --git a/src/sonic_ax_impl/mibs/ieee802_1ab.py b/src/sonic_ax_impl/mibs/ieee802_1ab.py index ac344f5cd..d37d6bddc 100644 --- a/src/sonic_ax_impl/mibs/ieee802_1ab.py +++ b/src/sonic_ax_impl/mibs/ieee802_1ab.py @@ -7,6 +7,7 @@ from swsssdk import port_util from sonic_ax_impl import mibs, logger +from sonic_ax_impl.mibs import Namespace from ax_interface import MIBMeta, SubtreeMIBEntry, MIBEntry, MIBUpdater, ValueType @@ -102,7 +103,7 @@ class LLDPLocalSystemDataUpdater(MIBUpdater): def __init__(self): super().__init__() - self.db_conn = mibs.init_db() + self.db_conn = Namespace.init_namespace_dbs() self.loc_chassis_data = {} def reinit_data(self): @@ -110,8 +111,8 @@ def reinit_data(self): Subclass update data routine. """ # establish connection to application database. - self.db_conn.connect(mibs.APPL_DB) - self.loc_chassis_data = self.db_conn.get_all(mibs.APPL_DB, mibs.LOC_CHASSIS_TABLE) + Namespace.connect_all_dbs(self.db_conn, mibs.APPL_DB) + self.loc_chassis_data = Namespace.get_all_dbs(self.db_conn, mibs.APPL_DB, mibs.LOC_CHASSIS_TABLE) self.loc_chassis_data[b'lldp_loc_sys_cap_supported'] = parse_sys_capability(self.loc_chassis_data[b'lldp_loc_sys_cap_supported']) self.loc_chassis_data[b'lldp_loc_sys_cap_enabled'] = parse_sys_capability(self.loc_chassis_data[b'lldp_loc_sys_cap_enabled']) def update_data(self): @@ -139,9 +140,9 @@ class LocPortUpdater(MIBUpdater): def __init__(self): super().__init__() - self.db_conn = mibs.init_db() + self.db_conn = Namespace.init_namespace_dbs() # establish connection to application database. - self.db_conn.connect(mibs.APPL_DB) + Namespace.connect_all_dbs(self.db_conn, mibs.APPL_DB) self.if_name_map = {} self.if_alias_map = {} self.if_id_map = {} @@ -156,7 +157,7 @@ def __init__(self): # cache of port data # { if_name -> { 'key': 'value' } } self.loc_port_data = {} - self.pubsub = None + self.pubsub = [None] * len(self.db_conn) def reinit_data(self): """ @@ -166,10 +167,10 @@ def reinit_data(self): self.if_alias_map, \ self.if_id_map, \ self.oid_sai_map, \ - self.oid_name_map = mibs.init_sync_d_interface_tables(self.db_conn) + self.oid_name_map = Namespace.init_namespace_sync_d_interface_tables(self.db_conn) self.mgmt_oid_name_map, \ - self.mgmt_alias_map = mibs.init_mgmt_interface_tables(self.db_conn) + self.mgmt_alias_map = mibs.init_mgmt_interface_tables(self.db_conn[0]) # merge dataplane and mgmt ports self.oid_name_map.update(self.mgmt_oid_name_map) @@ -199,7 +200,7 @@ def _get_if_entry(self, if_name): else: return None - return self.db_conn.get_all(db, if_table, blocking=True) + return Namespace.get_all_dbs(self.db_conn, db, if_table, blocking=True) def update_interface_data(self, if_name): """ @@ -221,18 +222,18 @@ def get_next(self, sub_id): return None return self.if_range[right] - def update_data(self): + def _update_per_namespace_data(self, db_conn, pubsub): """ Listen to updates in APP DB, update local cache """ - if not self.pubsub: - redis_client = self.db_conn.get_redis_client(self.db_conn.APPL_DB) - db = self.db_conn.get_dbid(self.db_conn.APPL_DB) - self.pubsub = redis_client.pubsub() - self.pubsub.psubscribe("__keyspace@{}__:{}".format(db, mibs.lldp_entry_table(b'*'))) + if not pubsub: + redis_client = db_conn.get_redis_client(db_conn.APPL_DB) + db = db_conn.get_dbid(db_conn.APPL_DB) + pubsub = redis_client.pubsub() + pubsub.psubscribe("__keyspace@{}__:{}".format(db, mibs.lldp_entry_table(b'*'))) while True: - data, interface, if_id = poll_lldp_entry_updates(self.pubsub) + data, interface, if_id = poll_lldp_entry_updates(pubsub) if not data: break @@ -240,6 +241,10 @@ def update_data(self): if b"set" in data: self.update_interface_data(interface.encode()) + def update_data(self): + for i in range(len(self.db_conn)): + self._update_per_namespace_data(self.db_conn[i], self.pubsub[i]) + def local_port_num(self, sub_id): if len(sub_id) == 0: return None @@ -302,7 +307,7 @@ def reinit_data(self): self.mgmt_ip_str = None # establish connection to application database. - self.db_conn.connect(mibs.APPL_DB) + self.db_conn.connect(mibs.APPL_DB) mgmt_ip_bytes = self.db_conn.get(mibs.APPL_DB, mibs.LOC_CHASSIS_TABLE, b'lldp_loc_man_addr') if not mgmt_ip_bytes: @@ -377,7 +382,7 @@ class LLDPRemTableUpdater(MIBUpdater): def __init__(self): super().__init__() - self.db_conn = mibs.init_db() + self.db_conn = Namespace.init_namespace_dbs() self.if_name_map = {} self.if_alias_map = {} self.if_id_map = {} @@ -400,9 +405,9 @@ def reinit_data(self): self.if_alias_map, \ self.if_id_map, \ self.oid_sai_map, \ - self.oid_name_map = mibs.init_sync_d_interface_tables(self.db_conn) + self.oid_name_map = Namespace.init_namespace_sync_d_interface_tables(self.db_conn) - self.mgmt_oid_name_map, _ = mibs.init_mgmt_interface_tables(self.db_conn) + self.mgmt_oid_name_map, _ = mibs.init_mgmt_interface_tables(self.db_conn[0]) self.oid_name_map.update(self.mgmt_oid_name_map) @@ -421,12 +426,11 @@ def update_data(self): Subclass update data routine. Updates available LLDP counters. """ # establish connection to application database. - self.db_conn.connect(mibs.APPL_DB) self.if_range = [] self.lldp_counters = {} for if_oid, if_name in self.oid_name_map.items(): - lldp_kvs = self.db_conn.get_all(mibs.APPL_DB, mibs.lldp_entry_table(if_name)) + lldp_kvs = Namespace.get_all_dbs(self.db_conn, mibs.APPL_DB, mibs.lldp_entry_table(if_name)) if not lldp_kvs: continue try: @@ -484,18 +488,18 @@ class LLDPRemManAddrUpdater(MIBUpdater): def __init__(self): super().__init__() - self.db_conn = mibs.init_db() + self.db_conn = Namespace.init_namespace_dbs() # establish connection to application database. - self.db_conn.connect(self.db_conn.APPL_DB) + Namespace.connect_all_dbs(self.db_conn, mibs.APPL_DB) self.if_range = [] self.mgmt_ips = {} self.oid_name_map = {} self.mgmt_oid_name_map = {} self.mgmt_ip_str = None - self.pubsub = None + self.pubsub = [None] * len(self.db_conn) def update_rem_if_mgmt(self, if_oid, if_name): - lldp_kvs = self.db_conn.get_all(mibs.APPL_DB, mibs.lldp_entry_table(if_name)) + lldp_kvs = Namespace.get_all_dbs(self.db_conn, mibs.APPL_DB, mibs.lldp_entry_table(if_name)) if not lldp_kvs or b'lldp_rem_man_addr' not in lldp_kvs: # this interfaces doesn't have remote lldp data, or the peer doesn't advertise his mgmt address return @@ -532,18 +536,18 @@ def update_rem_if_mgmt(self, if_oid, if_name): return self.if_range.sort() - def update_data(self): + def _update_per_namespace_data(self, db_conn, pubsub): """ Listen to updates in APP DB, update local cache """ - if not self.pubsub: - redis_client = self.db_conn.get_redis_client(self.db_conn.APPL_DB) - db = self.db_conn.get_dbid(self.db_conn.APPL_DB) - self.pubsub = redis_client.pubsub() - self.pubsub.psubscribe("__keyspace@{}__:{}".format(db, mibs.lldp_entry_table(b'*'))) + if not pubsub: + redis_client = db_conn.get_redis_client(db_conn.APPL_DB) + db = db_conn.get_dbid(db_conn.APPL_DB) + pubsub = redis_client.pubsub() + pubsub.psubscribe("__keyspace@{}__:{}".format(db, mibs.lldp_entry_table(b'*'))) while True: - data, interface, if_index = poll_lldp_entry_updates(self.pubsub) + data, interface, if_index = poll_lldp_entry_updates(pubsub) if not data: break @@ -555,18 +559,23 @@ def update_data(self): self.if_range = [sub_oid for sub_oid in self.if_range if sub_oid[0] != if_index] self.update_rem_if_mgmt(if_index, interface.encode()) + def update_data(self): + for i in range(len(self.db_conn)): + self._update_per_namespace_data(self.db_conn[i], self.pubsub[i]) + + def reinit_data(self): """ Subclass reinit data routine. """ - _, _, _, _, self.oid_name_map = mibs.init_sync_d_interface_tables(self.db_conn) + _, _, _, _, self.oid_name_map = Namespace.init_namespace_sync_d_interface_tables(self.db_conn) - self.mgmt_oid_name_map, _ = mibs.init_mgmt_interface_tables(self.db_conn) + self.mgmt_oid_name_map, _ = mibs.init_mgmt_interface_tables(self.db_conn[0]) self.oid_name_map.update(self.mgmt_oid_name_map) # establish connection to application database. - self.db_conn.connect(mibs.APPL_DB) + Namespace.connect_all_dbs(self.db_conn, mibs.APPL_DB) self.if_range = [] self.mgmt_ips = {} diff --git a/src/sonic_ax_impl/mibs/ietf/rfc2737.py b/src/sonic_ax_impl/mibs/ietf/rfc2737.py index 28f0002fe..77578b9c9 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc2737.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc2737.py @@ -9,7 +9,9 @@ from ax_interface import MIBMeta, MIBUpdater, ValueType, SubtreeMIBEntry from sonic_ax_impl import mibs +from sonic_ax_impl.mibs import Namespace +import threading @unique class PhysicalClass(int, Enum): @@ -120,8 +122,8 @@ class PhysicalTableMIBUpdater(MIBUpdater): def __init__(self): super().__init__() - self.statedb = SonicV2Connector() - self.statedb.connect(self.statedb.STATE_DB) + self.statedb = Namespace.init_namespace_dbs() + Namespace.connect_all_dbs(self.statedb, mibs.STATE_DB) self.if_alias_map = {} @@ -136,7 +138,7 @@ def __init__(self): self.physical_mfg_name_map = {} self.physical_model_name_map = {} - self.pubsub = None + self.pubsub = [None] * len(self.statedb) def reinit_data(self): """ @@ -153,9 +155,9 @@ def reinit_data(self): # update interface maps _, self.if_alias_map, _, _, _ = \ - mibs.init_sync_d_interface_tables(SonicV2Connector()) + Namespace.init_namespace_sync_d_interface_tables(Namespace.init_namespace_dbs()) - device_metadata = mibs.get_device_metadata(self.statedb) + device_metadata = mibs.get_device_metadata(self.statedb[0]) chassis_sub_id = (self.CHASSIS_ID, ) self.physical_entities = [chassis_sub_id] @@ -168,7 +170,7 @@ def reinit_data(self): self.physical_serial_number_map[chassis_sub_id] = chassis_serial_number # retrieve the initial list of transceivers that are present in the system - transceiver_info = self.statedb.keys(self.statedb.STATE_DB, self.TRANSCEIVER_KEY_PATTERN) + transceiver_info = Namespace.get_dbs_keys(self.statedb, mibs.STATE_DB, self.TRANSCEIVER_KEY_PATTERN) if transceiver_info: self.transceiver_entries = [entry.decode() \ for entry in transceiver_info] @@ -181,7 +183,7 @@ def reinit_data(self): interface = transceiver_entry.split(mibs.TABLE_NAME_SEPARATOR_VBAR)[-1] self._update_transceiver_cache(interface) - def update_data(self): + def _update_per_namespace_data(self, statedb, pubsub): """ Update cache. Here we listen to changes in STATE_DB TRANSCEIVER_INFO table @@ -190,14 +192,14 @@ def update_data(self): # This code is not executed in unit test, since mockredis # does not support pubsub - if not self.pubsub: - redis_client = self.statedb.get_redis_client(self.statedb.STATE_DB) - db = self.statedb.get_dbid(self.statedb.STATE_DB) - self.pubsub = redis_client.pubsub() - self.pubsub.psubscribe("__keyspace@{}__:{}".format(db, self.TRANSCEIVER_KEY_PATTERN)) + if not pubsub: + redis_client = statedb.get_redis_client(statedb.STATE_DB) + db = statedb.get_dbid(statedb.STATE_DB) + pubsub = redis_client.pubsub() + pubsub.psubscribe("__keyspace@{}__:{}".format(db, self.TRANSCEIVER_KEY_PATTERN)) while True: - msg = self.pubsub.get_message() + msg = pubsub.get_message() if not msg: break @@ -232,6 +234,10 @@ def update_data(self): if sub_id and sub_id in self.physical_entities: self.physical_entities.remove(sub_id) + def update_data(self): + for i in range(len(self.statedb)): + self._update_per_namespace_data(self.statedb[i], self.pubsub[i]) + def _update_transceiver_cache(self, interface): """ Update data for single transceiver @@ -249,7 +255,7 @@ def _update_transceiver_cache(self, interface): insort_right(self.physical_entities, sub_id) # get transceiver information from transceiver info entry in STATE DB - transceiver_info = self.statedb.get_all(self.statedb.STATE_DB, + transceiver_info = Namespace.get_all_dbs(self.statedb, mibs.STATE_DB, mibs.transceiver_info_table(interface)) if not transceiver_info: @@ -283,7 +289,7 @@ def _update_transceiver_sensor_cache(self, interface): ifindex = port_util.get_index_from_str(interface) # get transceiver sensors from transceiver dom entry in STATE DB - transceiver_dom_entry = self.statedb.get_all(self.statedb.STATE_DB, + transceiver_dom_entry = Namespace.get_all_dbs(self.statedb, mibs.STATE_DB, mibs.transceiver_dom_table(interface)) if not transceiver_dom_entry: diff --git a/src/sonic_ax_impl/mibs/ietf/rfc3433.py b/src/sonic_ax_impl/mibs/ietf/rfc3433.py index df1e3ee2a..3baf9da1d 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc3433.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc3433.py @@ -8,6 +8,7 @@ from swsssdk import SonicV2Connector, port_util from ax_interface import MIBMeta, MIBUpdater, ValueType, SubtreeMIBEntry from sonic_ax_impl import mibs +from sonic_ax_impl.mibs import Namespace @unique class EntitySensorDataType(int, Enum): @@ -249,8 +250,8 @@ def __init__(self): super().__init__() - self.statedb = SonicV2Connector() - self.statedb.connect(self.statedb.STATE_DB) + self.statedb = Namespace.init_namespace_dbs() + Namespace.connect_all_dbs(self.statedb, mibs.STATE_DB) # list of available sub OIDs self.sub_ids = [] @@ -276,7 +277,7 @@ def reinit_data(self): self.ent_phy_sensor_value_map = {} self.ent_phy_sensor_oper_state_map = {} - transceiver_dom_encoded = self.statedb.keys(self.statedb.STATE_DB, + transceiver_dom_encoded = Namespace.get_dbs_keys(self.statedb, mibs.STATE_DB, self.TRANSCEIVER_DOM_KEY_PATTERN) if transceiver_dom_encoded: self.transceiver_dom = [entry.decode() for entry in transceiver_dom_encoded] @@ -304,7 +305,7 @@ def update_data(self): continue # get transceiver sensors from transceiver dom entry in STATE DB - transceiver_dom_entry_data = self.statedb.get_all(self.statedb.STATE_DB, + transceiver_dom_entry_data = Namespace.get_all_dbs(self.statedb, mibs.STATE_DB, transceiver_dom_entry) if not transceiver_dom_entry_data: diff --git a/src/sonic_ax_impl/mibs/ietf/rfc4363.py b/src/sonic_ax_impl/mibs/ietf/rfc4363.py index fa0c5b81e..b4c4d269c 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc4363.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc4363.py @@ -1,15 +1,18 @@ import json +from enum import unique, Enum from sonic_ax_impl import mibs +from sonic_ax_impl.mibs import Namespace from swsssdk import port_util from ax_interface import MIBMeta, ValueType, MIBUpdater, SubtreeMIBEntry from ax_interface.util import mac_decimals from bisect import bisect_right +from sonic_ax_impl.mibs import Namespace class FdbUpdater(MIBUpdater): def __init__(self): super().__init__() - self.db_conn = mibs.init_db() + self.db_conn = Namespace.init_namespace_dbs() self.if_name_map = {} self.if_alias_map = {} @@ -28,7 +31,7 @@ def fdb_vlanmac(self, fdb): if fdb["bvid"] in self.bvid_vlan_map: vlan_id = self.bvid_vlan_map[fdb["bvid"]] else: - vlan_id = port_util.get_vlan_id_from_bvid(self.db_conn, fdb["bvid"]) + vlan_id = Namespace.get_vlan_id_from_bvid_from_namespace_dbs(self.db_conn, fdb["bvid"]) self.bvid_vlan_map[fdb["bvid"]] = vlan_id return (int(vlan_id),) + mac_decimals(fdb["mac"]) @@ -40,9 +43,9 @@ def reinit_data(self): self.if_alias_map, \ self.if_id_map, \ self.oid_sai_map, \ - self.oid_name_map = mibs.init_sync_d_interface_tables(self.db_conn) + self.oid_name_map = Namespace.init_namespace_sync_d_interface_tables(self.db_conn) - self.if_bpid_map = port_util.get_bridge_port_map(self.db_conn) + self.if_bpid_map = Namespace.get_bridge_port_map_from_namespace_dbs(self.db_conn, mibs.ASIC_DB) self.bvid_vlan_map.clear() def update_data(self): @@ -50,11 +53,10 @@ def update_data(self): Update redis (caches config) Pulls the table references for each interface. """ - self.db_conn.connect(mibs.ASIC_DB) self.vlanmac_ifindex_map = {} self.vlanmac_ifindex_list = [] - fdb_strings = self.db_conn.keys(mibs.ASIC_DB, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*") + fdb_strings = Namespace.get_dbs_keys(self.db_conn, mibs.ASIC_DB, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*") if not fdb_strings: return @@ -66,7 +68,7 @@ def update_data(self): mibs.logger.error("SyncD 'ASIC_DB' includes invalid FDB_ENTRY '{}': {}.".format(fdb_str, e)) break - ent = self.db_conn.get_all(mibs.ASIC_DB, s, blocking=True) + ent = Namespace.get_all_dbs(self.db_conn, mibs.ASIC_DB, s, blocking=True) # Example output: oid:0x3a000000000608 bridge_port_id = ent[b"SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID"][6:] if bridge_port_id not in self.if_bpid_map: diff --git a/tests/mock_tables/asic0/state_db.json b/tests/mock_tables/asic0/state_db.json new file mode 100644 index 000000000..fd6ac4e22 --- /dev/null +++ b/tests/mock_tables/asic0/state_db.json @@ -0,0 +1,25 @@ +{ + "TRANSCEIVER_INFO|Ethernet0": { + "type": "QSFP+", + "hardwarerev" : "A1", + "serialnum": "SERIAL_NUM", + "manufacturename": "VENDOR_NAME", + "modelname": "MODEL_NAME" + }, + "TRANSCEIVER_DOM_SENSOR|Ethernet0": { + "temperature": 25.39, + "voltage": 3.37, + "tx1bias": "N/A", + "tx2bias": 4.44, + "tx3bias": "inf", + "tx4bias": 4.44, + "rx1power": "-inf", + "rx2power": -0.97, + "rx3power": -0.97, + "rx4power": -0.97, + "tx1power": -5.4, + "tx2power": -5.4, + "tx3power": -5.4, + "tx4power": -5.4 + } +} diff --git a/tests/mock_tables/asic1/state_db.json b/tests/mock_tables/asic1/state_db.json new file mode 100644 index 000000000..c58cbd230 --- /dev/null +++ b/tests/mock_tables/asic1/state_db.json @@ -0,0 +1,25 @@ +{ + "TRANSCEIVER_INFO|Ethernet8": { + "type": "QSFP+", + "hardwarerev" : "A1", + "serialnum": "SERIAL_NUM", + "manufacturename": "VENDOR_NAME", + "modelname": "MODEL_NAME" + }, + "TRANSCEIVER_DOM_SENSOR|Ethernet8": { + "temperature": 30.39, + "voltage": 2.37, + "tx1bias": "N/A", + "tx2bias": 4.44, + "tx3bias": "inf", + "tx4bias": 4.44, + "rx1power": "-inf", + "rx2power": -0.97, + "rx3power": -0.97, + "rx4power": -0.97, + "tx1power": -5.4, + "tx2power": -5.4, + "tx3power": -5.4, + "tx4power": -5.4 + } +} diff --git a/tests/namespace/test_lldp.py b/tests/namespace/test_lldp.py new file mode 100644 index 000000000..7b2f228d5 --- /dev/null +++ b/tests/namespace/test_lldp.py @@ -0,0 +1,260 @@ +import os +import sys +import importlib + +modules_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, os.path.join(modules_path, 'src')) + +from unittest import TestCase +import tests.mock_tables.dbconnector + +from ax_interface import ValueType +from ax_interface.pdu_implementations import GetPDU, GetNextPDU +from ax_interface.encodings import ObjectIdentifier +from ax_interface.constants import PduTypes +from ax_interface.pdu import PDU, PDUHeader +from ax_interface.mib import MIBTable +from sonic_ax_impl.mibs import ieee802_1ab + + +class TestLLDPMIB(TestCase): + @classmethod + def setUpClass(cls): + tests.mock_tables.dbconnector.load_namespace_config() + importlib.reload(ieee802_1ab) + class LLDPMIB(ieee802_1ab.LLDPLocalSystemData, + ieee802_1ab.LLDPLocalSystemData.LLDPLocPortTable, + ieee802_1ab.LLDPLocalSystemData.LLDPLocManAddrTable, + ieee802_1ab.LLDPRemTable, + ieee802_1ab.LLDPRemManAddrTable): + pass + + cls.lut = MIBTable(LLDPMIB) + for updater in cls.lut.updater_instances: + updater.update_data() + updater.reinit_data() + updater.update_data() + + def test_getnextpdu_eth1(self): + oid = ObjectIdentifier(12, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, 7, 1, 1)) + get_pdu = GetNextPDU( + header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), + oids=[oid] + ) + + print("GetNextPDU sr=", get_pdu.sr) + encoded = get_pdu.encode() + response = get_pdu.make_response(self.lut) + print(response) + value0 = response.values[0] + self.assertEqual(value0.type_, ValueType.OCTET_STRING) + print("test_getnextpdu_exactmatch: ", str(oid)) + self.assertEqual(str(value0.name), str(ObjectIdentifier(11, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, 7, 1, 1)))) + self.assertEqual(str(value0.data), "Ethernet1") + + def test_getnextpdu_eth2(self): + # oid.include = 1 + oid = ObjectIdentifier(12, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, 7, 1, 5)) + get_pdu = GetNextPDU( + header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), + oids=[oid] + ) + + print("GetNextPDU sr=", get_pdu.sr) + encoded = get_pdu.encode() + response = get_pdu.make_response(self.lut) + print(response) + value0 = response.values[0] + self.assertEqual(value0.type_, ValueType.OCTET_STRING) + print("test_getnextpdu_exactmatch: ", str(oid)) + self.assertEqual(str(value0.name), str(ObjectIdentifier(11, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, 7, 1, 5)))) + self.assertEqual(str(value0.data), "Ethernet2") + + def test_getnextpdu_eth3_asic1(self): + # oid.include = 1 + oid = ObjectIdentifier(12, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, 7, 1, 9)) + get_pdu = GetNextPDU( + header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), + oids=[oid] + ) + + print("GetNextPDU sr=", get_pdu.sr) + encoded = get_pdu.encode() + response = get_pdu.make_response(self.lut) + print(response) + value0 = response.values[0] + self.assertEqual(value0.type_, ValueType.OCTET_STRING) + print("test_getnextpdu_exactmatch: ", str(oid)) + self.assertEqual(str(value0.name), str(ObjectIdentifier(11, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, 7, 1, 9)))) + self.assertEqual(str(value0.data), "Ethernet3") + + def test_subtype_lldp_rem_table(self): + for entry in range(4, 13): + mib_entry = self.lut[(1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, entry)] + ret = mib_entry(sub_id=(1, 1)) + self.assertIsNotNone(ret) + print(ret) + + def test_subtype_lldp_loc_port_table(self): + for entry in range(2, 5): + mib_entry = self.lut[(1, 0, 8802, 1, 1, 2, 1, 3, 7, 1, entry)] + ret = mib_entry(sub_id=(1,)) + self.assertIsNotNone(ret) + print(ret) + + def test_subtype_lldp_loc_sys_data(self): + for entry in range(1, 5): + mib_entry = self.lut[(1, 0, 8802, 1, 1, 2, 1, 3, entry)] + ret = mib_entry(sub_id=(1,)) + self.assertIsNotNone(ret) + print(ret) + + def test_subtype_lldp_loc_man_addr_table(self): + for entry in range(3, 7): + mib_entry = self.lut[(1, 0, 8802, 1, 1, 2, 1, 3, 8, 1, entry)] + ret = mib_entry(sub_id=(1,)) + self.assertIsNotNone(ret) + print(ret) + + def test_subtype_lldp_rem_man_addr_table(self): + for entry in range(3, 6): + mib_entry = self.lut[(1, 0, 8802, 1, 1, 2, 1, 4, 2, 1, entry)] + ret = mib_entry(sub_id=(1, 1)) + self.assertIsNotNone(ret) + print(ret) + + def test_local_port_identification(self): + mib_entry = self.lut[(1, 0, 8802, 1, 1, 2, 1, 3, 7, 1, 3)] + ret = mib_entry(sub_id=(1,)) + self.assertEquals(ret, b'etp1') + print(ret) + + def test_mgmt_local_port_identification(self): + mib_entry = self.lut[(1, 0, 8802, 1, 1, 2, 1, 3, 7, 1, 3)] + ret = mib_entry(sub_id=(10001,)) + self.assertEquals(ret, b'mgmt1') + print(ret) + + def test_getnextpdu_local_port_identification(self): + # oid.include = 1 + oid = ObjectIdentifier(11, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 3, 7, 1, 3)) + get_pdu = GetNextPDU( + header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), + oids=[oid] + ) + + encoded = get_pdu.encode() + response = get_pdu.make_response(self.lut) + value0 = response.values[0] + self.assertEqual(value0.type_, ValueType.OCTET_STRING) + self.assertEqual(str(value0.data), "etp1") + + def test_getnextpdu_local_port_identification_asic2(self): + # oid.include = 1 + oid = ObjectIdentifier(12, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 3, 7, 1, 3, 9015)) + get_pdu = GetNextPDU( + header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), + oids=[oid] + ) + + encoded = get_pdu.encode() + response = get_pdu.make_response(self.lut) + value0 = response.values[0] + self.assertEqual(value0.type_, ValueType.OCTET_STRING) + self.assertEqual(str(value0.data), "etp9") + + def test_lab_breaks(self): + break1 = b'\x01\x06\x10\x00\x00\x00\x00q\x00\x01\xd1\x02\x00\x01\xd1\x03\x00\x00\x00P\t\x00\x01\x00\x00' \ + b'\x00\x00\x01\x00\x00\x00\x00\x00\x00"b\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00' \ + b'\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x07\t\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00' \ + b'\x00"b\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\x00' \ + b'\x00\x00\x08' + + pdu = PDU.decode(break1) + resp = pdu.make_response(self.lut) + print(resp) + + break2 = b'\x01\x06\x10\x00\x00\x00\x00\x15\x00\x00\x08\x98\x00\x00\x08\x9a\x00\x00\x00P\t\x00\x01\x00' \ + b'\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00"b\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x02' \ + b'\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x01\t\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00' \ + b'\x00\x00\x00"b\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00' \ + b'\x04\x00\x00\x00\x02' + + pdu = PDU.decode(break2) + resp = pdu.make_response(self.lut) + print(resp) + + def test_getnextpdu_noeth(self): + # oid.include = 1 + oid = ObjectIdentifier(12, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, 7, 18545, 126, 1)) + get_pdu = GetNextPDU( + header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), + oids=[oid] + ) + + print("GetNextPDU sr=", get_pdu.sr) + encoded = get_pdu.encode() + response = get_pdu.make_response(self.lut) + print(response) + value0 = response.values[0] + self.assertEqual(value0.type_, ValueType.END_OF_MIB_VIEW) + + def test_getnextpdu_lldpLocSysCapSupported(self): + oid = ObjectIdentifier(9, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 3, 5)) + get_pdu = GetNextPDU( + header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), + oids=[oid] + ) + + encoded = get_pdu.encode() + response = get_pdu.make_response(self.lut) + value0 = response.values[0] + self.assertEqual(value0.type_, ValueType.OCTET_STRING) + self.assertEqual(str(value0.name), str(ObjectIdentifier(9, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 3, 5)))) + self.assertEqual(str(value0.data), "\x28\x00") + + def test_getnextpdu_lldpLocSysCapEnabled(self): + oid = ObjectIdentifier(9, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 3, 6)) + get_pdu = GetNextPDU( + header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), + oids=[oid] + ) + + encoded = get_pdu.encode() + response = get_pdu.make_response(self.lut) + value0 = response.values[0] + self.assertEqual(value0.type_, ValueType.OCTET_STRING) + self.assertEqual(str(value0.name), str(ObjectIdentifier(9, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 3, 6)))) + self.assertEqual(str(value0.data), "\x28\x00") + + def test_getnextpdu_lldpRemSysCapSupported(self): + oid = ObjectIdentifier(12, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, 11, 1, 1)) + get_pdu = GetNextPDU( + header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), + oids=[oid] + ) + + encoded = get_pdu.encode() + response = get_pdu.make_response(self.lut) + value0 = response.values[0] + self.assertEqual(value0.type_, ValueType.OCTET_STRING) + self.assertEqual(str(value0.name), str(ObjectIdentifier(12, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, 11, 1, 1)))) + self.assertEqual(str(value0.data), "\x28\x00") + + def test_getnextpdu_lldpRemSysCapEnabled(self): + oid = ObjectIdentifier(12, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, 12, 1, 1)) + get_pdu = GetNextPDU( + header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), + oids=[oid] + ) + + encoded = get_pdu.encode() + response = get_pdu.make_response(self.lut) + value0 = response.values[0] + self.assertEqual(value0.type_, ValueType.OCTET_STRING) + self.assertEqual(str(value0.name), str(ObjectIdentifier(12, 0, 1, 0, (1, 0, 8802, 1, 1, 2, 1, 4, 1, 1, 12, 1, 1)))) + self.assertEqual(str(value0.data), "\x28\x00") + + @classmethod + def tearDownClass(cls): + tests.mock_tables.dbconnector.clean_up_config() diff --git a/tests/namespace/test_sensor.py b/tests/namespace/test_sensor.py new file mode 100644 index 000000000..5ecaaae84 --- /dev/null +++ b/tests/namespace/test_sensor.py @@ -0,0 +1,230 @@ +import os +import sys +import importlib + +modules_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, os.path.join(modules_path, 'src')) + +from unittest import TestCase + +# noinspection PyUnresolvedReferences +import tests.mock_tables.dbconnector + +from ax_interface.mib import MIBTable +from ax_interface.pdu import PDUHeader +from ax_interface.pdu_implementations import GetPDU, GetNextPDU +from ax_interface import ValueType +from ax_interface.encodings import ObjectIdentifier +from ax_interface.constants import PduTypes +from sonic_ax_impl.mibs.ietf import rfc3433 +from sonic_ax_impl.main import SonicMIB + +class TestSonicMIB(TestCase): + @classmethod + def setUpClass(cls): + tests.mock_tables.dbconnector.load_namespace_config() + importlib.reload(rfc3433) + cls.lut = MIBTable(rfc3433.PhysicalSensorTableMIB) + cls.XCVR_SUB_ID = 1 * 1000 + cls.XCVR_SUB_ID_ASIC1 = 1 * 9000 + cls.XCVR_CHANNELS = (1, 2, 3, 4) + + # Update MIBs + for updater in cls.lut.updater_instances: + updater.reinit_data() + updater.update_data() + + @staticmethod + def generate_oids_for_physical_sensor_mib(sub_id): + + return [ObjectIdentifier(12, 0, 0, 0, (1, 3, 6, 1, 2, 1, 99, 1, 1, 1, i, sub_id)) + for i in range(1, 5)] + + def _test_getpdu_xcvr_sensor(self, sub_id, expected_values): + """ + Test case for correctness of transceiver sensor MIB values + :param sub_id: sub OID of the sensor + :expected values: iterable of expected values TYPE, SCALE, PRECISION, VALUE + """ + + # generate OIDs for TYPE(.1), SCALE(.2), PRECISION(.3), VALUE(.4) + # for given sub OID + oids = self.generate_oids_for_physical_sensor_mib(sub_id) + + get_pdu = GetPDU( + header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), + oids=oids + ) + + encoded = get_pdu.encode() + response = get_pdu.make_response(self.lut) + + for index, value in enumerate(response.values): + self.assertEqual(str(value.name), str(oids[index])) + self.assertEqual(value.type_, ValueType.INTEGER) + self.assertEqual(value.data, expected_values[index]) + + + def test_getpdu_xcvr_temperature_sensor(self): + """ + Test case for correct transceiver temperature sensor MIB values + """ + expected_values = [ + rfc3433.EntitySensorDataType.CELSIUS, + rfc3433.EntitySensorDataScale.UNITS, + 6, # precision + 25390000, # expected sensor value + rfc3433.EntitySensorStatus.OK + ] + + self._test_getpdu_xcvr_sensor(self.XCVR_SUB_ID + 1, expected_values) + + + def test_getpdu_xcvr_temperature_sensor_asic1(self): + """ + Test case for correct transceiver temperature sensor MIB values + """ + print(rfc3433.PhysicalSensorTableMIB.updater.sub_ids) + expected_values = [ + rfc3433.EntitySensorDataType.CELSIUS, + rfc3433.EntitySensorDataScale.UNITS, + 6, # precision + 30390000, # expected sensor value + rfc3433.EntitySensorStatus.OK + ] + + self._test_getpdu_xcvr_sensor(self.XCVR_SUB_ID_ASIC1 + 1, expected_values) + + def test_getpdu_xcvr_voltage_sensor(self): + """ + Test case for correct transceiver voltage sensor MIB values + """ + + expected_values = [ + rfc3433.EntitySensorDataType.VOLTS_DC, + rfc3433.EntitySensorDataScale.UNITS, + 4, # precision + 33700, # expected sensor value + rfc3433.EntitySensorStatus.OK + ] + + self._test_getpdu_xcvr_sensor(self.XCVR_SUB_ID + 2, expected_values) + + + def test_getpdu_xcvr_voltage_sensor_asic1(self): + """ + Test case for correct transceiver voltage sensor MIB values + """ + + expected_values = [ + rfc3433.EntitySensorDataType.VOLTS_DC, + rfc3433.EntitySensorDataScale.UNITS, + 4, # precision + 23700, # expected sensor value + rfc3433.EntitySensorStatus.OK + ] + + self._test_getpdu_xcvr_sensor(self.XCVR_SUB_ID_ASIC1 + 2, expected_values) + + def test_getpdu_xcvr_rx_power_sensor_minus_infinity(self): + """ + Test case for correct transceiver rx power sensor MIB values + in case when rx power == -inf + """ + + expected_values = [ + rfc3433.EntitySensorDataType.WATTS, + rfc3433.EntitySensorDataScale.MILLI, + 4, # precision + 0, # expected sensor value + rfc3433.EntitySensorStatus.OK + ] + + channel = 1 + self._test_getpdu_xcvr_sensor(self.XCVR_SUB_ID + 10 * channel + 1, expected_values) + + def test_getpdu_xcvr_rx_power_sensor(self): + """ + Test case for correct transceiver rx power sensor MIB values + """ + + expected_values = [ + rfc3433.EntitySensorDataType.WATTS, + rfc3433.EntitySensorDataScale.MILLI, + 4, # precision + 7998, # expected sensor value + rfc3433.EntitySensorStatus.OK + ] + + # test for each channel except first, we already test above + for channel in (2, 3, 4): + self._test_getpdu_xcvr_sensor(self.XCVR_SUB_ID + 10 * channel + 1, expected_values) + + def test_getpdu_xcvr_tx_power_sensor(self): + """ + Test case for correct transceiver rx power sensor MIB values + """ + + expected_values = [ + rfc3433.EntitySensorDataType.WATTS, + rfc3433.EntitySensorDataScale.MILLI, + 4, # precision + 2884, # expected sensor value + rfc3433.EntitySensorStatus.OK + ] + + # test for each channel except first, we already test above + for channel in (1, 2, 3, 4): + self._test_getpdu_xcvr_sensor(self.XCVR_SUB_ID + 10 * channel + 3, expected_values) + + def test_getpdu_xcvr_tx_bias_sensor_unknown(self): + """ + Test case for correct transceiver tx bias sensor MIB values, when + tx bias sensor is set to "UNKNOWN" in state DB + """ + + expected_values = [ + rfc3433.EntitySensorDataType.AMPERES, + rfc3433.EntitySensorDataScale.MILLI, + 3, # precision + 0, # expected sensor value + rfc3433.EntitySensorStatus.UNAVAILABLE + ] + + channel = 1 + self._test_getpdu_xcvr_sensor(self.XCVR_SUB_ID + 10 * channel + 2, expected_values) + + def test_getpdu_xcvr_tx_bias_sensor_overflow(self): + """ + Test case for correct transceiver tx bias sensor MIB values + when tx bias is grater than 1E9 + """ + + expected_values = [ + rfc3433.EntitySensorDataType.AMPERES, + rfc3433.EntitySensorDataScale.MILLI, + 3, # precision + 1E9, # expected sensor value + rfc3433.EntitySensorStatus.OK + ] + + channel = 3 + self._test_getpdu_xcvr_sensor(self.XCVR_SUB_ID + 10 * channel + 2, expected_values) + + def test_getpdu_xcvr_tx_bias_sensor(self): + """ + Test case for correct transceiver tx bias sensor MIB values + """ + + expected_values = [ + rfc3433.EntitySensorDataType.AMPERES, + rfc3433.EntitySensorDataScale.MILLI, + 3, # precision + 4440, # expected sensor value + rfc3433.EntitySensorStatus.OK + ] + + # test for each channel + for channel in (2, 4): + self._test_getpdu_xcvr_sensor(self.XCVR_SUB_ID + 10 * channel + 2, expected_values) + From 3ffba0e78e467f79aa5bb02759b1deb0bdb26d8b Mon Sep 17 00:00:00 2001 From: SuvarnaMeenakshi Date: Tue, 26 May 2020 19:32:27 -0700 Subject: [PATCH 2/4] Fix LGTM errors. Signed-off-by: SuvarnaMeenakshi --- src/sonic_ax_impl/mibs/__init__.py | 26 ++++++++++---------------- src/sonic_ax_impl/mibs/ietf/rfc2737.py | 2 -- src/sonic_ax_impl/mibs/ietf/rfc3433.py | 2 +- src/sonic_ax_impl/mibs/ietf/rfc4363.py | 2 -- 4 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/sonic_ax_impl/mibs/__init__.py b/src/sonic_ax_impl/mibs/__init__.py index 0e91c6295..f3bc42401 100644 --- a/src/sonic_ax_impl/mibs/__init__.py +++ b/src/sonic_ax_impl/mibs/__init__.py @@ -570,26 +570,20 @@ def init_namespace_sync_d_queue_tables(dbs): return port_queues_map, queue_stat_map, port_queue_list_map @staticmethod - def get_bridge_port_map_from_namespace_dbs(all_ns_db, db_name): + def get_bridge_port_map_from_namespace_dbs(dbs, db_name): """ get_bridge_port_map from all namespace DBs """ if_br_oid_map = {} - if len(all_ns_db) == 1: - if_br_oid_map = port_util.get_bridge_port_map(all_ns_db[0]) - else: - for db_conn in all_ns_db[1:]: - if_br_oid_map_ns = port_util.get_bridge_port_map(db_conn) - if_br_oid_map.update(if_br_oid_map_ns) + for db_conn in Namespace.get_non_host_dbs(dbs): + if_br_oid_map_ns = port_util.get_bridge_port_map(db_conn) + if_br_oid_map.update(if_br_oid_map_ns) return if_br_oid_map @staticmethod - def get_vlan_id_from_bvid_from_namespace_dbs(all_ns_db, bvid): - if len(all_ns_db) == 1: - return port_util.get_vlan_id_from_bvid(all_ns_db[0], bvid) - else: - for db_conn in all_ns_db[1:]: - db_conn.connect('ASIC_DB') - vlan_obj = db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:" + bvid) - if vlan_obj is not None: - return port_util.get_vlan_id_from_bvid(db_conn, bvid) + def get_vlan_id_from_bvid_from_namespace_dbs(dbs, bvid): + for db_conn in Namespace.get_non_host_dbs(dbs): + db_conn.connect('ASIC_DB') + vlan_obj = db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:" + bvid) + if vlan_obj is not None: + return port_util.get_vlan_id_from_bvid(db_conn, bvid) diff --git a/src/sonic_ax_impl/mibs/ietf/rfc2737.py b/src/sonic_ax_impl/mibs/ietf/rfc2737.py index 77578b9c9..04f0de1d3 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc2737.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc2737.py @@ -11,8 +11,6 @@ from sonic_ax_impl import mibs from sonic_ax_impl.mibs import Namespace -import threading - @unique class PhysicalClass(int, Enum): """ diff --git a/src/sonic_ax_impl/mibs/ietf/rfc3433.py b/src/sonic_ax_impl/mibs/ietf/rfc3433.py index 3baf9da1d..1a46a232c 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc3433.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc3433.py @@ -5,7 +5,7 @@ from enum import Enum, unique from bisect import bisect_right -from swsssdk import SonicV2Connector, port_util +from swsssdk import port_util from ax_interface import MIBMeta, MIBUpdater, ValueType, SubtreeMIBEntry from sonic_ax_impl import mibs from sonic_ax_impl.mibs import Namespace diff --git a/src/sonic_ax_impl/mibs/ietf/rfc4363.py b/src/sonic_ax_impl/mibs/ietf/rfc4363.py index b4c4d269c..f4ae12db1 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc4363.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc4363.py @@ -1,9 +1,7 @@ import json -from enum import unique, Enum from sonic_ax_impl import mibs from sonic_ax_impl.mibs import Namespace -from swsssdk import port_util from ax_interface import MIBMeta, ValueType, MIBUpdater, SubtreeMIBEntry from ax_interface.util import mac_decimals from bisect import bisect_right From 6b55884685f3c831d04d04435b7979ed7c2d6fb7 Mon Sep 17 00:00:00 2001 From: SuvarnaMeenakshi Date: Wed, 27 May 2020 06:21:45 -0700 Subject: [PATCH 3/4] Fix LGTM error. Signed-off-by: SuvarnaMeenakshi --- src/sonic_ax_impl/mibs/ietf/rfc2737.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic_ax_impl/mibs/ietf/rfc2737.py b/src/sonic_ax_impl/mibs/ietf/rfc2737.py index 04f0de1d3..46d78ebb7 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc2737.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc2737.py @@ -5,7 +5,7 @@ from enum import Enum, unique from bisect import bisect_right, insort_right -from swsssdk import SonicV2Connector, port_util +from swsssdk import port_util from ax_interface import MIBMeta, MIBUpdater, ValueType, SubtreeMIBEntry from sonic_ax_impl import mibs From 6ba24bd9b8eaadbabc027886ecbaad9701cd7120 Mon Sep 17 00:00:00 2001 From: SuvarnaMeenakshi Date: Fri, 29 May 2020 08:40:48 -0700 Subject: [PATCH 4/4] Fix merge conflicts and fix function names as per review comment. Signed-off-by: SuvarnaMeenakshi --- src/sonic_ax_impl/mibs/__init__.py | 28 ++------------------------ src/sonic_ax_impl/mibs/ieee802_1ab.py | 8 ++++---- src/sonic_ax_impl/mibs/ietf/rfc2737.py | 6 +++--- src/sonic_ax_impl/mibs/ietf/rfc3433.py | 4 ++-- src/sonic_ax_impl/mibs/ietf/rfc4363.py | 8 ++++---- 5 files changed, 15 insertions(+), 39 deletions(-) diff --git a/src/sonic_ax_impl/mibs/__init__.py b/src/sonic_ax_impl/mibs/__init__.py index 7e1c64fa9..c9154c7f7 100644 --- a/src/sonic_ax_impl/mibs/__init__.py +++ b/src/sonic_ax_impl/mibs/__init__.py @@ -419,11 +419,7 @@ def update_data(self): self.oid_list = [] self.oid_map = {} -<<<<<<< HEAD - keys = Namespace.get_dbs_keys(self.db_conn, SNMP_OVERLAY_DB, self.prefix_str + '*') -======= keys = Namespace.dbs_keys(self.db_conn, SNMP_OVERLAY_DB, self.prefix_str + '*') ->>>>>>> remotes/azure/master # TODO: fix db_conn.keys to return empty list instead of None if there is no match if keys is None: keys = [] @@ -432,11 +428,7 @@ def update_data(self): key = key.decode() oid = oid2tuple(key, dot_prefix=False) self.oid_list.append(oid) -<<<<<<< HEAD - value = Namespace.get_all_dbs(self.db_conn, SNMP_OVERLAY_DB, key) -======= value = Namespace.dbs_get_all(self.db_conn, SNMP_OVERLAY_DB, key) ->>>>>>> remotes/azure/master if value[b'type'] in [b'COUNTER_32', b'COUNTER_64']: self.oid_map[oid] = int(value[b'data']) else: @@ -466,11 +458,7 @@ def connect_all_dbs(dbs, db_name): db_conn.connect(db_name) @staticmethod -<<<<<<< HEAD - def get_dbs_keys(dbs, db_name, pattern='*'): -======= def dbs_keys(dbs, db_name, pattern='*'): ->>>>>>> remotes/azure/master """ db keys function execute on global and all namespace DBs. """ @@ -483,17 +471,6 @@ def dbs_keys(dbs, db_name, pattern='*'): return result_keys @staticmethod -<<<<<<< HEAD - def get_all_dbs(dbs, db_name, _hash, *args, **kwargs): - """ - db get_all function executed on global and all namespace DBs. - """ - for db_conn in dbs: - db_conn.connect(db_name) - if(db_conn.exists(db_name, _hash)): - return db_conn.get_all(db_name, _hash, *args, **kwargs) - return {} -======= def dbs_get_all(dbs, db_name, _hash, *args, **kwargs): """ db get_all function executed on global and all namespace DBs. @@ -506,7 +483,6 @@ def dbs_get_all(dbs, db_name, _hash, *args, **kwargs): if ns_result is not None: result.update(ns_result) return result ->>>>>>> remotes/azure/master @staticmethod def get_non_host_dbs(dbs): @@ -597,7 +573,7 @@ def init_namespace_sync_d_queue_tables(dbs): return port_queues_map, queue_stat_map, port_queue_list_map @staticmethod - def get_bridge_port_map_from_namespace_dbs(dbs, db_name): + def dbs_get_bridge_port_map(dbs, db_name): """ get_bridge_port_map from all namespace DBs """ @@ -608,7 +584,7 @@ def get_bridge_port_map_from_namespace_dbs(dbs, db_name): return if_br_oid_map @staticmethod - def get_vlan_id_from_bvid_from_namespace_dbs(dbs, bvid): + def dbs_get_vlan_id_from_bvid(dbs, bvid): for db_conn in Namespace.get_non_host_dbs(dbs): db_conn.connect('ASIC_DB') vlan_obj = db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:" + bvid) diff --git a/src/sonic_ax_impl/mibs/ieee802_1ab.py b/src/sonic_ax_impl/mibs/ieee802_1ab.py index d37d6bddc..fa4d2b7e2 100644 --- a/src/sonic_ax_impl/mibs/ieee802_1ab.py +++ b/src/sonic_ax_impl/mibs/ieee802_1ab.py @@ -112,7 +112,7 @@ def reinit_data(self): """ # establish connection to application database. Namespace.connect_all_dbs(self.db_conn, mibs.APPL_DB) - self.loc_chassis_data = Namespace.get_all_dbs(self.db_conn, mibs.APPL_DB, mibs.LOC_CHASSIS_TABLE) + self.loc_chassis_data = Namespace.dbs_get_all(self.db_conn, mibs.APPL_DB, mibs.LOC_CHASSIS_TABLE) self.loc_chassis_data[b'lldp_loc_sys_cap_supported'] = parse_sys_capability(self.loc_chassis_data[b'lldp_loc_sys_cap_supported']) self.loc_chassis_data[b'lldp_loc_sys_cap_enabled'] = parse_sys_capability(self.loc_chassis_data[b'lldp_loc_sys_cap_enabled']) def update_data(self): @@ -200,7 +200,7 @@ def _get_if_entry(self, if_name): else: return None - return Namespace.get_all_dbs(self.db_conn, db, if_table, blocking=True) + return Namespace.dbs_get_all(self.db_conn, db, if_table, blocking=True) def update_interface_data(self, if_name): """ @@ -430,7 +430,7 @@ def update_data(self): self.if_range = [] self.lldp_counters = {} for if_oid, if_name in self.oid_name_map.items(): - lldp_kvs = Namespace.get_all_dbs(self.db_conn, mibs.APPL_DB, mibs.lldp_entry_table(if_name)) + lldp_kvs = Namespace.dbs_get_all(self.db_conn, mibs.APPL_DB, mibs.lldp_entry_table(if_name)) if not lldp_kvs: continue try: @@ -499,7 +499,7 @@ def __init__(self): self.pubsub = [None] * len(self.db_conn) def update_rem_if_mgmt(self, if_oid, if_name): - lldp_kvs = Namespace.get_all_dbs(self.db_conn, mibs.APPL_DB, mibs.lldp_entry_table(if_name)) + lldp_kvs = Namespace.dbs_get_all(self.db_conn, mibs.APPL_DB, mibs.lldp_entry_table(if_name)) if not lldp_kvs or b'lldp_rem_man_addr' not in lldp_kvs: # this interfaces doesn't have remote lldp data, or the peer doesn't advertise his mgmt address return diff --git a/src/sonic_ax_impl/mibs/ietf/rfc2737.py b/src/sonic_ax_impl/mibs/ietf/rfc2737.py index 46d78ebb7..a0134cf99 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc2737.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc2737.py @@ -168,7 +168,7 @@ def reinit_data(self): self.physical_serial_number_map[chassis_sub_id] = chassis_serial_number # retrieve the initial list of transceivers that are present in the system - transceiver_info = Namespace.get_dbs_keys(self.statedb, mibs.STATE_DB, self.TRANSCEIVER_KEY_PATTERN) + transceiver_info = Namespace.dbs_keys(self.statedb, mibs.STATE_DB, self.TRANSCEIVER_KEY_PATTERN) if transceiver_info: self.transceiver_entries = [entry.decode() \ for entry in transceiver_info] @@ -253,7 +253,7 @@ def _update_transceiver_cache(self, interface): insort_right(self.physical_entities, sub_id) # get transceiver information from transceiver info entry in STATE DB - transceiver_info = Namespace.get_all_dbs(self.statedb, mibs.STATE_DB, + transceiver_info = Namespace.dbs_get_all(self.statedb, mibs.STATE_DB, mibs.transceiver_info_table(interface)) if not transceiver_info: @@ -287,7 +287,7 @@ def _update_transceiver_sensor_cache(self, interface): ifindex = port_util.get_index_from_str(interface) # get transceiver sensors from transceiver dom entry in STATE DB - transceiver_dom_entry = Namespace.get_all_dbs(self.statedb, mibs.STATE_DB, + transceiver_dom_entry = Namespace.dbs_get_all(self.statedb, mibs.STATE_DB, mibs.transceiver_dom_table(interface)) if not transceiver_dom_entry: diff --git a/src/sonic_ax_impl/mibs/ietf/rfc3433.py b/src/sonic_ax_impl/mibs/ietf/rfc3433.py index 1a46a232c..4c0754f99 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc3433.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc3433.py @@ -277,7 +277,7 @@ def reinit_data(self): self.ent_phy_sensor_value_map = {} self.ent_phy_sensor_oper_state_map = {} - transceiver_dom_encoded = Namespace.get_dbs_keys(self.statedb, mibs.STATE_DB, + transceiver_dom_encoded = Namespace.dbs_keys(self.statedb, mibs.STATE_DB, self.TRANSCEIVER_DOM_KEY_PATTERN) if transceiver_dom_encoded: self.transceiver_dom = [entry.decode() for entry in transceiver_dom_encoded] @@ -305,7 +305,7 @@ def update_data(self): continue # get transceiver sensors from transceiver dom entry in STATE DB - transceiver_dom_entry_data = Namespace.get_all_dbs(self.statedb, mibs.STATE_DB, + transceiver_dom_entry_data = Namespace.dbs_get_all(self.statedb, mibs.STATE_DB, transceiver_dom_entry) if not transceiver_dom_entry_data: diff --git a/src/sonic_ax_impl/mibs/ietf/rfc4363.py b/src/sonic_ax_impl/mibs/ietf/rfc4363.py index f4ae12db1..e9aa46af6 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc4363.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc4363.py @@ -29,7 +29,7 @@ def fdb_vlanmac(self, fdb): if fdb["bvid"] in self.bvid_vlan_map: vlan_id = self.bvid_vlan_map[fdb["bvid"]] else: - vlan_id = Namespace.get_vlan_id_from_bvid_from_namespace_dbs(self.db_conn, fdb["bvid"]) + vlan_id = Namespace.dbs_get_vlan_id_from_bvid(self.db_conn, fdb["bvid"]) self.bvid_vlan_map[fdb["bvid"]] = vlan_id return (int(vlan_id),) + mac_decimals(fdb["mac"]) @@ -43,7 +43,7 @@ def reinit_data(self): self.oid_sai_map, \ self.oid_name_map = Namespace.init_namespace_sync_d_interface_tables(self.db_conn) - self.if_bpid_map = Namespace.get_bridge_port_map_from_namespace_dbs(self.db_conn, mibs.ASIC_DB) + self.if_bpid_map = Namespace.dbs_get_bridge_port_map(self.db_conn, mibs.ASIC_DB) self.bvid_vlan_map.clear() def update_data(self): @@ -54,7 +54,7 @@ def update_data(self): self.vlanmac_ifindex_map = {} self.vlanmac_ifindex_list = [] - fdb_strings = Namespace.get_dbs_keys(self.db_conn, mibs.ASIC_DB, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*") + fdb_strings = Namespace.dbs_keys(self.db_conn, mibs.ASIC_DB, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*") if not fdb_strings: return @@ -66,7 +66,7 @@ def update_data(self): mibs.logger.error("SyncD 'ASIC_DB' includes invalid FDB_ENTRY '{}': {}.".format(fdb_str, e)) break - ent = Namespace.get_all_dbs(self.db_conn, mibs.ASIC_DB, s, blocking=True) + ent = Namespace.dbs_get_all(self.db_conn, mibs.ASIC_DB, s, blocking=True) # Example output: oid:0x3a000000000608 bridge_port_id = ent[b"SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID"][6:] if bridge_port_id not in self.if_bpid_map: