Skip to content

Commit a559828

Browse files
authored
Enable overriding interface counters OIDs (sonic-net#98)
* Add test for interface IN_OCTETS * Add OverlayAdpaterMIBEntry class * Refine * InterfacesMIB supports counter override * (reformat) * Add missing test data * Remvoe unused code * Refactor * (reformat) * InterfaceMIBObjects supports counter override
1 parent 0f2bbd7 commit a559828

9 files changed

Lines changed: 324 additions & 70 deletions

File tree

src/ax_interface/mib.py

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,22 +86,16 @@ def __new__(mcs, name, bases, attributes, prefix=None):
8686
for me in vars(cls).values():
8787
if isinstance(me, MIBEntry):
8888
setattr(me, MIBEntry.PREFIXLEN, _prefix_len + len(me.subtree))
89+
setattr(me, MIBEntry.PREFIX, _prefix + me.subtree)
8990

9091
sub_ids = {}
9192

92-
# gather all static MIB entries.
93-
static_entries = (v for v in vars(cls).values() if type(v) is MIBEntry)
94-
for me in static_entries:
93+
# gather all MIB entries.
94+
mib_entries = (v for v in vars(cls).values() if isinstance(v, MIBEntry))
95+
for me in mib_entries:
9596
sub_ids.update({_prefix + me.subtree: me})
9697
prefixes.append(_prefix + me.subtree)
9798

98-
# gather all subtree IDs
99-
# to support dynamic sub_id in the subtree, not to pour leaves into dictionary
100-
subtree_entries = (v for v in vars(cls).values() if type(v) is SubtreeMIBEntry)
101-
for sme in subtree_entries:
102-
sub_ids.update({_prefix + sme.subtree: sme})
103-
prefixes.append(_prefix + sme.subtree)
104-
10599
# gather all updater instances
106100
updaters = set(v for k, v in vars(cls).items() if isinstance(v, MIBUpdater))
107101

@@ -134,6 +128,7 @@ def __init__(cls, name, bases, attributes, prefix=None):
134128

135129
class MIBEntry:
136130
PREFIXLEN = '__prefixlen__'
131+
PREFIX = '__prefix__'
137132

138133
def __init__(self, subtree, value_type, callable_, *args):
139134
"""
@@ -155,7 +150,7 @@ def __init__(self, subtree, value_type, callable_, *args):
155150
raise ValueError("Third argument must be a callable object--got literal instead.")
156151
self._callable_ = callable_
157152
self._callable_args = args
158-
self.subtree = subtree
153+
self.subtree_str = subtree
159154
self.value_type = value_type
160155
self.subtree = util.oid2tuple(subtree, dot_prefix=False)
161156

@@ -174,8 +169,11 @@ def replace_sub_id(self, oid_key, sub_id):
174169
def get_next(self, sub_id):
175170
return None
176171

172+
def get_prefix(self):
173+
return getattr(self, MIBEntry.PREFIX)
174+
177175
class SubtreeMIBEntry(MIBEntry):
178-
def __init__(self, subtree, iterator, value_type, callable_, *args, updater=None):
176+
def __init__(self, subtree, iterator, value_type, callable_, *args):
179177
super().__init__(subtree, value_type, callable_, *args)
180178
self.iterator = iterator
181179

@@ -209,6 +207,46 @@ def get_next(self, sub_id):
209207
logger.exception("SubtreeMIBEntry.get_next() caught an unexpected exception during iterator.get_next()")
210208
return None
211209

210+
# Define MIB entry (subtree) with a callable, which accepts a starndard OID tuple as a paramter
211+
class OidMIBEntry(MIBEntry):
212+
def __init__(self, subtree, value_type, callable_):
213+
super().__init__(subtree, value_type, callable_)
214+
215+
def __iter__(self):
216+
raise NotImplementedError
217+
218+
def __call__(self, sub_id):
219+
return self._callable_.__call__(self.get_prefix() + sub_id)
220+
221+
class OverlayAdpaterMIBEntry(MIBEntry):
222+
def __init__(self, underlay_mibentry, overlay_mibentry):
223+
assert underlay_mibentry.value_type == overlay_mibentry.value_type
224+
assert underlay_mibentry.subtree == overlay_mibentry.subtree
225+
226+
super().__init__(underlay_mibentry.subtree_str, underlay_mibentry.value_type, underlay_mibentry._callable_)
227+
self.underlay_mibentry = underlay_mibentry
228+
self.overlay_mibentry = overlay_mibentry
229+
230+
def __setattr__(self, name, value):
231+
super().__setattr__(name, value)
232+
if name.startswith('__') and name.endswith('__'):
233+
setattr(self.underlay_mibentry, name, value)
234+
setattr(self.overlay_mibentry, name, value)
235+
236+
def __iter__(self):
237+
return self.underlay_mibentry.__iter__()
238+
239+
def __call__(self, sub_id=None):
240+
overlay_val = self.overlay_mibentry(sub_id)
241+
if overlay_val is not None:
242+
return overlay_val
243+
244+
underlay_val = self.underlay_mibentry(sub_id)
245+
return underlay_val
246+
247+
def get_next(self, sub_id):
248+
return self.underlay_mibentry.get_next(sub_id)
249+
212250
class MIBTable(dict):
213251
"""
214252
Simplistic LUT for Get/GetNext OID. Interprets iterables as keys and implements the same interfaces as dict's.

src/sonic_ax_impl/mibs/__init__.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from swsssdk import SonicV2Connector
55
from swsssdk import port_util
66
from swsssdk.port_util import get_index, get_index_from_str
7+
from ax_interface.mib import MIBUpdater
8+
from ax_interface.util import oid2tuple
79
from sonic_ax_impl import logger
810

911
COUNTERS_PORT_NAME_MAP = b'COUNTERS_PORT_NAME_MAP'
@@ -16,6 +18,7 @@
1618
COUNTERS_DB = 'COUNTERS_DB'
1719
CONFIG_DB = 'CONFIG_DB'
1820
STATE_DB = 'STATE_DB'
21+
SNMP_OVERLAY_DB = 'SNMP_OVERLAY_DB'
1922

2023
TABLE_NAME_SEPARATOR_COLON = ':'
2124
TABLE_NAME_SEPARATOR_VBAR = '|'
@@ -363,3 +366,56 @@ def get_transceiver_sensor_sub_id(ifindex, sensor):
363366

364367
transceiver_oid, = get_transceiver_sub_id(ifindex)
365368
return (transceiver_oid + SENSOR_PART_ID_MAP[sensor], )
369+
370+
class RedisOidTreeUpdater(MIBUpdater):
371+
def __init__(self, prefix_str):
372+
super().__init__()
373+
374+
self.db_conn = init_db()
375+
if prefix_str.startswith('.'):
376+
prefix_str = prefix_str[1:]
377+
self.prefix_str = prefix_str
378+
379+
def get_next(self, sub_id):
380+
"""
381+
:param sub_id: The 1-based sub-identifier query.
382+
:return: the next sub id.
383+
"""
384+
raise NotImplementedError
385+
386+
def reinit_data(self):
387+
"""
388+
Subclass update loopback information
389+
"""
390+
pass
391+
392+
def update_data(self):
393+
"""
394+
Update redis (caches config)
395+
Pulls the table references for each interface.
396+
"""
397+
self.oid_list = []
398+
self.oid_map = {}
399+
400+
self.db_conn.connect(SNMP_OVERLAY_DB)
401+
keys = self.db_conn.keys(SNMP_OVERLAY_DB, self.prefix_str + '*')
402+
# TODO: fix db_conn.keys to return empty list instead of None if there is no match
403+
if keys is None:
404+
keys = []
405+
406+
for key in keys:
407+
key = key.decode()
408+
oid = oid2tuple(key, dot_prefix=False)
409+
self.oid_list.append(oid)
410+
value = self.db_conn.get_all(SNMP_OVERLAY_DB, key)
411+
if value[b'type'] in [b'COUNTER_32', b'COUNTER_64']:
412+
self.oid_map[oid] = int(value[b'data'])
413+
else:
414+
raise ValueError("Invalid value type")
415+
416+
self.oid_list.sort()
417+
418+
def get_oidvalue(self, oid):
419+
if oid not in self.oid_map:
420+
return None
421+
return self.oid_map[oid]

src/sonic_ax_impl/mibs/ietf/rfc1213.py

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
from bisect import bisect_right
55

66
from sonic_ax_impl import mibs
7-
from ax_interface import MIBMeta, ValueType, MIBUpdater, MIBEntry, SubtreeMIBEntry
7+
from ax_interface.mib import MIBMeta, ValueType, MIBUpdater, MIBEntry, SubtreeMIBEntry, OverlayAdpaterMIBEntry, OidMIBEntry
88
from ax_interface.encodings import ObjectIdentifier
99
from ax_interface.util import mac_decimals, ip2tuple_v4
1010

11-
1211
@unique
1312
class DbTables(int, Enum):
1413
"""
@@ -271,6 +270,7 @@ def get_counter(self, sub_id, table_name):
271270
:param table_name: the redis table (either IntEnum or string literal) to query.
272271
:return: the counter for the respective sub_id/table.
273272
"""
273+
274274
oid = self.get_oid(sub_id)
275275
if not oid:
276276
return
@@ -423,14 +423,15 @@ def get_if_type(self, sub_id):
423423
else:
424424
return IfTypes.ethernetCsmacd
425425

426-
427426
class InterfacesMIB(metaclass=MIBMeta, prefix='.1.3.6.1.2.1.2'):
428427
"""
429428
'interfaces' https://tools.ietf.org/html/rfc1213#section-3.5
430429
"""
431430

432431
if_updater = InterfacesUpdater()
433432

433+
oidtree_updater = mibs.RedisOidTreeUpdater(prefix_str='1.3.6.1.2.1.2')
434+
434435
# (subtree, value_type, callable_, *args, handler=None)
435436
ifNumber = MIBEntry('1', ValueType.INTEGER, if_updater.get_if_number)
436437

@@ -467,52 +468,88 @@ class InterfacesMIB(metaclass=MIBMeta, prefix='.1.3.6.1.2.1.2'):
467468
SubtreeMIBEntry('2.1.9', if_updater, ValueType.TIME_TICKS, lambda sub_id: 0)
468469

469470
ifInOctets = \
470-
SubtreeMIBEntry('2.1.10', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
471-
DbTables(10))
471+
OverlayAdpaterMIBEntry(
472+
SubtreeMIBEntry('2.1.10', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
473+
DbTables(10)),
474+
OidMIBEntry('2.1.10', ValueType.COUNTER_32, oidtree_updater.get_oidvalue)
475+
)
472476

473477
ifInUcastPkts = \
474-
SubtreeMIBEntry('2.1.11', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
475-
DbTables(11))
478+
OverlayAdpaterMIBEntry(
479+
SubtreeMIBEntry('2.1.11', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
480+
DbTables(11)),
481+
OidMIBEntry('2.1.11', ValueType.COUNTER_32, oidtree_updater.get_oidvalue)
482+
)
476483

477484
ifInNUcastPkts = \
478-
SubtreeMIBEntry('2.1.12', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
479-
DbTables(12))
485+
OverlayAdpaterMIBEntry(
486+
SubtreeMIBEntry('2.1.12', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
487+
DbTables(12)),
488+
OidMIBEntry('2.1.12', ValueType.COUNTER_32, oidtree_updater.get_oidvalue)
489+
)
480490

481491
ifInDiscards = \
482-
SubtreeMIBEntry('2.1.13', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
483-
DbTables(13))
492+
OverlayAdpaterMIBEntry(
493+
SubtreeMIBEntry('2.1.13', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
494+
DbTables(13)),
495+
OidMIBEntry('2.1.13', ValueType.COUNTER_32, oidtree_updater.get_oidvalue)
496+
)
484497

485498
ifInErrors = \
486-
SubtreeMIBEntry('2.1.14', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
487-
DbTables(14))
499+
OverlayAdpaterMIBEntry(
500+
SubtreeMIBEntry('2.1.14', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
501+
DbTables(14)),
502+
OidMIBEntry('2.1.14', ValueType.COUNTER_32, oidtree_updater.get_oidvalue)
503+
)
488504

489505
ifInUnknownProtos = \
490-
SubtreeMIBEntry('2.1.15', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
491-
DbTables(15))
506+
OverlayAdpaterMIBEntry(
507+
SubtreeMIBEntry('2.1.15', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
508+
DbTables(15)),
509+
OidMIBEntry('2.1.15', ValueType.COUNTER_32, oidtree_updater.get_oidvalue)
510+
)
492511

493512
ifOutOctets = \
494-
SubtreeMIBEntry('2.1.16', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
495-
DbTables(16))
513+
OverlayAdpaterMIBEntry(
514+
SubtreeMIBEntry('2.1.16', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
515+
DbTables(16)),
516+
OidMIBEntry('2.1.16', ValueType.COUNTER_32, oidtree_updater.get_oidvalue)
517+
)
496518

497519
ifOutUcastPkts = \
498-
SubtreeMIBEntry('2.1.17', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
499-
DbTables(17))
520+
OverlayAdpaterMIBEntry(
521+
SubtreeMIBEntry('2.1.17', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
522+
DbTables(17)),
523+
OidMIBEntry('2.1.17', ValueType.COUNTER_32, oidtree_updater.get_oidvalue)
524+
)
500525

501526
ifOutNUcastPkts = \
502-
SubtreeMIBEntry('2.1.18', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
503-
DbTables(18))
527+
OverlayAdpaterMIBEntry(
528+
SubtreeMIBEntry('2.1.18', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
529+
DbTables(18)),
530+
OidMIBEntry('2.1.18', ValueType.COUNTER_32, oidtree_updater.get_oidvalue)
531+
)
504532

505533
ifOutDiscards = \
506-
SubtreeMIBEntry('2.1.19', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
507-
DbTables(19))
534+
OverlayAdpaterMIBEntry(
535+
SubtreeMIBEntry('2.1.19', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
536+
DbTables(19)),
537+
OidMIBEntry('2.1.19', ValueType.COUNTER_32, oidtree_updater.get_oidvalue)
538+
)
508539

509540
ifOutErrors = \
510-
SubtreeMIBEntry('2.1.20', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
511-
DbTables(20))
541+
OverlayAdpaterMIBEntry(
542+
SubtreeMIBEntry('2.1.20', if_updater, ValueType.COUNTER_32, if_updater.get_counter,
543+
DbTables(20)),
544+
OidMIBEntry('2.1.20', ValueType.COUNTER_32, oidtree_updater.get_oidvalue)
545+
)
512546

513547
ifOutQLen = \
514-
SubtreeMIBEntry('2.1.21', if_updater, ValueType.GAUGE_32, if_updater.get_counter,
515-
DbTables(21))
548+
OverlayAdpaterMIBEntry(
549+
SubtreeMIBEntry('2.1.21', if_updater, ValueType.GAUGE_32, if_updater.get_counter,
550+
DbTables(21)),
551+
OidMIBEntry('2.1.21', ValueType.GAUGE_32, oidtree_updater.get_oidvalue)
552+
)
516553

517554
# FIXME Placeholder
518555
ifSpecific = \

0 commit comments

Comments
 (0)