Skip to content

Commit 253f58e

Browse files
authored
[rfc1213] Interface MIB add l3 vlan interfaces & aggregate rif counters (#133)
* [rfc1213] Interface MIB add l3 vlan interfaces * [rfc1213] aggregate rifcounters on top of l2 counters * fix issues * add unittests * add mock data * cleanup * lag rif fixes * add more unittests * update test_mibs.py * fix comments * update namespace/test_mibs.py unittest * [rfc1213] add vlan interface admin_status * only aggregate errors * add vlan subinterface unitttests * fix init_sync_d_lag * update namespace mib test * add namespace mock table data
1 parent eba1408 commit 253f58e

File tree

12 files changed

+855
-27
lines changed

12 files changed

+855
-27
lines changed

src/sonic_ax_impl/mibs/__init__.py

+106-5
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@
4343
"tx4power": 43,
4444
}
4545

46+
RIF_COUNTERS_AGGR_MAP = {
47+
b"SAI_PORT_STAT_IF_IN_OCTETS": b"SAI_ROUTER_INTERFACE_STAT_IN_OCTETS",
48+
b"SAI_PORT_STAT_IF_IN_UCAST_PKTS": b"SAI_ROUTER_INTERFACE_STAT_IN_PACKETS",
49+
b"SAI_PORT_STAT_IF_IN_ERRORS": b"SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS",
50+
b"SAI_PORT_STAT_IF_OUT_OCTETS": b"SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS",
51+
b"SAI_PORT_STAT_IF_OUT_UCAST_PKTS": b"SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS",
52+
b"SAI_PORT_STAT_IF_OUT_ERRORS": b"SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS"
53+
}
54+
55+
RIF_DROPS_AGGR_MAP = {
56+
b"SAI_PORT_STAT_IF_IN_ERRORS": b"SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS",
57+
b"SAI_PORT_STAT_IF_OUT_ERRORS": b"SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS"
58+
}
59+
4660
# IfIndex to OID multiplier for transceiver
4761
IFINDEX_SUB_ID_MULTIPLIER = 1000
4862

@@ -113,6 +127,14 @@ def if_entry_table(if_name):
113127
return b'PORT_TABLE:' + if_name
114128

115129

130+
def vlan_entry_table(if_name):
131+
"""
132+
:param if_name: given interface to cast.
133+
:return: VLAN_TABLE key.
134+
"""
135+
return b'VLAN_TABLE:' + if_name
136+
137+
116138
def lag_entry_table(lag_name):
117139
"""
118140
:param lag_name: given lag to cast.
@@ -244,6 +266,48 @@ def init_sync_d_interface_tables(db_conn):
244266

245267
return if_name_map, if_alias_map, if_id_map, oid_sai_map, oid_name_map
246268

269+
270+
def init_sync_d_rif_tables(db_conn):
271+
"""
272+
Initializes map of RIF SAI oids to port SAI oid.
273+
:return: dict
274+
"""
275+
rif_port_map = port_util.get_rif_port_map(db_conn)
276+
277+
if not rif_port_map:
278+
return {}, {}
279+
port_rif_map = {port: rif for rif, port in rif_port_map.items()}
280+
logger.debug("Rif port map:\n" + pprint.pformat(rif_port_map, indent=2))
281+
282+
return rif_port_map, port_rif_map
283+
284+
285+
def init_sync_d_vlan_tables(db_conn):
286+
"""
287+
Initializes vlan interface maps for SyncD-connected MIB(s).
288+
:return: tuple(vlan_name_map, oid_sai_map, oid_name_map)
289+
"""
290+
291+
vlan_name_map = port_util.get_vlan_interface_oid_map(db_conn)
292+
293+
logger.debug("Vlan oid map:\n" + pprint.pformat(vlan_name_map, indent=2))
294+
295+
# { OID -> sai_id }
296+
oid_sai_map = {get_index(if_name): sai_id for sai_id, if_name in vlan_name_map.items()
297+
# only map the interface if it's a style understood to be a SONiC interface.
298+
if get_index(if_name) is not None}
299+
logger.debug("OID sai map:\n" + pprint.pformat(oid_sai_map, indent=2))
300+
301+
# { OID -> if_name (SONiC) }
302+
oid_name_map = {get_index(if_name): if_name for sai_id, if_name in vlan_name_map.items()
303+
# only map the interface if it's a style understood to be a SONiC interface.
304+
if get_index(if_name) is not None}
305+
306+
logger.debug("OID name map:\n" + pprint.pformat(oid_name_map, indent=2))
307+
308+
return vlan_name_map, oid_sai_map, oid_name_map
309+
310+
247311
def init_sync_d_lag_tables(db_conn):
248312
"""
249313
Helper method. Connects to and initializes LAG interface maps for SyncD-connected MIB(s).
@@ -258,13 +322,18 @@ def init_sync_d_lag_tables(db_conn):
258322
if_name_lag_name_map = {}
259323
# { OID -> lag_name (SONiC) }
260324
oid_lag_name_map = {}
325+
# { lag_name (SONiC) -> lag_oid (SAI) }
326+
lag_sai_map = {}
261327

262328
db_conn.connect(APPL_DB)
263-
264329
lag_entries = db_conn.keys(APPL_DB, b"LAG_TABLE:*")
265330

266331
if not lag_entries:
267-
return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map
332+
return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map, lag_sai_map
333+
334+
db_conn.connect(COUNTERS_DB)
335+
lag_sai_map = db_conn.get_all(COUNTERS_DB, b"COUNTERS_LAG_NAME_MAP")
336+
lag_sai_map = {name: sai_id.lstrip(b"oid:0x") for name, sai_id in lag_sai_map.items()}
268337

269338
for lag_entry in lag_entries:
270339
lag_name = lag_entry[len(b"LAG_TABLE:"):]
@@ -286,7 +355,7 @@ def member_name_str(val, lag_name):
286355
if idx:
287356
oid_lag_name_map[idx] = if_name
288357

289-
return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map
358+
return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map, lag_sai_map
290359

291360
def init_sync_d_queue_tables(db_conn):
292361
"""
@@ -540,6 +609,7 @@ def init_namespace_sync_d_lag_tables(dbs):
540609
lag_name_if_name_map = {}
541610
if_name_lag_name_map = {}
542611
oid_lag_name_map = {}
612+
lag_sai_map = {}
543613

544614
"""
545615
all_ns_db - will have db_conn to all namespace DBs and
@@ -550,12 +620,43 @@ def init_namespace_sync_d_lag_tables(dbs):
550620
for db_conn in Namespace.get_non_host_dbs(dbs):
551621
lag_name_if_name_map_ns, \
552622
if_name_lag_name_map_ns, \
553-
oid_lag_name_map_ns = init_sync_d_lag_tables(db_conn)
623+
oid_lag_name_map_ns, \
624+
lag_sai_map_ns = init_sync_d_lag_tables(db_conn)
554625
lag_name_if_name_map.update(lag_name_if_name_map_ns)
555626
if_name_lag_name_map.update(if_name_lag_name_map_ns)
556627
oid_lag_name_map.update(oid_lag_name_map_ns)
628+
lag_sai_map.update(lag_sai_map_ns)
629+
630+
return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map, lag_sai_map
631+
632+
@staticmethod
633+
def init_namespace_sync_d_rif_tables(dbs):
634+
rif_port_map = {}
635+
port_rif_map = {}
636+
637+
for db_conn in Namespace.get_non_host_dbs(dbs):
638+
rif_port_map_ns, \
639+
port_rif_map_ns = init_sync_d_rif_tables(db_conn)
640+
rif_port_map.update(rif_port_map_ns)
641+
port_rif_map.update(port_rif_map_ns)
642+
643+
return rif_port_map, port_rif_map
644+
645+
@staticmethod
646+
def init_namespace_sync_d_vlan_tables(dbs):
647+
vlan_name_map = {}
648+
oid_sai_map = {}
649+
oid_name_map = {}
650+
651+
for db_conn in Namespace.get_non_host_dbs(dbs):
652+
vlan_name_map_ns, \
653+
oid_sai_map_ns, \
654+
oid_name_map_ns = init_sync_d_vlan_tables(db_conn)
655+
vlan_name_map.update(vlan_name_map_ns)
656+
oid_sai_map.update(oid_sai_map_ns)
657+
oid_name_map.update(oid_name_map_ns)
557658

558-
return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map
659+
return vlan_name_map, oid_sai_map, oid_name_map
559660

560661
@staticmethod
561662
def init_namespace_sync_d_queue_tables(dbs):

src/sonic_ax_impl/mibs/ietf/rfc1213.py

+73-5
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 import logger
78
from sonic_ax_impl.mibs import Namespace
89
from ax_interface.mib import MIBMeta, ValueType, MIBUpdater, MIBEntry, SubtreeMIBEntry, OverlayAdpaterMIBEntry, OidMIBEntry
910
from ax_interface.encodings import ObjectIdentifier
@@ -49,7 +50,8 @@ class DbTables(int, Enum):
4950
class IfTypes(int, Enum):
5051
""" IANA ifTypes """
5152
ethernetCsmacd = 6
52-
ieee8023adLag = 161
53+
l3ipvlan = 136
54+
ieee8023adLag = 161
5355

5456
class ArpUpdater(MIBUpdater):
5557
def __init__(self):
@@ -157,8 +159,13 @@ def __init__(self):
157159
self.lag_name_if_name_map = {}
158160
self.if_name_lag_name_map = {}
159161
self.oid_lag_name_map = {}
162+
self.lag_sai_map = {}
160163
self.mgmt_oid_name_map = {}
161164
self.mgmt_alias_map = {}
165+
self.vlan_oid_name_map = {}
166+
self.vlan_name_map = {}
167+
self.rif_port_map = {}
168+
self.port_rif_map = {}
162169

163170
# cache of interface counters
164171
self.if_counters = {}
@@ -168,6 +175,7 @@ def __init__(self):
168175
self.if_id_map = {}
169176
self.oid_sai_map = {}
170177
self.oid_name_map = {}
178+
self.rif_counters = {}
171179

172180
def reinit_data(self):
173181
"""
@@ -186,6 +194,13 @@ def reinit_data(self):
186194
self.mgmt_oid_name_map, \
187195
self.mgmt_alias_map = mibs.init_mgmt_interface_tables(self.db_conn[0])
188196

197+
self.vlan_name_map, \
198+
self.vlan_oid_sai_map, \
199+
self.vlan_oid_name_map = Namespace.init_namespace_sync_d_vlan_tables(self.db_conn)
200+
201+
self.rif_port_map, \
202+
self.port_rif_map = Namespace.init_namespace_sync_d_rif_tables(self.db_conn)
203+
189204
def update_data(self):
190205
"""
191206
Update redis (caches config)
@@ -195,13 +210,24 @@ def update_data(self):
195210
{sai_id: Namespace.dbs_get_all(self.db_conn, mibs.COUNTERS_DB, mibs.counter_table(sai_id), blocking=True)
196211
for sai_id in self.if_id_map}
197212

213+
rif_sai_ids = list(self.rif_port_map) + list(self.vlan_name_map)
214+
215+
self.rif_counters = \
216+
{sai_id: Namespace.dbs_get_all(self.db_conn, mibs.COUNTERS_DB, mibs.counter_table(sai_id), blocking=True)
217+
for sai_id in rif_sai_ids}
218+
219+
if self.rif_counters:
220+
self.aggregate_counters()
221+
198222
self.lag_name_if_name_map, \
199223
self.if_name_lag_name_map, \
200-
self.oid_lag_name_map = Namespace.init_namespace_sync_d_lag_tables(self.db_conn)
224+
self.oid_lag_name_map, \
225+
self.lag_sai_map = Namespace.init_namespace_sync_d_lag_tables(self.db_conn)
201226

202227
self.if_range = sorted(list(self.oid_sai_map.keys()) +
203228
list(self.oid_lag_name_map.keys()) +
204-
list(self.mgmt_oid_name_map.keys()))
229+
list(self.mgmt_oid_name_map.keys()) +
230+
list(self.vlan_oid_name_map.keys()))
205231
self.if_range = [(i,) for i in self.if_range]
206232

207233
def get_next(self, sub_id):
@@ -245,6 +271,8 @@ def interface_description(self, sub_id):
245271
return self.oid_lag_name_map[oid]
246272
elif oid in self.mgmt_oid_name_map:
247273
return self.mgmt_alias_map[self.mgmt_oid_name_map[oid]]
274+
elif oid in self.vlan_oid_name_map:
275+
return self.vlan_oid_name_map[oid]
248276

249277
return self.if_alias_map[self.oid_name_map[oid]]
250278

@@ -254,7 +282,13 @@ def _get_counter(self, oid, table_name):
254282
:param table_name: the redis table (either IntEnum or string literal) to query.
255283
:return: the counter for the respective sub_id/table.
256284
"""
257-
sai_id = self.oid_sai_map[oid]
285+
sai_id = ''
286+
if oid in self.oid_sai_map:
287+
sai_id = self.oid_sai_map[oid]
288+
elif oid in self.vlan_oid_sai_map:
289+
sai_id = self.vlan_oid_sai_map[oid]
290+
else:
291+
logger.warning("Unexpected oid {}".format(oid))
258292
# Enum.name or table_name = 'name_of_the_table'
259293
_table_name = bytes(getattr(table_name, 'name', table_name), 'utf-8')
260294

@@ -268,6 +302,29 @@ def _get_counter(self, oid, table_name):
268302
mibs.logger.warning("SyncD 'COUNTERS_DB' missing attribute '{}'.".format(e))
269303
return None
270304

305+
def aggregate_counters(self):
306+
"""
307+
For ports with l3 router interfaces l3 drops may be counted separately (RIF counters)
308+
add l3 drops to l2 drop counters cache according to mapping
309+
310+
For l3vlan map l3 counters to l2 counters
311+
"""
312+
for rif_sai_id, port_sai_id in self.rif_port_map.items():
313+
if port_sai_id in self.if_id_map:
314+
for port_counter_name, rif_counter_name in mibs.RIF_DROPS_AGGR_MAP.items():
315+
self.if_counters[port_sai_id][port_counter_name] = \
316+
int(self.if_counters[port_sai_id][port_counter_name]) + \
317+
int(self.rif_counters[rif_sai_id][rif_counter_name])
318+
319+
for vlan_sai_id in self.vlan_name_map:
320+
for port_counter_name, rif_counter_name in mibs.RIF_COUNTERS_AGGR_MAP.items():
321+
try:
322+
self.if_counters.setdefault(vlan_sai_id, {})
323+
self.if_counters[vlan_sai_id][port_counter_name] = \
324+
int(self.rif_counters[vlan_sai_id][rif_counter_name])
325+
except KeyError as e:
326+
logger.warning("Not able to aggregate counters for {}: {}\n {}".format(vlan_sai_id, rif_counter_name, e))
327+
271328
def get_counter(self, sub_id, table_name):
272329
"""
273330
:param sub_id: The 1-based sub-identifier query.
@@ -287,7 +344,13 @@ def get_counter(self, sub_id, table_name):
287344
counter_value = 0
288345
for lag_member in self.lag_name_if_name_map[self.oid_lag_name_map[oid]]:
289346
counter_value += self._get_counter(mibs.get_index(lag_member), table_name)
290-
347+
sai_lag_id = self.lag_sai_map[self.oid_lag_name_map[oid]]
348+
sai_lag_rif_id = self.port_rif_map[sai_lag_id]
349+
if sai_lag_rif_id in self.rif_port_map:
350+
table_name = bytes(getattr(table_name, 'name', table_name), 'utf-8')
351+
if table_name in mibs.RIF_DROPS_AGGR_MAP:
352+
rif_table_name = mibs.RIF_DROPS_AGGR_MAP[table_name]
353+
counter_value += int(self.rif_counters[sai_lag_rif_id][rif_table_name])
291354
# truncate to 32-bit counter
292355
return counter_value & 0x00000000ffffffff
293356
else:
@@ -317,6 +380,8 @@ def _get_if_entry(self, sub_id):
317380
elif oid in self.mgmt_oid_name_map:
318381
if_table = mibs.mgmt_if_entry_table(self.mgmt_oid_name_map[oid])
319382
db = mibs.CONFIG_DB
383+
elif oid in self.vlan_oid_name_map:
384+
if_table = mibs.vlan_entry_table(self.vlan_oid_name_map[oid])
320385
elif oid in self.oid_name_map:
321386
if_table = mibs.if_entry_table(self.oid_name_map[oid])
322387
else:
@@ -421,6 +486,7 @@ def get_if_type(self, sub_id):
421486
422487
ethernetCsmacd(6), -- for all ethernet-like interfaces,
423488
-- regardless of speed, as per RFC3635
489+
l3ipvlan(136) -- Layer 3 Virtual LAN using IP
424490
ieee8023adLag(161) -- IEEE 802.3ad Link Aggregate
425491
"""
426492
oid = self.get_oid(sub_id)
@@ -429,6 +495,8 @@ def get_if_type(self, sub_id):
429495

430496
if oid in self.oid_lag_name_map:
431497
return IfTypes.ieee8023adLag
498+
elif oid in self.vlan_oid_name_map:
499+
return IfTypes.l3ipvlan
432500
else:
433501
return IfTypes.ethernetCsmacd
434502

src/sonic_ax_impl/mibs/ietf/rfc2863.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def reinit_data(self):
7979

8080
self.lag_name_if_name_map, \
8181
self.if_name_lag_name_map, \
82-
self.oid_lag_name_map = Namespace.init_namespace_sync_d_lag_tables(self.db_conn)
82+
self.oid_lag_name_map, _ = Namespace.init_namespace_sync_d_lag_tables(self.db_conn)
8383
"""
8484
db_conn - will have db_conn to all namespace DBs and
8585
global db. First db in the list is global db.

src/sonic_ax_impl/mibs/vendor/cisco/ciscoPfcExtMIB.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def update_data(self):
5151

5252
self.lag_name_if_name_map, \
5353
self.if_name_lag_name_map, \
54-
self.oid_lag_name_map = Namespace.init_namespace_sync_d_lag_tables(self.db_conn)
54+
self.oid_lag_name_map, _ = Namespace.init_namespace_sync_d_lag_tables(self.db_conn)
5555

5656
self.if_range = sorted(list(self.oid_sai_map.keys()) + list(self.oid_lag_name_map.keys()))
5757
self.if_range = [(i,) for i in self.if_range]

tests/mock_tables/asic0/counters_db.json

+6
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,12 @@
314314
"COUNTERS_LAG_NAME_MAP": {
315315
"PortChannel01": "oid:0x1000000000007"
316316
},
317+
"COUNTERS_RIF_NAME_MAP": {
318+
"PortChannel01": "oid:0x6000000000006"
319+
},
320+
"COUNTERS_RIF_TYPE_MAP": {
321+
"oid:0x6000000000006": "SAI_ROUTER_INTERFACE_TYPE_PORT"
322+
},
317323
"COUNTERS:oid:0x1000000000004": {
318324
"SAI_PORT_STAT_ETHER_STATS_TX_NO_ERRORS": "0",
319325
"SAI_PORT_STAT_ETHER_STATS_OVERSIZE_PKTS": "0",

tests/mock_tables/asic1/counters_db.json

+6
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@
110110
"COUNTERS_LAG_NAME_MAP": {
111111
"PortChannel02": "oid:0x1000000000012"
112112
},
113+
"COUNTERS_RIF_TYPE_MAP": {
114+
"oid:0x6000000000012": "SAI_ROUTER_INTERFACE_TYPE_PORT"
115+
},
116+
"COUNTERS_RIF_NAME_MAP": {
117+
"PortChannel02": "oid:0x6000000000012"
118+
},
113119
"COUNTERS:oid:0x1000000000009": {
114120
"SAI_PORT_STAT_ETHER_STATS_TX_NO_ERRORS": "0",
115121
"SAI_PORT_STAT_ETHER_STATS_OVERSIZE_PKTS": "0",

0 commit comments

Comments
 (0)