Files
vpp-snmp-agent/vppapi.py
Pim van Pelt c319ef576d Add an optional configuration file
A simple convenience configfile can provide a mapping between VPP
interface names, Linux Control Plane interface names, and descriptions.
An example:

```
interfaces:
  "TenGigabitEthernet6/0/0":
    description: "Infra: xsw0.chrma0:2"
    lcp: "xe1-0"
  "TenGigabitEthernet6/0/0.3102":
    description: "Infra: QinQ to Solnet for Daedalean"
    lcp: "xe1-0.3102"
  "TenGigabitEthernet6/0/0.310211":
    description: "Cust: Daedalean IP Transit"
    lcp: "xe1-0.3102.11"
```

This configuration file is completely optional. If the `-c` flag is
empty, or it's set but the file does not exist, the Agent will simply
enumerate all interfaces, and set the `ifAlias` OID to the same value
as the `ifName`. However, if the config file is read, it will change
the behavior as follows:

*  Any `tapNN` interface names from VPP will be matched to their PHY by
   looking up their Linux Control Plane interface. The `ifName` field
   will be rewritten to the _LIP_ `host-if`. For example, `tap3` above
   will become `xe1-0` while `tap3.310211` will become `xe1-0.3102.11`.
*  The `ifAlias` OID for a PHY will be set to the `description` field.
*  The `ifAlias` OID for a TAP will be set to the string `LCP: `
   followed by its PHY `ifName`. For example, `xe1-0.3102.11` will
    become `LCP TenGigabitEthernet6/0/0.310211 (tap9)`
2022-02-27 22:58:03 +00:00

127 lines
3.7 KiB
Python

'''
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 socket
class NullHandler(logging.Handler):
def emit(self, record):
pass
logger = logging.getLogger('agentx.vppapi')
logger.addHandler(NullHandler())
class VPPApi():
def __init__(self, address='/run/vpp/api.sock', clientname='vppapi-client'):
self.address = address
self.connected = False
self.clientname = clientname
self.vpp = None
def connect(self):
if self.connected:
return True
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
self.vpp = VPPApiClient(apifiles=jsonfiles,
server_address=self.address)
try:
logger.info('Connecting to VPP')
self.vpp.connect(self.clientname)
except:
return False
v = self.vpp.api.show_version()
logger.info('VPP version is %s' % v.version)
self.connected = True
return True
def disconnect(self):
if not self.connected:
return True
self.vpp.disconnect()
self.connected = False
return True
def get_ifaces(self):
ret = {}
if not self.connected:
return ret
try:
iface_list = self.vpp.api.sw_interface_dump()
except Exception as e:
logger.error("VPP communication error, disconnecting", e)
self.vpp.disconnect()
self.connected = False
return ret
if not iface_list:
logger.error("Can't get interface list")
return ret
for iface in iface_list:
ret[iface.interface_name] = iface
return ret
def get_lcp(self):
ret = {}
if not self.connected:
return ret
try:
lcp_list = self.vpp.api.lcp_itf_pair_get()
except Exception as e:
logger.error("VPP communication error, disconnecting", e)
self.vpp.disconnect()
self.connected = False
return ret
if not lcp_list or not lcp_list[1]:
logger.error("Can't get LCP list")
return ret
## TODO(pim) - fix upstream, the indexes are in network byte order and
## the message is messed up. This hack allows for both little endian and
## big endian responses, and will be removed once VPP's LinuxCP is updated
## and rolled out to AS8298
for lcp in lcp_list[1]:
if lcp.phy_sw_if_index > 65535 or lcp.host_sw_if_index > 65535 or lcp.vif_index > 65535:
i = {
'phy_sw_if_index': socket.ntohl(lcp.phy_sw_if_index),
'host_sw_if_index': socket.ntohl(lcp.host_sw_if_index),
'vif_index': socket.ntohl(lcp.vif_index),
'host_if_name': lcp.host_if_name,
'namespace': lcp.namespace
}
else:
i = {
'phy_sw_if_index': lcp.phy_sw_if_index,
'host_sw_if_index': lcp.host_sw_if_index,
'vif_index': lcp.vif_index,
'host_if_name': lcp.host_if_name,
'namespace': lcp.namespace
}
ret[lcp.host_if_name] = i
return ret