@@ -50,7 +50,8 @@ class DbTables(int, Enum):
5050class IfTypes (int , Enum ):
5151 """ IANA ifTypes """
5252 ethernetCsmacd = 6
53- ieee8023adLag = 161
53+ l3ipvlan = 136
54+ ieee8023adLag = 161
5455
5556class 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 ):
@@ -226,26 +234,58 @@ def reinit_data(self):
226234
227235 self .lag_name_if_name_map , \
228236 self .if_name_lag_name_map , \
229- self .oid_lag_name_map , _ = Namespace .get_sync_d_from_all_namespace (mibs .init_sync_d_lag_tables , self .db_conn )
237+ self .oid_lag_name_map , \
238+ self .lag_sai_map , self .sai_lag_map = Namespace .get_sync_d_from_all_namespace (mibs .init_sync_d_lag_tables , self .db_conn )
239+
240+ self .vlan_name_map , \
241+ self .vlan_oid_sai_map , \
242+ self .vlan_oid_name_map = Namespace .get_sync_d_from_all_namespace (mibs .init_sync_d_vlan_tables , self .db_conn )
243+
244+ self .rif_port_map , \
245+ self .port_rif_map = Namespace .get_sync_d_from_all_namespace (mibs .init_sync_d_rif_tables , self .db_conn )
230246
231247 def update_data (self ):
232248 """
233249 Update redis (caches config)
234250 Pulls the table references for each interface.
235251 """
252+ self .update_if_counters ()
253+ self .update_rif_counters ()
254+
255+ self .aggregate_counters ()
256+
257+ self .lag_name_if_name_map , \
258+ self .if_name_lag_name_map , \
259+ self .oid_lag_name_map , \
260+ self .lag_sai_map , self .sai_lag_map = Namespace .get_sync_d_from_all_namespace (mibs .init_sync_d_lag_tables , self .db_conn )
261+
262+ self .if_range = sorted (list (self .oid_name_map .keys ()) +
263+ list (self .oid_lag_name_map .keys ()) +
264+ list (self .mgmt_oid_name_map .keys ()) +
265+ list (self .vlan_oid_name_map .keys ()))
266+ self .if_range = [(i ,) for i in self .if_range ]
267+
268+ def update_if_counters (self ):
236269 for sai_id_key in self .if_id_map :
237270 namespace , sai_id = mibs .split_sai_id_key (sai_id_key )
238271 if_idx = mibs .get_index_from_str (self .if_id_map [sai_id_key ])
239272 counter_table = self .namespace_db_map [namespace ].get_all (mibs .COUNTERS_DB , \
240273 mibs .counter_table (sai_id ))
241274 if counter_table is None :
242275 counter_table = {}
243- self .if_counters [if_idx ] = counter_table
244-
245- self .if_range = sorted (list (self .oid_name_map .keys ()) +
246- list (self .oid_lag_name_map .keys ()) +
247- list (self .mgmt_oid_name_map .keys ()))
248- self .if_range = [(i ,) for i in self .if_range ]
276+ self .if_counters [if_idx ] = {
277+ counter : int (value ) for counter , value in counter_table .items ()
278+ }
279+
280+ def update_rif_counters (self ):
281+ rif_sai_ids = list (self .rif_port_map ) + list (self .vlan_name_map )
282+ for sai_id in rif_sai_ids :
283+ counters_db_data = Namespace .dbs_get_all (self .db_conn , mibs .COUNTERS_DB ,
284+ mibs .counter_table (mibs .split_sai_id_key (sai_id )[1 ]),
285+ blocking = False )
286+ self .rif_counters [sai_id ] = {
287+ counter : int (value ) for counter , value in counters_db_data .items ()
288+ }
249289
250290 def get_next (self , sub_id ):
251291 """
@@ -288,6 +328,8 @@ def interface_description(self, sub_id):
288328 return self .oid_lag_name_map [oid ]
289329 elif oid in self .mgmt_oid_name_map :
290330 return self .mgmt_alias_map [self .mgmt_oid_name_map [oid ]]
331+ elif oid in self .vlan_oid_name_map :
332+ return self .vlan_oid_name_map [oid ]
291333
292334 return self .if_alias_map [self .oid_name_map [oid ]]
293335
@@ -298,18 +340,46 @@ def _get_counter(self, oid, table_name):
298340 :return: the counter for the respective sub_id/table.
299341 """
300342 # Enum.name or table_name = 'name_of_the_table'
343+ # Example:
344+ # table_name = <DbTables.SAI_PORT_STAT_IF_OUT_ERRORS: 20>
345+ # _table_name = 'SAI_PORT_STAT_IF_OUT_ERRORS'
301346 _table_name = getattr (table_name , 'name' , table_name )
302347
303348 try :
304349 counter_value = self .if_counters [oid ][_table_name ]
305350 # truncate to 32-bit counter (database implements 64-bit counters)
306- counter_value = int ( counter_value ) & 0x00000000ffffffff
351+ counter_value = counter_value & 0x00000000ffffffff
307352 # done!
308353 return counter_value
309354 except KeyError as e :
310355 mibs .logger .warning ("SyncD 'COUNTERS_DB' missing attribute '{}'." .format (e ))
311356 return None
312357
358+ def aggregate_counters (self ):
359+ """
360+ For ports with l3 router interfaces l3 drops may be counted separately (RIF counters)
361+ add l3 drops to l2 drop counters cache according to mapping
362+
363+ For l3vlan map l3 counters to l2 counters
364+ """
365+ for rif_sai_id , port_sai_id in self .rif_port_map .items ():
366+ if port_sai_id in self .if_id_map :
367+ port_idx = mibs .get_index_from_str (self .if_id_map [port_sai_id ])
368+ for port_counter_name , rif_counter_name in mibs .RIF_DROPS_AGGR_MAP .items ():
369+ self .if_counters [port_idx ][port_counter_name ] = \
370+ self .if_counters [port_idx ][port_counter_name ] + \
371+ self .rif_counters [rif_sai_id ][rif_counter_name ]
372+
373+ for vlan_sai_id , vlan_name in self .vlan_name_map .items ():
374+ for port_counter_name , rif_counter_name in mibs .RIF_COUNTERS_AGGR_MAP .items ():
375+ vlan_idx = mibs .get_index_from_str (vlan_name )
376+ vlan_rif_counters = self .rif_counters [vlan_sai_id ]
377+ if rif_counter_name in vlan_rif_counters :
378+ self .if_counters .setdefault (vlan_idx , {})
379+ self .if_counters [vlan_idx ][port_counter_name ] = \
380+ vlan_rif_counters [rif_counter_name ]
381+
382+
313383 def get_counter (self , sub_id , table_name ):
314384 """
315385 :param sub_id: The 1-based sub-identifier query.
@@ -327,9 +397,40 @@ def get_counter(self, sub_id, table_name):
327397 return 0
328398 elif oid in self .oid_lag_name_map :
329399 counter_value = 0
400+ # Sum the values of this counter for all ports in the LAG.
401+ # Example:
402+ # table_name = <DbTables.SAI_PORT_STAT_IF_OUT_ERRORS: 20>
403+ # oid = 1001
404+ # self.oid_lag_name_map = {1001: 'PortChannel01', 1002: 'PortChannel02', 1003: 'PortChannel03'}
405+ # self.oid_lag_name_map[oid] = 'PortChannel01'
406+ # self.lag_name_if_name_map = {'PortChannel01': ['Ethernet112'], 'PortChannel02': ['Ethernet116'], 'PortChannel03': ['Ethernet120']}
407+ # self.lag_name_if_name_map['PortChannel01'] = ['Ethernet112']
408+ # mibs.get_index_from_str('Ethernet112') = 113 (because Ethernet N = N + 1)
409+ # self._get_counter retrieves the counter per oid and table.
330410 for lag_member in self .lag_name_if_name_map [self .oid_lag_name_map [oid ]]:
331411 counter_value += self ._get_counter (mibs .get_index_from_str (lag_member ), table_name )
332-
412+ # Check if we need to add a router interface count.
413+ # Example:
414+ # self.lag_sai_map = {'PortChannel01': '2000000000006', 'PortChannel02': '2000000000005', 'PortChannel03': '2000000000004'}
415+ # self.port_rif_map = {'2000000000006': '6000000000006', '2000000000005': '6000000000005', '2000000000004': '6000000000004'}
416+ # self.rif_port_map = {'6000000000006': '2000000000006', '6000000000005': '2000000000005', '6000000000004': '2000000000004'}
417+ # self.lag_sai_map['PortChannel01'] = '2000000000006'
418+ # self.port_rif_map['2000000000006'] = '6000000000006'
419+ sai_lag_id = self .lag_sai_map [self .oid_lag_name_map [oid ]]
420+ sai_lag_rif_id = self .port_rif_map [sai_lag_id ]
421+ if sai_lag_rif_id in self .rif_port_map :
422+ # Extract the 'name' part of 'table_name'.
423+ # Example:
424+ # table_name = <DbTables.SAI_PORT_STAT_IF_OUT_ERRORS: 20>
425+ # _table_name = 'SAI_PORT_STAT_IF_OUT_ERRORS'
426+ table_name = getattr (table_name , 'name' , table_name )
427+ # Find rif counter table if applicable and add the count for this table.
428+ # Example:
429+ # 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'}
430+ # self.rif_counters['6000000000006'] = {'SAI_ROUTER_INTERFACE_STAT_IN_PACKETS': 6, ... 'SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS': 6, ...}
431+ if table_name in mibs .RIF_DROPS_AGGR_MAP :
432+ rif_table_name = mibs .RIF_DROPS_AGGR_MAP [table_name ]
433+ counter_value += self .rif_counters [sai_lag_rif_id ].get (rif_table_name , 0 )
333434 # truncate to 32-bit counter
334435 return counter_value & 0x00000000ffffffff
335436 else :
@@ -359,6 +460,8 @@ def _get_if_entry(self, sub_id):
359460 elif oid in self .mgmt_oid_name_map :
360461 if_table = mibs .mgmt_if_entry_table (self .mgmt_oid_name_map [oid ])
361462 db = mibs .CONFIG_DB
463+ elif oid in self .vlan_oid_name_map :
464+ if_table = mibs .vlan_entry_table (self .vlan_oid_name_map [oid ])
362465 elif oid in self .oid_name_map :
363466 if_table = mibs .if_entry_table (self .oid_name_map [oid ])
364467 else :
@@ -463,6 +566,7 @@ def get_if_type(self, sub_id):
463566
464567 ethernetCsmacd(6), -- for all ethernet-like interfaces,
465568 -- regardless of speed, as per RFC3635
569+ l3ipvlan(136) -- Layer 3 Virtual LAN using IP
466570 ieee8023adLag(161) -- IEEE 802.3ad Link Aggregate
467571 """
468572 oid = self .get_oid (sub_id )
@@ -471,6 +575,8 @@ def get_if_type(self, sub_id):
471575
472576 if oid in self .oid_lag_name_map :
473577 return IfTypes .ieee8023adLag
578+ elif oid in self .vlan_oid_name_map :
579+ return IfTypes .l3ipvlan
474580 else :
475581 return IfTypes .ethernetCsmacd
476582
0 commit comments