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)`
127 lines
3.7 KiB
Python
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
|