diff --git a/src/sonic_ax_impl/mibs/__init__.py b/src/sonic_ax_impl/mibs/__init__.py index e4996146a0f9..c9154c7f72e5 100644 --- a/src/sonic_ax_impl/mibs/__init__.py +++ b/src/sonic_ax_impl/mibs/__init__.py @@ -571,3 +571,22 @@ def init_namespace_sync_d_queue_tables(dbs): port_queue_list_map.update(port_queue_list_map_ns) return port_queues_map, queue_stat_map, port_queue_list_map + + @staticmethod + def dbs_get_bridge_port_map(dbs, db_name): + """ + get_bridge_port_map from all namespace DBs + """ + if_br_oid_map = {} + 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 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) + 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 ac344f5cd04b..fa4d2b7e20e7 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.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): @@ -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.dbs_get_all(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.dbs_get_all(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.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 @@ -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 28f0002fefed..a0134cf9920b 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc2737.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc2737.py @@ -5,11 +5,11 @@ 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 sonic_ax_impl.mibs import Namespace @unique class PhysicalClass(int, Enum): @@ -120,8 +120,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 +136,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 +153,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 +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 = self.statedb.keys(self.statedb.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] @@ -181,7 +181,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 +190,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 +232,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 +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 = self.statedb.get_all(self.statedb.STATE_DB, + transceiver_info = Namespace.dbs_get_all(self.statedb, mibs.STATE_DB, mibs.transceiver_info_table(interface)) if not transceiver_info: @@ -283,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 = self.statedb.get_all(self.statedb.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 df1e3ee2afa9..4c0754f99f3c 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc3433.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc3433.py @@ -5,9 +5,10 @@ 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 @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.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.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 fa0c5b81eb8f..e9aa46af65b2 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc4363.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc4363.py @@ -1,15 +1,16 @@ import json from sonic_ax_impl import mibs -from swsssdk import port_util +from sonic_ax_impl.mibs import Namespace 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 +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 = port_util.get_vlan_id_from_bvid(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"]) @@ -40,9 +41,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.dbs_get_bridge_port_map(self.db_conn, mibs.ASIC_DB) self.bvid_vlan_map.clear() def update_data(self): @@ -50,11 +51,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.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 = self.db_conn.get_all(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: diff --git a/tests/mock_tables/asic0/state_db.json b/tests/mock_tables/asic0/state_db.json index 2c63c0851048..fd6ac4e22285 100644 --- a/tests/mock_tables/asic0/state_db.json +++ b/tests/mock_tables/asic0/state_db.json @@ -1,2 +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 index 2c63c0851048..c58cbd230ecc 100644 --- a/tests/mock_tables/asic1/state_db.json +++ b/tests/mock_tables/asic1/state_db.json @@ -1,2 +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 000000000000..7b2f228d5dfd --- /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 000000000000..5ecaaae84e3c --- /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) +