-
Notifications
You must be signed in to change notification settings - Fork 104
/
ciscoSwitchQosMIB.py
202 lines (167 loc) · 7.59 KB
/
ciscoSwitchQosMIB.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
import math
from enum import unique, Enum
from bisect import bisect_right
from sonic_ax_impl import mibs
from sonic_ax_impl.mibs import Namespace
from ax_interface import MIBMeta, ValueType, MIBUpdater, MIBEntry, SubtreeMIBEntry
from ax_interface.encodings import ObjectIdentifier
# Maps SNMP queue stat counters to SAI counters and type
CounterMap = {
# Unicast send packets
('SAI_QUEUE_STAT_PACKETS', 'SAI_QUEUE_TYPE_UNICAST'): 1,
# Unicast send bytes
('SAI_QUEUE_STAT_BYTES', 'SAI_QUEUE_TYPE_UNICAST'): 2,
# Multicast send packets
('SAI_QUEUE_STAT_PACKETS','SAI_QUEUE_TYPE_MULTICAST'): 3,
# Multicast send bytes
('SAI_QUEUE_STAT_BYTES','SAI_QUEUE_TYPE_MULTICAST'): 4,
# Unicast dropped packets
('SAI_QUEUE_STAT_DROPPED_PACKETS','SAI_QUEUE_TYPE_UNICAST'): 5,
# Unicast dropped bytes
('SAI_QUEUE_STAT_DROPPED_BYTES','SAI_QUEUE_TYPE_UNICAST'): 6,
# Multicast dropped packets
('SAI_QUEUE_STAT_DROPPED_PACKETS','SAI_QUEUE_TYPE_MULTICAST'): 7,
# Multicast dropped bytes
('SAI_QUEUE_STAT_DROPPED_BYTES', 'SAI_QUEUE_TYPE_MULTICAST'): 8
}
class DirectionTypes(int, Enum):
"""
Queue direction types
"""
INGRESS = 1
EGRESS = 2
class QueueStatUpdater(MIBUpdater):
"""
Class to update the info from Counter DB and to handle the SNMP request
"""
def __init__(self):
"""
init the updater
"""
super().__init__()
self.db_conn = Namespace.init_namespace_dbs()
# establish connection to state database.
Namespace.connect_all_dbs(self.db_conn, mibs.STATE_DB)
self.lag_name_if_name_map = {}
self.if_name_lag_name_map = {}
self.oid_lag_name_map = {}
self.queue_type_map = {}
self.if_name_map = {}
self.if_alias_map = {}
self.if_id_map = {}
self.oid_name_map = {}
self.port_queues_map = {}
self.queue_stat_map = {}
self.port_queue_list_map = {}
self.mib_oid_to_queue_map = {}
self.mib_oid_list = []
self.queue_type_map = {}
self.port_index_namespace = {}
self.namespace_db_map = Namespace.get_namespace_db_map(self.db_conn)
def reinit_connection(self):
Namespace.connect_namespace_dbs(self.db_conn)
def reinit_data(self):
"""
Subclass update interface information
"""
self.if_name_map, \
self.if_alias_map, \
self.if_id_map, \
self.oid_name_map = Namespace.get_sync_d_from_all_namespace(mibs.init_sync_d_interface_tables, self.db_conn)
for sai_id_key in self.if_id_map:
namespace, sai_id = mibs.split_sai_id_key(sai_id_key)
if_idx = mibs.get_index_from_str(self.if_id_map[sai_id_key])
self.port_index_namespace[if_idx] = namespace
self.port_queues_map, self.queue_stat_map, self.port_queue_list_map = \
Namespace.get_sync_d_from_all_namespace(mibs.init_sync_d_queue_tables, self.db_conn)
for db_conn in Namespace.get_non_host_dbs(self.db_conn):
self.queue_type_map[db_conn.namespace] = db_conn.get_all(mibs.COUNTERS_DB, "COUNTERS_QUEUE_TYPE_MAP", blocking=False)
def update_data(self):
"""
Update redis (caches config)
Pulls the table references for each queue.
"""
for queue_key, sai_id in self.port_queues_map.items():
queue_stat_name = mibs.queue_table(sai_id)
port_index, _ = queue_key.split(':')
queue_stat_idx = mibs.queue_key(port_index, queue_stat_name)
namespace = self.port_index_namespace[int(port_index)]
queue_stat = self.namespace_db_map[namespace].get_all( \
mibs.COUNTERS_DB, queue_stat_name, blocking=False)
if queue_stat is not None:
self.queue_stat_map[queue_stat_idx] = queue_stat
else:
del self.queue_stat_map[queue_stat_idx]
self.update_stats()
def update_stats(self):
"""
Update statistics.
1. Get and sort port list to keep the order in MIB
2. Prepare OID and get a statistic for each queue of each port
3. Get and sort LAG ports list to keep the order in MIB
4. Prepare OID for LAG and prepare a statistic for each queue of each LAG port
"""
# Clear previous data
self.mib_oid_to_queue_map = {}
self.mib_oid_list = []
# Sort the ports to keep the OID order in the MIB
if_range = list(self.oid_name_map.keys())
# Update queue counters for port
for if_index in if_range:
if if_index not in self.port_queue_list_map:
# Port does not has a queues, continue..
continue
if_queues = self.port_queue_list_map[if_index]
namespace = self.port_index_namespace[if_index]
# The first half of queue id is for ucast, and second half is for mcast
# To simulate vendor OID, we wrap queues by max priority groups
port_max_queues = Namespace.dbs_get_all(self.db_conn, mibs.STATE_DB,
mibs.buffer_max_parm_table(self.oid_name_map[if_index]))['max_queues']
pq_count = math.ceil(int(port_max_queues) / 2)
for queue in if_queues:
# Get queue type and statistics
queue_sai_oid = self.port_queues_map[mibs.queue_key(if_index, queue)]
queue_stat_table_name = mibs.queue_table(queue_sai_oid)
queue_stat_key = mibs.queue_key(if_index, queue_stat_table_name)
queue_type = self.queue_type_map[namespace].get(queue_sai_oid)
queue_stat = self.queue_stat_map.get(queue_stat_key, {})
# Add supported counters to MIBs list and store counters values
for (counter, counter_type), counter_mib_id in CounterMap.items():
# Only egress queues are supported
mib_oid = (if_index, int(DirectionTypes.EGRESS), (queue % pq_count) + 1, counter_mib_id)
counter_value = 0
if queue_type == counter_type:
counter_value = int(queue_stat.get(counter, 0))
if mib_oid in self.mib_oid_to_queue_map:
continue
self.mib_oid_list.append(mib_oid)
self.mib_oid_to_queue_map[mib_oid] = counter_value
self.mib_oid_list.sort()
def get_next(self, sub_id):
"""
:param sub_id: The 1-based sub-identifier query.
:return: the next sub id.
"""
right = bisect_right(self.mib_oid_list, sub_id)
if right >= len(self.mib_oid_list):
return None
return self.mib_oid_list[right]
def handle_stat_request(self, sub_id):
"""
:param sub_id: The 1-based sub-identifier query.
:return: the counter for the respective sub_id/table.
"""
# if_index, if_direction, queue_index and counter id should be passed
if sub_id in self.mib_oid_to_queue_map:
return self.mib_oid_to_queue_map[sub_id] & 0xffffffffffffffff
else:
return None
class csqIfQosGroupStatsTable(metaclass=MIBMeta, prefix='.1.3.6.1.4.1.9.9.580.1.5.5'):
"""
'csqIfQosGroupStatsTable' http://oidref.com/1.3.6.1.4.1.9.9.580.1.5.5
"""
queue_updater = QueueStatUpdater()
# csqIfQosGroupStatsTable = '1.3.6.1.4.1.9.9.580.1.5.5'
# csqIfQosGroupStatsEntry = '1.3.6.1.4.1.9.9.580.1.5.5.1.4'
queue_stat_request = \
SubtreeMIBEntry('1.4', queue_updater, ValueType.COUNTER_64, queue_updater.handle_stat_request)