Skip to content

Commit

Permalink
Added ciscoPfcExtMIB, ciscoSwitchQosMIB MIBs
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit 6c580806f962d508056e687108e04dc2a9df9276
Author: Qi Luo <[email protected]>
Date:   Fri Jan 26 15:08:53 2018 -0800

    Fix queue counter value type, and wrap queue index (sonic-net#4)

    * Fix queue counter value type
    * Wrap queue index

commit 66d738c297f852a5d504de1405ae55ff7d45dd0f
Author: Qi Luo <[email protected]>
Date:   Fri Jan 26 02:44:32 2018 +0000

    Added ciscoPfcExtMIB, ciscoSwitchQosMIB MIBs

    Squashed commit of the following:

    commit 0b68d9ed01ffe6a4b06345494e7bf7d3728c2371
    Author: Qi Luo <[email protected]>
    Date:   Thu Jan 25 18:27:53 2018 -0800

        Fix PFC queue index base and value type (sonic-net#3)

        * Fix PFC queue index base
        * Fix pfc counter64

    commit e84d1d89b8925cb547dfd435a5c1e8b58c74dedc
    Author: Qi Luo <[email protected]>
    Date:   Tue Jan 23 23:59:51 2018 +0000

        Added ciscoPfcExtMIB, ciscoSwitchQosMIB MIBs

        Squashed commit of the following:

        commit f0cbfff09066e372c1fe99983692a1dd719e5e80
        Author: Qi Luo <[email protected]>
        Date:   Tue Jan 23 23:20:02 2018 +0000

            Fix Pfc/Qos counter integer range

        commit c954e4e44d1e44fc5b4b2269a5bbcee63aeb07c7
        Author: AndriiS <[email protected]>
        Date:   Thu Jan 11 21:51:35 2018 +0200

            Added ciscoPfcExtMIB, ciscoSwitchQosMIB MIBs (sonic-net#1)

Remove lag from csqIfQosGroupStatsTable (sonic-net#5)
  • Loading branch information
qiluo-msft committed Apr 25, 2018
1 parent 67050bb commit a03f779
Show file tree
Hide file tree
Showing 8 changed files with 1,968 additions and 34 deletions.
3 changes: 3 additions & 0 deletions src/sonic_ax_impl/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class SonicMIB(
ieee802_1ab.LLDPLocPortTable,
ieee802_1ab.LLDPRemTable,
dell.force10.SSeriesMIB,
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 +1,3 @@
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) & 0xffffffffffffffff
# 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 = 0
self.max_prio = 7

def queue_index(self, sub_id):
"""
:param sub_id: The 0-based sub-identifier query.
:return: the 0-based interface ID.
"""
if len(sub_id) >= 2:
return sub_id[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 0-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 0-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.COUNTER_64, pfc_updater.cpfc_if_requests)

ifIndications = \
SubtreeMIBEntry('1.2', pfc_updater, ValueType.COUNTER_64, 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.COUNTER_64, pfc_updater.requests_per_priority)

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

0 comments on commit a03f779

Please sign in to comment.