Skip to content

Commit a677876

Browse files
[Multi-asic]: Support multi-asic platform (#126)
* [sonic-ax-impl]: Add SNMP support for multi-asic platform: - Modify interface, lag, queue related functions to get data from all databases. - Update implementation of the following MIBS to get data from all databases: - InterfaceMIB - InterfaceMIBObjects - CiscoSystemExtMIB - csqIfQosGroupStatsTable * Fix as per review comments. Test case for init_namespace_dbs * Remove whitespace. * Add namespace support to IpCidrRouteTable MIB. * Add testcases for multiple namesapce for below MIBS: InterfaceMIB InterfaceMIBObjects cpfcIfPriorityTable * Remove debug print messages. * Modified as per review comments. Added a new class for Namespace related functions. Updated single namespace testcase to load database_config.json. * Changes made as per LGTM comments and review comments. * Minor fix to remove import of module not being used. * Fix PortChannel name in asic1 mock table. * Remove import of libraries that are not required. * Corrections in namespace database json files. * Add namespace test case for csqIfQosGroupStatsTable. * Fix SonicV2Connector mock __init__ function to match changes in swsssdk. * Change function name as per review comment. Add mock connect function to get mock db filenames.
1 parent c8e5757 commit a677876

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+4362
-63
lines changed

src/sonic_ax_impl/mibs/__init__.py

Lines changed: 143 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import pprint
22
import re
3+
import os
34

45
from swsssdk import SonicV2Connector
6+
from swsssdk import SonicDBConfig
57
from swsssdk import port_util
68
from swsssdk.port_util import get_index, get_index_from_str
79
from ax_interface.mib import MIBUpdater
@@ -148,7 +150,7 @@ def init_db():
148150
"""
149151
# SyncD database connector. THIS MUST BE INITIALIZED ON A PER-THREAD BASIS.
150152
# Redis PubSub objects (such as those within swsssdk) are NOT thread-safe.
151-
db_conn = SonicV2Connector(**redis_kwargs)
153+
db_conn = SonicV2Connector(**redis_kwargs)
152154

153155
return db_conn
154156

@@ -182,8 +184,6 @@ def init_mgmt_interface_tables(db_conn):
182184

183185
return oid_name_map, if_alias_map
184186

185-
186-
# TODO: the function name include interface, but only return port by design. Fix the design or the name
187187
def init_sync_d_interface_tables(db_conn):
188188
"""
189189
Initializes interface maps for SyncD-connected MIB(s).
@@ -196,9 +196,12 @@ def init_sync_d_interface_tables(db_conn):
196196
# { if_name (SONiC) -> sai_id }
197197
# ex: { "Ethernet76" : "1000000000023" }
198198
if_name_map, if_id_map = port_util.get_interface_oid_map(db_conn)
199-
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())}
200-
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())}
201-
199+
if_name_map = {if_name: sai_id for if_name, sai_id in if_name_map.items() if \
200+
(re.match(port_util.SONIC_ETHERNET_RE_PATTERN, if_name.decode()) or \
201+
re.match(port_util.SONIC_ETHERNET_BP_RE_PATTERN, if_name.decode()))}
202+
if_id_map = {sai_id: if_name for sai_id, if_name in if_id_map.items() if \
203+
(re.match(port_util.SONIC_ETHERNET_RE_PATTERN, if_name.decode()) or \
204+
re.match(port_util.SONIC_ETHERNET_BP_RE_PATTERN, if_name.decode()))}
202205
logger.debug("Port name map:\n" + pprint.pformat(if_name_map, indent=2))
203206
logger.debug("Interface name map:\n" + pprint.pformat(if_id_map, indent=2))
204207

@@ -241,7 +244,6 @@ def init_sync_d_interface_tables(db_conn):
241244

242245
return if_name_map, if_alias_map, if_id_map, oid_sai_map, oid_name_map
243246

244-
245247
def init_sync_d_lag_tables(db_conn):
246248
"""
247249
Helper method. Connects to and initializes LAG interface maps for SyncD-connected MIB(s).
@@ -391,7 +393,7 @@ class RedisOidTreeUpdater(MIBUpdater):
391393
def __init__(self, prefix_str):
392394
super().__init__()
393395

394-
self.db_conn = init_db()
396+
self.db_conn = Namespace.init_namespace_dbs()
395397
if prefix_str.startswith('.'):
396398
prefix_str = prefix_str[1:]
397399
self.prefix_str = prefix_str
@@ -417,8 +419,7 @@ def update_data(self):
417419
self.oid_list = []
418420
self.oid_map = {}
419421

420-
self.db_conn.connect(SNMP_OVERLAY_DB)
421-
keys = self.db_conn.keys(SNMP_OVERLAY_DB, self.prefix_str + '*')
422+
keys = Namespace.dbs_keys(self.db_conn, SNMP_OVERLAY_DB, self.prefix_str + '*')
422423
# TODO: fix db_conn.keys to return empty list instead of None if there is no match
423424
if keys is None:
424425
keys = []
@@ -427,7 +428,7 @@ def update_data(self):
427428
key = key.decode()
428429
oid = oid2tuple(key, dot_prefix=False)
429430
self.oid_list.append(oid)
430-
value = self.db_conn.get_all(SNMP_OVERLAY_DB, key)
431+
value = Namespace.dbs_get_all(self.db_conn, SNMP_OVERLAY_DB, key)
431432
if value[b'type'] in [b'COUNTER_32', b'COUNTER_64']:
432433
self.oid_map[oid] = int(value[b'data'])
433434
else:
@@ -439,3 +440,134 @@ def get_oidvalue(self, oid):
439440
if oid not in self.oid_map:
440441
return None
441442
return self.oid_map[oid]
443+
444+
class Namespace:
445+
@staticmethod
446+
def init_namespace_dbs():
447+
db_conn= []
448+
SonicDBConfig.load_sonic_global_db_config()
449+
for namespace in SonicDBConfig.get_ns_list():
450+
db = SonicV2Connector(use_unix_socket_path=True, namespace=namespace)
451+
db_conn.append(db)
452+
453+
return db_conn
454+
455+
@staticmethod
456+
def connect_all_dbs(dbs, db_name):
457+
for db_conn in dbs:
458+
db_conn.connect(db_name)
459+
460+
@staticmethod
461+
def dbs_keys(dbs, db_name, pattern='*'):
462+
"""
463+
db keys function execute on global and all namespace DBs.
464+
"""
465+
result_keys=[]
466+
for db_conn in dbs:
467+
db_conn.connect(db_name)
468+
keys = db_conn.keys(db_name, pattern)
469+
if keys is not None:
470+
result_keys.extend(keys)
471+
return result_keys
472+
473+
@staticmethod
474+
def dbs_get_all(dbs, db_name, _hash, *args, **kwargs):
475+
"""
476+
db get_all function executed on global and all namespace DBs.
477+
"""
478+
result = {}
479+
for db_conn in dbs:
480+
db_conn.connect(db_name)
481+
if(db_conn.exists(db_name, _hash)):
482+
ns_result = db_conn.get_all(db_name, _hash, *args, **kwargs)
483+
if ns_result is not None:
484+
result.update(ns_result)
485+
return result
486+
487+
@staticmethod
488+
def get_non_host_dbs(dbs):
489+
"""
490+
From the list of all dbs, return the list of dbs
491+
which will have interface related tables.
492+
For single namespace db, return the single db.
493+
For multiple namespace dbs, return all dbs except the
494+
host namespace db which is the first db in the list.
495+
"""
496+
if len(dbs) == 1:
497+
return dbs
498+
else:
499+
return dbs[1:]
500+
501+
502+
@staticmethod
503+
def init_namespace_sync_d_interface_tables(dbs):
504+
if_name_map = {}
505+
if_alias_map = {}
506+
if_id_map = {}
507+
oid_sai_map = {}
508+
oid_name_map = {}
509+
510+
"""
511+
all_ns_db - will have db_conn to all namespace DBs and
512+
global db. First db in the list is global db.
513+
Ignore first global db to get interface tables if there
514+
are multiple namespaces.
515+
"""
516+
for db_conn in Namespace.get_non_host_dbs(dbs):
517+
if_name_map_ns, \
518+
if_alias_map_ns, \
519+
if_id_map_ns, \
520+
oid_sai_map_ns, \
521+
oid_name_map_ns = init_sync_d_interface_tables(db_conn)
522+
if_name_map.update(if_name_map_ns)
523+
if_alias_map.update(if_alias_map_ns)
524+
if_id_map.update(if_id_map_ns)
525+
oid_sai_map.update(oid_sai_map_ns)
526+
oid_name_map.update(oid_name_map_ns)
527+
528+
return if_name_map, if_alias_map, if_id_map, oid_sai_map, oid_name_map
529+
530+
@staticmethod
531+
def init_namespace_sync_d_lag_tables(dbs):
532+
533+
lag_name_if_name_map = {}
534+
if_name_lag_name_map = {}
535+
oid_lag_name_map = {}
536+
537+
"""
538+
all_ns_db - will have db_conn to all namespace DBs and
539+
global db. First db in the list is global db.
540+
Ignore first global db to get lag tables if
541+
there are multiple namespaces.
542+
"""
543+
for db_conn in Namespace.get_non_host_dbs(dbs):
544+
lag_name_if_name_map_ns, \
545+
if_name_lag_name_map_ns, \
546+
oid_lag_name_map_ns = init_sync_d_lag_tables(db_conn)
547+
lag_name_if_name_map.update(lag_name_if_name_map_ns)
548+
if_name_lag_name_map.update(if_name_lag_name_map_ns)
549+
oid_lag_name_map.update(oid_lag_name_map_ns)
550+
551+
return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map
552+
553+
@staticmethod
554+
def init_namespace_sync_d_queue_tables(dbs):
555+
port_queues_map = {}
556+
queue_stat_map = {}
557+
port_queue_list_map = {}
558+
559+
"""
560+
all_ns_db - will have db_conn to all namespace DBs and
561+
global db. First db in the list is global db.
562+
Ignore first global db to get queue tables if there
563+
are multiple namespaces.
564+
"""
565+
for db_conn in Namespace.get_non_host_dbs(dbs):
566+
port_queues_map_ns, \
567+
queue_stat_map_ns, \
568+
port_queue_list_map_ns = init_sync_d_queue_tables(db_conn)
569+
port_queues_map.update(port_queues_map_ns)
570+
queue_stat_map.update(queue_stat_map_ns)
571+
port_queue_list_map.update(port_queue_list_map_ns)
572+
573+
return port_queues_map, queue_stat_map, port_queue_list_map

src/sonic_ax_impl/mibs/ietf/rfc1213.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from bisect import bisect_right
55

66
from sonic_ax_impl import mibs
7+
from sonic_ax_impl.mibs import Namespace
78
from ax_interface.mib import MIBMeta, ValueType, MIBUpdater, MIBEntry, SubtreeMIBEntry, OverlayAdpaterMIBEntry, OidMIBEntry
89
from ax_interface.encodings import ObjectIdentifier
910
from ax_interface.util import mac_decimals, ip2tuple_v4
@@ -93,7 +94,7 @@ def get_next(self, sub_id):
9394
class NextHopUpdater(MIBUpdater):
9495
def __init__(self):
9596
super().__init__()
96-
self.db_conn = mibs.init_db()
97+
self.db_conn = Namespace.init_namespace_dbs()
9798
self.nexthop_map = {}
9899
self.route_list = []
99100

@@ -105,8 +106,7 @@ def update_data(self):
105106
self.nexthop_map = {}
106107
self.route_list = []
107108

108-
self.db_conn.connect(mibs.APPL_DB)
109-
route_entries = self.db_conn.keys(mibs.APPL_DB, "ROUTE_TABLE:*")
109+
route_entries = Namespace.dbs_keys(self.db_conn, mibs.APPL_DB, "ROUTE_TABLE:*")
110110
if not route_entries:
111111
return
112112

@@ -115,7 +115,7 @@ def update_data(self):
115115
ipnstr = routestr[len("ROUTE_TABLE:"):]
116116
if ipnstr == "0.0.0.0/0":
117117
ipn = ipaddress.ip_network(ipnstr)
118-
ent = self.db_conn.get_all(mibs.APPL_DB, routestr, blocking=True)
118+
ent = Namespace.dbs_get_all(self.db_conn, mibs.APPL_DB, routestr, blocking=True)
119119
nexthops = ent[b"nexthop"].decode()
120120
for nh in nexthops.split(','):
121121
# TODO: if ipn contains IP range, create more sub_id here
@@ -152,7 +152,7 @@ class InterfacesUpdater(MIBUpdater):
152152

153153
def __init__(self):
154154
super().__init__()
155-
self.db_conn = mibs.init_db()
155+
self.db_conn = Namespace.init_namespace_dbs()
156156

157157
self.lag_name_if_name_map = {}
158158
self.if_name_lag_name_map = {}
@@ -177,23 +177,27 @@ def reinit_data(self):
177177
self.if_alias_map, \
178178
self.if_id_map, \
179179
self.oid_sai_map, \
180-
self.oid_name_map = mibs.init_sync_d_interface_tables(self.db_conn)
181-
180+
self.oid_name_map = Namespace.init_namespace_sync_d_interface_tables(self.db_conn)
181+
"""
182+
db_conn - will have db_conn to all namespace DBs and
183+
global db. First db in the list is global db.
184+
Use first global db to get management interface table.
185+
"""
182186
self.mgmt_oid_name_map, \
183-
self.mgmt_alias_map = mibs.init_mgmt_interface_tables(self.db_conn)
187+
self.mgmt_alias_map = mibs.init_mgmt_interface_tables(self.db_conn[0])
184188

185189
def update_data(self):
186190
"""
187191
Update redis (caches config)
188192
Pulls the table references for each interface.
189193
"""
190194
self.if_counters = \
191-
{sai_id: self.db_conn.get_all(mibs.COUNTERS_DB, mibs.counter_table(sai_id), blocking=True)
192-
for sai_id in self.if_id_map}
195+
{sai_id: Namespace.dbs_get_all(self.db_conn, mibs.COUNTERS_DB, mibs.counter_table(sai_id), blocking=True)
196+
for sai_id in self.if_id_map}
193197

194198
self.lag_name_if_name_map, \
195199
self.if_name_lag_name_map, \
196-
self.oid_lag_name_map = mibs.init_sync_d_lag_tables(self.db_conn)
200+
self.oid_lag_name_map = Namespace.init_namespace_sync_d_lag_tables(self.db_conn)
197201

198202
self.if_range = sorted(list(self.oid_sai_map.keys()) +
199203
list(self.oid_lag_name_map.keys()) +
@@ -318,7 +322,7 @@ def _get_if_entry(self, sub_id):
318322
else:
319323
return None
320324

321-
return self.db_conn.get_all(db, if_table, blocking=True)
325+
return Namespace.dbs_get_all(self.db_conn, db, if_table, blocking=True)
322326

323327
def _get_if_entry_state_db(self, sub_id):
324328
"""
@@ -337,7 +341,7 @@ def _get_if_entry_state_db(self, sub_id):
337341
else:
338342
return None
339343

340-
return self.db_conn.get_all(db, if_table, blocking=False)
344+
return Namespace.dbs_get_all(self.db_conn, db, if_table, blocking=False)
341345

342346
def _get_status(self, sub_id, key):
343347
"""

src/sonic_ax_impl/mibs/ietf/rfc2863.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from sonic_ax_impl import mibs
55
from ax_interface.mib import MIBMeta, MIBUpdater, ValueType, SubtreeMIBEntry, OverlayAdpaterMIBEntry, OidMIBEntry
6+
from sonic_ax_impl.mibs import Namespace
67

78
@unique
89
class DbTables32(int, Enum):
@@ -47,7 +48,7 @@ class InterfaceMIBUpdater(MIBUpdater):
4748
def __init__(self):
4849
super().__init__()
4950

50-
self.db_conn = mibs.init_db()
51+
self.db_conn = Namespace.init_namespace_dbs()
5152

5253
self.lag_name_if_name_map = {}
5354
self.if_name_lag_name_map = {}
@@ -74,14 +75,18 @@ def reinit_data(self):
7475
self.if_alias_map, \
7576
self.if_id_map, \
7677
self.oid_sai_map, \
77-
self.oid_name_map = mibs.init_sync_d_interface_tables(self.db_conn)
78+
self.oid_name_map = Namespace.init_namespace_sync_d_interface_tables(self.db_conn)
7879

7980
self.lag_name_if_name_map, \
8081
self.if_name_lag_name_map, \
81-
self.oid_lag_name_map = mibs.init_sync_d_lag_tables(self.db_conn)
82-
82+
self.oid_lag_name_map = Namespace.init_namespace_sync_d_lag_tables(self.db_conn)
83+
"""
84+
db_conn - will have db_conn to all namespace DBs and
85+
global db. First db in the list is global db.
86+
Use first global db to get management interface table.
87+
"""
8388
self.mgmt_oid_name_map, \
84-
self.mgmt_alias_map = mibs.init_mgmt_interface_tables(self.db_conn)
89+
self.mgmt_alias_map = mibs.init_mgmt_interface_tables(self.db_conn[0])
8590

8691
self.if_range = sorted(list(self.oid_sai_map.keys()) +
8792
list(self.oid_lag_name_map.keys()) +
@@ -94,7 +99,7 @@ def update_data(self):
9499
Pulls the table references for each interface.
95100
"""
96101
self.if_counters = {
97-
sai_id: self.db_conn.get_all(mibs.COUNTERS_DB, mibs.counter_table(sai_id), blocking=True)
102+
sai_id: Namespace.dbs_get_all(self.db_conn, mibs.COUNTERS_DB, mibs.counter_table(sai_id), blocking=True)
98103
for sai_id in self.if_id_map}
99104

100105

@@ -217,7 +222,7 @@ def _get_if_entry(self, sub_id):
217222
else:
218223
return None
219224

220-
return self.db_conn.get_all(db, if_table, blocking=True)
225+
return Namespace.dbs_get_all(self.db_conn, db, if_table, blocking=True)
221226

222227
def get_high_speed(self, sub_id):
223228
"""

0 commit comments

Comments
 (0)