Skip to content

Commit 373a061

Browse files
raphaelt-nvidiaSuvarnaMeenakshi
authored andcommitted
Restored snmp vlan support per RFC1213 and added the missing support for RFC2863 (sonic-net#218)
- What I did Restored snmp vlan support per RFC1213, which had been reverted due to inconsistency with RFC2863, and added the missing support for RFC2863. Added unit tests for RFC2863. - How I did it Reverted sonic-net#191, which was itself a revert of sonic-net#169. Then added code to support vlan in rfc2863.py and unit tests. Since a long time has elapsed since the original commit and other code has been pushed in the meantime, great care is needed in merging. Note in particular that mibs.init_sync_d_lag_tables now returns five parameters, the last two of which were added: lag_sai_map and sai_lap_map. This PR needs one of those maps, and a concurrent commit supporting RFC4363 needs the other, so all the callers were updated and use the one they need. - How to verify it Unit tests are run via make target/python-wheels/asyncsnmp-2.1.0-py3-none-any.whl. See also Azure#169. - Description for the changelog Restored support for aggregated router interface counters and L3 VLAN counters to RFC1213 MIB, and extended to RFC2863. (cherry picked from commit 266bd15)
1 parent 7147354 commit 373a061

19 files changed

+2042
-63
lines changed

src/sonic_ax_impl/mibs/__init__.py

+71-6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,22 @@
2626
TABLE_NAME_SEPARATOR_COLON = ':'
2727
TABLE_NAME_SEPARATOR_VBAR = '|'
2828

29+
HOST_NAMESPACE_DB_IDX = 0
30+
31+
RIF_COUNTERS_AGGR_MAP = {
32+
"SAI_PORT_STAT_IF_IN_OCTETS": "SAI_ROUTER_INTERFACE_STAT_IN_OCTETS",
33+
"SAI_PORT_STAT_IF_IN_UCAST_PKTS": "SAI_ROUTER_INTERFACE_STAT_IN_PACKETS",
34+
"SAI_PORT_STAT_IF_IN_ERRORS": "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS",
35+
"SAI_PORT_STAT_IF_OUT_OCTETS": "SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS",
36+
"SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS",
37+
"SAI_PORT_STAT_IF_OUT_ERRORS": "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS"
38+
}
39+
40+
RIF_DROPS_AGGR_MAP = {
41+
"SAI_PORT_STAT_IF_IN_ERRORS": "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS",
42+
"SAI_PORT_STAT_IF_OUT_ERRORS": "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS"
43+
}
44+
2945
redis_kwargs = {'unix_socket_path': '/var/run/redis/redis.sock'}
3046

3147

@@ -135,6 +151,14 @@ def if_entry_table(if_name):
135151
return 'PORT_TABLE:' + if_name
136152

137153

154+
def vlan_entry_table(if_name):
155+
"""
156+
:param if_name: given interface to cast.
157+
:return: VLAN_TABLE key.
158+
"""
159+
return 'VLAN_TABLE:' + if_name
160+
161+
138162
def lag_entry_table(lag_name):
139163
"""
140164
:param lag_name: given lag to cast.
@@ -296,11 +320,52 @@ def init_sync_d_interface_tables(db_conn):
296320

297321
return if_name_map, if_alias_map, if_id_map, oid_name_map
298322

323+
324+
def init_sync_d_rif_tables(db_conn):
325+
"""
326+
Initializes map of RIF SAI oids to port SAI oid.
327+
:return: dict
328+
"""
329+
rif_port_map = {get_sai_id_key(db_conn.namespace, rif): get_sai_id_key(db_conn.namespace, port)
330+
for rif, port in port_util.get_rif_port_map(db_conn).items()}
331+
port_rif_map = {port: rif for rif, port in rif_port_map.items()}
332+
logger.debug("Rif port map:\n" + pprint.pformat(rif_port_map, indent=2))
333+
334+
return rif_port_map, port_rif_map
335+
336+
337+
def init_sync_d_vlan_tables(db_conn):
338+
"""
339+
Initializes vlan interface maps for SyncD-connected MIB(s).
340+
:return: tuple(vlan_name_map, oid_sai_map, oid_name_map)
341+
"""
342+
343+
vlan_name_map = port_util.get_vlan_interface_oid_map(db_conn)
344+
345+
logger.debug("Vlan oid map:\n" + pprint.pformat(vlan_name_map, indent=2))
346+
347+
oid_sai_map = {}
348+
oid_name_map = {}
349+
for sai_id, if_name in vlan_name_map.items():
350+
port_index = get_index_from_str(if_name)
351+
if not port_index:
352+
continue
353+
# { OID -> sai_id }
354+
oid_sai_map[port_index] = sai_id
355+
# { OID -> if_name (SONiC) }
356+
oid_name_map[port_index] = if_name
357+
358+
logger.debug("OID sai map:\n" + pprint.pformat(oid_sai_map, indent=2))
359+
logger.debug("OID name map:\n" + pprint.pformat(oid_name_map, indent=2))
360+
361+
return vlan_name_map, oid_sai_map, oid_name_map
362+
363+
299364
def init_sync_d_lag_tables(db_conn):
300365
"""
301366
Helper method. Connects to and initializes LAG interface maps for SyncD-connected MIB(s).
302367
:param db_conn: database connector
303-
:return: tuple(lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map)
368+
:return: tuple(lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map, lag_sai_map, sai_lag_map)
304369
"""
305370
# { lag_name (SONiC) -> [ lag_members (if_name) ] }
306371
# ex: { "PortChannel0" : [ "Ethernet0", "Ethernet4" ] }
@@ -320,7 +385,7 @@ def init_sync_d_lag_tables(db_conn):
320385
lag_entries = db_conn.keys(APPL_DB, "LAG_TABLE:*")
321386

322387
if not lag_entries:
323-
return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map, lag_sai_map
388+
return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map, lag_sai_map, sai_lag_map
324389

325390
db_conn.connect(COUNTERS_DB)
326391
lag_sai_map = db_conn.get_all(COUNTERS_DB, "COUNTERS_LAG_NAME_MAP")
@@ -349,7 +414,7 @@ def member_name_str(val, lag_name):
349414
if idx:
350415
oid_lag_name_map[idx] = if_name
351416

352-
return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map, sai_lag_map
417+
return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map, lag_sai_map, sai_lag_map
353418

354419
def init_sync_d_queue_tables(db_conn):
355420
"""
@@ -364,7 +429,7 @@ def init_sync_d_queue_tables(db_conn):
364429

365430
# Parse the queue_name_map and create the following maps:
366431
# port_queues_map -> {"port_index : queue_index" : sai_oid}
367-
# queue_stat_map -> {"port_index : queue stat table name" : {counter name : value}}
432+
# queue_stat_map -> {"port_index : queue stat table name" : {counter name : value}}
368433
# port_queue_list_map -> {port_index: [sorted queue list]}
369434
port_queues_map = {}
370435
queue_stat_map = {}
@@ -428,7 +493,7 @@ class RedisOidTreeUpdater(MIBUpdater):
428493
def __init__(self, prefix_str):
429494
super().__init__()
430495

431-
self.db_conn = Namespace.init_namespace_dbs()
496+
self.db_conn = Namespace.init_namespace_dbs()
432497
if prefix_str.startswith('.'):
433498
prefix_str = prefix_str[1:]
434499
self.prefix_str = prefix_str
@@ -551,7 +616,7 @@ def dbs_get_all(dbs, db_name, _hash, *args, **kwargs):
551616
db get_all function executed on global and all namespace DBs.
552617
"""
553618
result = {}
554-
# If there are multiple namespaces, _hash might not be
619+
# If there are multiple namespaces, _hash might not be
555620
# present in all namespace, ignore if not present in a
556621
# specific namespace.
557622
if len(dbs) > 1:

src/sonic_ax_impl/mibs/ietf/rfc1213.py

+117-4
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ class DbTables(int, Enum):
5050
class IfTypes(int, Enum):
5151
""" IANA ifTypes """
5252
ethernetCsmacd = 6
53-
ieee8023adLag = 161
53+
l3ipvlan = 136
54+
ieee8023adLag = 161
5455

5556
class ArpUpdater(MIBUpdater):
5657
def __init__(self):
@@ -196,8 +197,13 @@ def __init__(self):
196197
self.lag_name_if_name_map = {}
197198
self.if_name_lag_name_map = {}
198199
self.oid_lag_name_map = {}
200+
self.lag_sai_map = {}
199201
self.mgmt_oid_name_map = {}
200202
self.mgmt_alias_map = {}
203+
self.vlan_oid_name_map = {}
204+
self.vlan_name_map = {}
205+
self.rif_port_map = {}
206+
self.port_rif_map = {}
201207

202208
# cache of interface counters
203209
self.if_counters = {}
@@ -206,6 +212,8 @@ def __init__(self):
206212
self.if_alias_map = {}
207213
self.if_id_map = {}
208214
self.oid_name_map = {}
215+
self.rif_counters = {}
216+
209217
self.namespace_db_map = Namespace.get_namespace_db_map(self.db_conn)
210218

211219
def reinit_data(self):
@@ -228,6 +236,13 @@ def reinit_data(self):
228236
self.if_name_lag_name_map, \
229237
self.oid_lag_name_map, _ = Namespace.get_sync_d_from_all_namespace(mibs.init_sync_d_lag_tables, self.db_conn)
230238

239+
self.vlan_name_map, \
240+
self.vlan_oid_sai_map, \
241+
self.vlan_oid_name_map = Namespace.get_sync_d_from_all_namespace(mibs.init_sync_d_vlan_tables, self.db_conn)
242+
243+
self.rif_port_map, \
244+
self.port_rif_map = Namespace.get_sync_d_from_all_namespace(mibs.init_sync_d_rif_tables, self.db_conn)
245+
231246
def update_data(self):
232247
"""
233248
Update redis (caches config)
@@ -242,11 +257,43 @@ def update_data(self):
242257
counter_table = {}
243258
self.if_counters[if_idx] = counter_table
244259

260+
self.update_if_counters()
261+
self.update_rif_counters()
262+
263+
self.aggregate_counters()
264+
265+
self.lag_name_if_name_map, \
266+
self.if_name_lag_name_map, \
267+
self.oid_lag_name_map, \
268+
self.lag_sai_map, self.sai_lag_map = Namespace.get_sync_d_from_all_namespace(mibs.init_sync_d_lag_tables, self.db_conn)
269+
245270
self.if_range = sorted(list(self.oid_name_map.keys()) +
246271
list(self.oid_lag_name_map.keys()) +
247-
list(self.mgmt_oid_name_map.keys()))
272+
list(self.mgmt_oid_name_map.keys()) +
273+
list(self.vlan_oid_name_map.keys()))
248274
self.if_range = [(i,) for i in self.if_range]
249275

276+
def update_if_counters(self):
277+
for sai_id_key in self.if_id_map:
278+
namespace, sai_id = mibs.split_sai_id_key(sai_id_key)
279+
if_idx = mibs.get_index_from_str(self.if_id_map[sai_id_key])
280+
counters_db_data = self.namespace_db_map[namespace].get_all(mibs.COUNTERS_DB,
281+
mibs.counter_table(sai_id),
282+
blocking=True)
283+
self.if_counters[if_idx] = {
284+
counter: int(value) for counter, value in counters_db_data.items()
285+
}
286+
287+
def update_rif_counters(self):
288+
rif_sai_ids = list(self.rif_port_map) + list(self.vlan_name_map)
289+
for sai_id in rif_sai_ids:
290+
counters_db_data = Namespace.dbs_get_all(self.db_conn, mibs.COUNTERS_DB,
291+
mibs.counter_table(mibs.split_sai_id_key(sai_id)[1]),
292+
blocking=False)
293+
self.rif_counters[sai_id] = {
294+
counter: int(value) for counter, value in counters_db_data.items()
295+
}
296+
250297
def get_next(self, sub_id):
251298
"""
252299
:param sub_id: The 1-based sub-identifier query.
@@ -288,6 +335,8 @@ def interface_description(self, sub_id):
288335
return self.oid_lag_name_map[oid]
289336
elif oid in self.mgmt_oid_name_map:
290337
return self.mgmt_alias_map[self.mgmt_oid_name_map[oid]]
338+
elif oid in self.vlan_oid_name_map:
339+
return self.vlan_oid_name_map[oid]
291340

292341
return self.if_alias_map[self.oid_name_map[oid]]
293342

@@ -298,18 +347,46 @@ def _get_counter(self, oid, table_name):
298347
:return: the counter for the respective sub_id/table.
299348
"""
300349
# Enum.name or table_name = 'name_of_the_table'
350+
# Example:
351+
# table_name = <DbTables.SAI_PORT_STAT_IF_OUT_ERRORS: 20>
352+
# _table_name = 'SAI_PORT_STAT_IF_OUT_ERRORS'
301353
_table_name = getattr(table_name, 'name', table_name)
302354

303355
try:
304356
counter_value = self.if_counters[oid][_table_name]
305357
# truncate to 32-bit counter (database implements 64-bit counters)
306-
counter_value = int(counter_value) & 0x00000000ffffffff
358+
counter_value = counter_value & 0x00000000ffffffff
307359
# done!
308360
return counter_value
309361
except KeyError as e:
310362
mibs.logger.warning("SyncD 'COUNTERS_DB' missing attribute '{}'.".format(e))
311363
return None
312364

365+
def aggregate_counters(self):
366+
"""
367+
For ports with l3 router interfaces l3 drops may be counted separately (RIF counters)
368+
add l3 drops to l2 drop counters cache according to mapping
369+
370+
For l3vlan map l3 counters to l2 counters
371+
"""
372+
for rif_sai_id, port_sai_id in self.rif_port_map.items():
373+
if port_sai_id in self.if_id_map:
374+
port_idx = mibs.get_index_from_str(self.if_id_map[port_sai_id])
375+
for port_counter_name, rif_counter_name in mibs.RIF_DROPS_AGGR_MAP.items():
376+
self.if_counters[port_idx][port_counter_name] = \
377+
self.if_counters[port_idx][port_counter_name] + \
378+
self.rif_counters[rif_sai_id][rif_counter_name]
379+
380+
for vlan_sai_id, vlan_name in self.vlan_name_map.items():
381+
for port_counter_name, rif_counter_name in mibs.RIF_COUNTERS_AGGR_MAP.items():
382+
vlan_idx = mibs.get_index_from_str(vlan_name)
383+
vlan_rif_counters = self.rif_counters[vlan_sai_id]
384+
if rif_counter_name in vlan_rif_counters:
385+
self.if_counters.setdefault(vlan_idx, {})
386+
self.if_counters[vlan_idx][port_counter_name] = \
387+
vlan_rif_counters[rif_counter_name]
388+
389+
313390
def get_counter(self, sub_id, table_name):
314391
"""
315392
:param sub_id: The 1-based sub-identifier query.
@@ -327,9 +404,40 @@ def get_counter(self, sub_id, table_name):
327404
return 0
328405
elif oid in self.oid_lag_name_map:
329406
counter_value = 0
407+
# Sum the values of this counter for all ports in the LAG.
408+
# Example:
409+
# table_name = <DbTables.SAI_PORT_STAT_IF_OUT_ERRORS: 20>
410+
# oid = 1001
411+
# self.oid_lag_name_map = {1001: 'PortChannel01', 1002: 'PortChannel02', 1003: 'PortChannel03'}
412+
# self.oid_lag_name_map[oid] = 'PortChannel01'
413+
# self.lag_name_if_name_map = {'PortChannel01': ['Ethernet112'], 'PortChannel02': ['Ethernet116'], 'PortChannel03': ['Ethernet120']}
414+
# self.lag_name_if_name_map['PortChannel01'] = ['Ethernet112']
415+
# mibs.get_index_from_str('Ethernet112') = 113 (because Ethernet N = N + 1)
416+
# self._get_counter retrieves the counter per oid and table.
330417
for lag_member in self.lag_name_if_name_map[self.oid_lag_name_map[oid]]:
331418
counter_value += self._get_counter(mibs.get_index_from_str(lag_member), table_name)
332-
419+
# Check if we need to add a router interface count.
420+
# Example:
421+
# self.lag_sai_map = {'PortChannel01': '2000000000006', 'PortChannel02': '2000000000005', 'PortChannel03': '2000000000004'}
422+
# self.port_rif_map = {'2000000000006': '6000000000006', '2000000000005': '6000000000005', '2000000000004': '6000000000004'}
423+
# self.rif_port_map = {'6000000000006': '2000000000006', '6000000000005': '2000000000005', '6000000000004': '2000000000004'}
424+
# self.lag_sai_map['PortChannel01'] = '2000000000006'
425+
# self.port_rif_map['2000000000006'] = '6000000000006'
426+
sai_lag_id = self.lag_sai_map[self.oid_lag_name_map[oid]]
427+
sai_lag_rif_id = self.port_rif_map[sai_lag_id]
428+
if sai_lag_rif_id in self.rif_port_map:
429+
# Extract the 'name' part of 'table_name'.
430+
# Example:
431+
# table_name = <DbTables.SAI_PORT_STAT_IF_OUT_ERRORS: 20>
432+
# _table_name = 'SAI_PORT_STAT_IF_OUT_ERRORS'
433+
table_name = getattr(table_name, 'name', table_name)
434+
# Find rif counter table if applicable and add the count for this table.
435+
# Example:
436+
# mibs.RIF_DROPS_AGGR_MAP = {'SAI_PORT_STAT_IF_IN_ERRORS': 'SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS', 'SAI_PORT_STAT_IF_OUT_ERRORS': 'SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS'}
437+
# self.rif_counters['6000000000006'] = {'SAI_ROUTER_INTERFACE_STAT_IN_PACKETS': 6, ... 'SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS': 6, ...}
438+
if table_name in mibs.RIF_DROPS_AGGR_MAP:
439+
rif_table_name = mibs.RIF_DROPS_AGGR_MAP[table_name]
440+
counter_value += self.rif_counters[sai_lag_rif_id].get(rif_table_name, 0)
333441
# truncate to 32-bit counter
334442
return counter_value & 0x00000000ffffffff
335443
else:
@@ -359,6 +467,8 @@ def _get_if_entry(self, sub_id):
359467
elif oid in self.mgmt_oid_name_map:
360468
if_table = mibs.mgmt_if_entry_table(self.mgmt_oid_name_map[oid])
361469
db = mibs.CONFIG_DB
470+
elif oid in self.vlan_oid_name_map:
471+
if_table = mibs.vlan_entry_table(self.vlan_oid_name_map[oid])
362472
elif oid in self.oid_name_map:
363473
if_table = mibs.if_entry_table(self.oid_name_map[oid])
364474
else:
@@ -463,6 +573,7 @@ def get_if_type(self, sub_id):
463573
464574
ethernetCsmacd(6), -- for all ethernet-like interfaces,
465575
-- regardless of speed, as per RFC3635
576+
l3ipvlan(136) -- Layer 3 Virtual LAN using IP
466577
ieee8023adLag(161) -- IEEE 802.3ad Link Aggregate
467578
"""
468579
oid = self.get_oid(sub_id)
@@ -471,6 +582,8 @@ def get_if_type(self, sub_id):
471582

472583
if oid in self.oid_lag_name_map:
473584
return IfTypes.ieee8023adLag
585+
elif oid in self.vlan_oid_name_map:
586+
return IfTypes.l3ipvlan
474587
else:
475588
return IfTypes.ethernetCsmacd
476589

0 commit comments

Comments
 (0)