Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ciscoPfcExtMIB, ciscoSwitchQosMIB MIBs #1

Merged
merged 1 commit into from
Jan 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/sonic_ax_impl/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class SonicMIB(
dell.force10.SSeriesMIB,
cisco.mgmt.CiscoSystemExtMIB,
cisco.bgp4.CiscoBgp4MIB,
cisco.ciscoPfcExtMIB.cpfcIfTable,
cisco.ciscoPfcExtMIB.cpfcIfPriorityTable,
cisco.ciscoSwitchQosMIB.csqIfQosGroupStatsTable,
cisco.ciscoEntityFruControlMIB.cefcFruPowerStatusTable,
):
"""
Expand Down
66 changes: 66 additions & 0 deletions src/sonic_ax_impl/mibs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from sonic_ax_impl import logger, _if_alias_map

COUNTERS_PORT_NAME_MAP = b'COUNTERS_PORT_NAME_MAP'
COUNTERS_QUEUE_NAME_MAP = b'COUNTERS_QUEUE_NAME_MAP'
LAG_TABLE = b'LAG_TABLE'
LAG_MEMBER_TABLE = b'LAG_MEMBER_TABLE'
APPL_DB = 'APPL_DB'
Expand All @@ -22,6 +23,16 @@ def counter_table(sai_id):
"""
return b'COUNTERS:oid:0x' + sai_id

def queue_table(sai_id):
"""
:param sai_id: given sai_id to cast.
:return: COUNTERS table key.
"""
return b'COUNTERS:' + sai_id

def queue_key(port_index, queue_index):
return str(port_index) + ':' + str(queue_index)


def lldp_entry_table(if_name):
"""
Expand Down Expand Up @@ -158,3 +169,58 @@ def member_name_str(val, lag_name):
oid_lag_name_map[idx] = if_name

return lag_name_if_name_map, if_name_lag_name_map, oid_lag_name_map

def init_sync_d_queue_tables(db_conn):
"""
Initializes queue maps for SyncD-connected MIB(s).
:return: tuple(port_queues_map, queue_stat_map)
"""

# Make sure we're connected to COUNTERS_DB
db_conn.connect(COUNTERS_DB)

# { Port index : Queue index (SONiC) -> sai_id }
# ex: { "1:2" : "1000000000023" }
queue_name_map = db_conn.get_all(COUNTERS_DB, COUNTERS_QUEUE_NAME_MAP, blocking=True)
logger.debug("Queue name map:\n" + pprint.pformat(queue_name_map, indent=2))

# Parse the queue_name_map and create the following maps:
# port_queues_map -> {"if_index : queue_index" : sai_oid}
# queue_stat_map -> {queue stat table name : {counter name : value}}
# port_queue_list_map -> {if_index: [sorted queue list]}
port_queues_map = {}
queue_stat_map = {}
port_queue_list_map = {}

for queue_name, sai_id in queue_name_map.items():
port_name, queue_index = queue_name.decode().split(':')
queue_index = ''.join(i for i in queue_index if i.isdigit())
port_index = get_index_from_str(port_name)
key = queue_key(port_index, queue_index)
port_queues_map[key] = sai_id

queue_stat_name = queue_table(sai_id)
queue_stat = db_conn.get_all(COUNTERS_DB, queue_stat_name, blocking=False)
if queue_stat is not None:
queue_stat_map[queue_stat_name] = queue_stat

if not port_queue_list_map.get(int(port_index)):
port_queue_list_map[int(port_index)] = [int(queue_index)]
else:
port_queue_list_map[int(port_index)].append(int(queue_index))

# SyncD consistency checks.
if not port_queues_map:
# In the event no queue exists that follows the SONiC pattern, no OIDs are able to be registered.
# A RuntimeError here will prevent the 'main' module from loading. (This is desirable.)
logger.error("No queues found in the Counter DB. SyncD database is incoherent.")
raise RuntimeError('The port_queues_map is not defined')
elif not queue_stat_map:
logger.error("No queue stat counters found in the Counter DB. SyncD database is incoherent.")
raise RuntimeError('The queue_stat_map is not defined')

for queues in port_queue_list_map.values():
queues.sort()

return port_queues_map, queue_stat_map, port_queue_list_map

2 changes: 2 additions & 0 deletions src/sonic_ax_impl/mibs/vendor/cisco/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from . import mgmt, bgp4
from . import ciscoPfcExtMIB
from . import ciscoSwitchQosMIB
from . import ciscoEntityFruControlMIB
275 changes: 275 additions & 0 deletions src/sonic_ax_impl/mibs/vendor/cisco/ciscoPfcExtMIB.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
from enum import unique, Enum
from bisect import bisect_right

from sonic_ax_impl import mibs
from ax_interface import MIBMeta, ValueType, MIBUpdater, MIBEntry, SubtreeMIBEntry
from ax_interface.encodings import ObjectIdentifier

class PfcUpdater(MIBUpdater):
"""
Class to update the info from Counter DB and to handle the SNMP request
"""
def __init__(self):
super().__init__()
self.db_conn = mibs.init_db()

self.if_name_map = {}
self.if_alias_map = {}
self.if_id_map = {}
self.oid_sai_map = {}
self.oid_name_map = {}

self.lag_name_if_name_map = {}
self.if_name_lag_name_map = {}
self.oid_lag_name_map = {}

# cache of interface counters
self.if_counters = {}
self.if_range = []

def reinit_data(self):
"""
Subclass update interface information
"""
self.if_name_map, \
self.if_alias_map, \
self.if_id_map, \
self.oid_sai_map, \
self.oid_name_map = mibs.init_sync_d_interface_tables(self.db_conn)

self.update_data()

def update_data(self):
"""
Update redis (caches config)
Pulls the table references for each interface.
"""
self.if_counters = \
{sai_id: self.db_conn.get_all(mibs.COUNTERS_DB, mibs.counter_table(sai_id), blocking=True)
for sai_id in self.if_id_map}

self.lag_name_if_name_map, \
self.if_name_lag_name_map, \
self.oid_lag_name_map = mibs.init_sync_d_lag_tables(self.db_conn)

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

def get_next(self, sub_id):
"""
:param sub_id: The 1-based sub-identifier query.
:return: the next sub id.
"""
try:
if not sub_id:
return self.if_range[0]

right = bisect_right(self.if_range, sub_id)
if right >= len(self.if_range):
return None
return self.if_range[right]
except (IndexError, KeyError) as e:
mibs.logger.error("failed to get next oid with error = {}".format(str(e)))

def get_oid(self, sub_id):
"""
:param sub_id: The 1-based sub-identifier query.
:return: the interface OID.
"""
if sub_id is None or sub_id not in self.if_range:
return None

return sub_id[0]

def _get_counter(self, oid, counter_name):
"""
:param sub_id: The interface OID.
:param counter_name: the redis table (either IntEnum or string literal) to query.
:return: the counter for the respective sub_id/table.
"""
sai_id = self.oid_sai_map[oid]

# Enum.name or counter_name = 'name_of_the_table'
_counter_name = bytes(getattr(counter_name, 'name', counter_name), 'utf-8')

try:
counter_value = self.if_counters[sai_id][_counter_name]
counter_value = int(counter_value)
# done!
return counter_value
except KeyError as e:
mibs.logger.warning("SyncD 'COUNTERS_DB' missing attribute '{}'.".format(e))
return None

def cpfc_if_requests(self, sub_id):
"""
:param sub_id: The 1-based sub-identifier query.
:return: the counter for the respective sub_id/table.
"""
oid = self.get_oid(sub_id)
if oid is None:
return None

counter_name = 'SAI_PORT_STAT_PFC_3_RX_PKTS'

if oid in self.oid_lag_name_map:
counter_value = 0
for lag_member in self.lag_name_if_name_map[self.oid_lag_name_map[oid]]:
counter_value += self._get_counter(mibs.get_index(lag_member), counter_name)

return counter_value
else:
return self._get_counter(oid, counter_name)


def cpfc_if_indications(self, sub_id):
"""
:param sub_id: The 1-based sub-identifier query.
:return: the counter for the respective sub_id/table.
"""
oid = self.get_oid(sub_id)
if oid is None:
return None

counter_name = 'SAI_PORT_STAT_PFC_3_TX_PKTS'

if oid in self.oid_lag_name_map:
counter_value = 0
for lag_member in self.lag_name_if_name_map[self.oid_lag_name_map[oid]]:
counter_value += self._get_counter(mibs.get_index(lag_member), counter_name)

return counter_value
else:
return self._get_counter(oid, counter_name)


class PfcPrioUpdater(PfcUpdater):
def __init__(self):
super().__init__()
self.min_prio = 1
self.max_prio = 8

def queue_index(self, sub_id):
"""
:param sub_id: The 1-based sub-identifier query.
:return: the 0-based interface ID.
"""
if len(sub_id) >= 2:
return sub_id[1] - 1
return None

def get_next(self, sub_id):
"""
:param sub_id: The 1-based sub-identifier query.
:return: the next sub id.
"""
try:
if not sub_id:
return self.if_range[0][0], self.min_prio

if len(sub_id) < 2:
return sub_id[0], self.min_prio

if sub_id[1] >= self.max_prio:
idx = self.if_range.index((sub_id[0],))
return self.if_range[idx + 1][0], self.min_prio

right = sub_id[1] + 1

return sub_id[0], right
except IndexError:
# Reached the last element. Return None to notify caller
return None
except Exception as e:
mibs.logger.error("failed to get next oid with error = {}".format(str(e)))
return None

def requests_per_priority(self, sub_id):
"""
:param sub_id: The 1-based sub-identifier query.
:return: the counter for the respective sub_id/table.
"""
port_oid = ''
queue_index = ''
try:
if not sub_id:
return None

port_oid = self.get_oid((sub_id[0],))
queue_index = self.queue_index(sub_id)
if port_oid is None or queue_index is None:
return None
except Exception as e:
mibs.logger.warning("requestsPerPriority: incorrect sub_id = {} error: {}".format(str(sub_id), e))
return None

counter_name = 'SAI_PORT_STAT_PFC_' + str(queue_index) + '_RX_PKTS'

if port_oid in self.oid_lag_name_map:
counter_value = 0
for lag_member in self.lag_name_if_name_map[self.oid_lag_name_map[port_oid]]:
counter_value += self._get_counter(mibs.get_index(lag_member), counter_name)

return counter_value
else:
return self._get_counter(port_oid, counter_name)

def indications_per_priority(self, sub_id):
"""
:param sub_id: The 1-based sub-identifier query.
:return: the counter for the respective sub_id/table.
"""
port_oid = ''
queue_index = ''
try:
if not sub_id:
return None

port_oid = self.get_oid((sub_id[0],))
queue_index = self.queue_index(sub_id)
if port_oid is None or queue_index is None:
return None
except IndexError:
mibs.logger.warning("indicationsPerPriority: incorrect sub_id = {}".format(str(sub_id)))
return None

counter_name = 'SAI_PORT_STAT_PFC_' + str(queue_index) + '_TX_PKTS'

if port_oid in self.oid_lag_name_map:
counter_value = 0
for lag_member in self.lag_name_if_name_map[self.oid_lag_name_map[port_oid]]:
counter_value += self._get_counter(mibs.get_index(lag_member), counter_name)

return counter_value
else:
return self._get_counter(port_oid, counter_name)


# cpfcIfTable = '1.1'
# cpfcIfEntry = '1.1.1.x'
class cpfcIfTable(metaclass=MIBMeta, prefix='.1.3.6.1.4.1.9.9.813.1.1'):
"""
'ciscoPfcExtMIB' http://oidref.com/1.3.6.1.4.1.9.9.813.1.1
"""
pfc_updater = PfcUpdater()

ifRequests = \
SubtreeMIBEntry('1.1', pfc_updater, ValueType.INTEGER, pfc_updater.cpfc_if_requests)

ifIndications = \
SubtreeMIBEntry('1.2', pfc_updater, ValueType.INTEGER, pfc_updater.cpfc_if_indications)


# cpfcIfPriorityTable = '1.2'
# cpfcIfPriorityEntry = '1.2.x'
class cpfcIfPriorityTable(metaclass=MIBMeta, prefix='.1.3.6.1.4.1.9.9.813.1.2'):
"""
'ciscoPfcExtMIB' http://oidref.com/1.3.6.1.4.1.9.9.813
"""
pfc_updater = PfcPrioUpdater()

prioRequests = \
SubtreeMIBEntry('1.2', pfc_updater, ValueType.INTEGER, pfc_updater.requests_per_priority)

prioIndications = \
SubtreeMIBEntry('1.3', pfc_updater, ValueType.INTEGER, pfc_updater.indications_per_priority)
Loading