Add VPP API support to retrieve mtu/ifspeed/operstatus/adminstatus/mac

This commit is contained in:
Pim van Pelt
2021-09-05 19:39:20 +00:00
parent 238471d25f
commit e1cddc8c26
2 changed files with 210 additions and 11 deletions

View File

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
from vppstats import VPPStats
import vppapi
import time
import pyagentx
import logging
@ -13,7 +14,7 @@ class NullHandler(logging.Handler):
pass
logger = logging.getLogger('pyagentx.vpp')
logger = logging.getLogger('pyagentx.vppstats')
logger.addHandler(NullHandler())
@ -47,6 +48,105 @@ class ifType(pyagentx.Updater):
self.set_INTEGER(str(i + 1), t)
class ifMtu(pyagentx.Updater):
def update(self):
global vppstat, vpp
vppstat.connect()
ifaces = vppapi.get_ifaces(vpp)
for i in range(len(vppstat['/if/names'])):
ifname = vppstat['/if/names'][i]
mtu = 0
if not ifname in ifaces:
logger.warning("Could not get MTU for interface %s", ifname)
else:
mtu = ifaces[ifname].mtu[0]
self.set_INTEGER(str(i + 1), mtu)
class ifSpeed(pyagentx.Updater):
def update(self):
global vppstat, vpp
vppstat.connect()
ifaces = vppapi.get_ifaces(vpp)
for i in range(len(vppstat['/if/names'])):
ifname = vppstat['/if/names'][i]
speed = 0
if ifname.startswith("loop") or ifname.startswith("tap"):
speed = 1000000000
elif not ifname in ifaces:
logger.warning("Could not get link speed for interface %s",
ifname)
else:
speed = ifaces[ifname].link_speed * 1000
if speed >= 2**32:
speed = 2**32 - 1
self.set_GAUGE32(str(i + 1), speed)
class ifAdminStatus(pyagentx.Updater):
def update(self):
global vppstat, vpp
vppstat.connect()
ifaces = vppapi.get_ifaces(vpp)
for i in range(len(vppstat['/if/names'])):
ifname = vppstat['/if/names'][i]
state = 3 # testing
if not ifname in ifaces:
logger.warning("Could not get AdminStatus for interface %s",
ifname)
else:
if int(ifaces[ifname].flags) & 2:
state = 1 # up
else:
state = 2 # down
self.set_INTEGER(str(i + 1), state)
class ifOperStatus(pyagentx.Updater):
def update(self):
global vppstat, vpp
vppstat.connect()
ifaces = vppapi.get_ifaces(vpp)
for i in range(len(vppstat['/if/names'])):
ifname = vppstat['/if/names'][i]
state = 3 # testing
if not ifname in ifaces:
logger.warning("Could not get OperStatus for interface %s",
ifname)
else:
if int(ifaces[ifname].flags) & 1:
state = 1 # up
else:
state = 2 # down
self.set_INTEGER(str(i + 1), state)
class ifPhysAddress(pyagentx.Updater):
def update(self):
global vppstat, vpp
vppstat.connect()
ifaces = vppapi.get_ifaces(vpp)
for i in range(len(vppstat['/if/names'])):
ifname = vppstat['/if/names'][i]
mac = "00:00:00:00:00:00"
if not ifname in ifaces:
logger.warning("Could not get PhysAddress for interface %s",
ifname)
else:
mac = str(ifaces[ifname].l2_address)
self.set_OCTETSTRING(str(i + 1), mac)
class ifAlias(pyagentx.Updater):
def update(self):
global vppstat
@ -178,11 +278,22 @@ class ifHCOutBroadcastPkts(pyagentx.Updater):
class ifHighSpeed(pyagentx.Updater):
def update(self):
global vppstat
global vppstat, vpp
vppstat.connect()
ifaces = vppapi.get_ifaces(vpp)
for i in range(len(vppstat['/if/names'])):
self.set_GAUGE32(str(i + 1), 1000)
ifname = vppstat['/if/names'][i]
speed = 0
if ifname.startswith("loop") or ifname.startswith("tap"):
speed = 1000
elif not ifname in ifaces:
logger.warning("Could not get link speed for interface %s",
ifname)
else:
speed = int(ifaces[ifname].link_speed / 1000)
self.set_GAUGE32(str(i + 1), speed)
class ifPromiscuousMode(pyagentx.Updater):
@ -319,6 +430,11 @@ class MyAgent(pyagentx.Agent):
self.register('1.3.6.1.2.1.2.2.1.1', ifIndex)
self.register('1.3.6.1.2.1.2.2.1.2', ifName)
self.register('1.3.6.1.2.1.2.2.1.3', ifType)
self.register('1.3.6.1.2.1.2.2.1.4', ifMtu)
self.register('1.3.6.1.2.1.2.2.1.5', ifSpeed)
self.register('1.3.6.1.2.1.2.2.1.6', ifPhysAddress)
self.register('1.3.6.1.2.1.2.2.1.7', ifAdminStatus)
self.register('1.3.6.1.2.1.2.2.1.8', ifOperStatus)
self.register('1.3.6.1.2.1.2.2.1.9', ifCounterDiscontinuityTime)
self.register('1.3.6.1.2.1.2.2.1.10', ifInOctets)
self.register('1.3.6.1.2.1.2.2.1.11', ifInUcastPkts)
@ -332,13 +448,6 @@ class MyAgent(pyagentx.Agent):
self.register('1.3.6.1.2.1.2.2.1.19', ifOutDiscards)
self.register('1.3.6.1.2.1.2.2.1.20', ifOutErrors)
# TODO(pim) -- these require VPP API calls
#4 .iso.org.dod.internet.mgmt.mib_2.interfaces.ifTable.ifEntry.ifMtu.132 = INTEGER: 1500
#5 .iso.org.dod.internet.mgmt.mib_2.interfaces.ifTable.ifEntry.ifSpeed.132 = Gauge32: 10000000
#6 .iso.org.dod.internet.mgmt.mib_2.interfaces.ifTable.ifEntry.ifPhysAddress.132 = Hex-STRING: 68 05 CA 32 46 15
#7 .iso.org.dod.internet.mgmt.mib_2.interfaces.ifTable.ifEntry.ifAdminStatus.132 = INTEGER: 1
#8 .iso.org.dod.internet.mgmt.mib_2.interfaces.ifTable.ifEntry.ifOperStatus.132 = INTEGER: 1
# iso.org.dod.internet.mgmt.mib_2.ifMIB.ifMIBObjects.ifXTable.ifXEntry
self.register('1.3.6.1.2.1.31.1.1.1.1', ifName)
self.register('1.3.6.1.2.1.31.1.1.1.2', ifInMulticastPkts)
@ -364,13 +473,18 @@ class MyAgent(pyagentx.Agent):
def main():
global vppstat
global vppstat, vpp, logger
pyagentx.setup_logging(debug=False)
vppstat = VPPStats(socketname='/run/vpp/stats.sock', timeout=2)
vppstat.connect()
vpp = vppapi.vpp_connect()
if not vpp:
logger.error("Can't connect to VPP API, bailing")
return
try:
a = MyAgent()
a.start()

85
vppapi.py Normal file
View File

@ -0,0 +1,85 @@
'''
The functions in this file interact with the VPP API to retrieve certain
interface metadata.
'''
from vpp_papi import VPPApiClient
import os
import fnmatch
import logging
import threading
class NullHandler(logging.Handler):
def emit(self, record):
pass
logger = logging.getLogger('pyagentx.vppapi')
logger.addHandler(NullHandler())
vpp_lock = threading.Lock()
def vpp_connect():
global logger
vpp_json_dir = '/usr/share/vpp/api/'
# construct a list of all the json api files
jsonfiles = []
for root, dirnames, filenames in os.walk(vpp_json_dir):
for filename in fnmatch.filter(filenames, '*.api.json'):
jsonfiles.append(os.path.join(root, filename))
if not jsonfiles:
logger.error('no json api files found')
return False
vpp = VPPApiClient(apifiles=jsonfiles, server_address='/run/vpp/api.sock')
try:
vpp.connect('vpp-snmp-agent')
except:
return False
v = vpp.api.show_version()
logger.info('VPP version is %s' % v.version)
return vpp
def get_iface(vpp, ifname):
global logger
vpp_lock.acquire()
iface_list = vpp.api.sw_interface_dump(name_filter=ifname,
name_filter_valid=True)
if not iface_list:
logger.error("Can't get interface %s" % ifname)
vpp_lock.release()
return None
for iface in iface_list:
if iface.interface_name == ifname:
vpp_lock.release()
return iface
vpp_lock.release()
return None
def get_ifaces(vpp):
global logger
vpp_lock.acquire()
ret = {}
iface_list = vpp.api.sw_interface_dump()
if not iface_list:
logger.error("Can't get interface list")
vpp_lock.release()
return ret
for iface in iface_list:
ret[iface.interface_name] = iface
vpp_lock.release()
return ret