Move the YAML config to be compatible with vppcfg's config file

This commit is contained in:
Pim van Pelt
2022-07-10 09:45:57 +00:00
parent 3be732e6ab
commit b024a3e96b
3 changed files with 90 additions and 58 deletions

View File

@ -36,7 +36,7 @@ optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
-a ADDRESS Location of the SNMPd agent (unix-path or host:port), default localhost:705 -a ADDRESS Location of the SNMPd agent (unix-path or host:port), default localhost:705
-p PERIOD Period to poll VPP, default 30 (seconds) -p PERIOD Period to poll VPP, default 30 (seconds)
-c CONFIG Optional YAML configuration file, default empty -c CONFIG Optional vppcfg YAML configuration file, default empty
-d Enable debug, default False -d Enable debug, default False
## Install ## Install
@ -45,32 +45,43 @@ sudo cp dist/vpp-snmp-agent /usr/sbin/
## Configuration file ## Configuration file
A simple convenience configfile can provide a mapping between VPP interface names, Linux Control Plane This SNMP Agent will read a [vppcfg](https://github.com/pimvanpelt/vppcfg) configuration file,
interface names, and descriptions. An example: which provides a mapping between VPP interface names, Linux Control Plane interface names, and
descriptions. From the upstream `vppcfg` configuration file, it will only consume the `interfaces`
block, and ignore the rest. An example snippet:
``` ```
interfaces: interfaces:
"TenGigabitEthernet6/0/0": GigabitEthernet3/0/0:
description: "Infra: xsw0.chrma0:2" description: "Infra: Some interface"
lcp: "xe1-0" lcp: e0
"TenGigabitEthernet6/0/0.3102": mtu: 9000
description: "Infra: QinQ to L2 Provider" sub-interfaces:
lcp: "xe1-0.3102" 100:
"TenGigabitEthernet6/0/0.310211": description: "Cust: Some sub-interface"
description: "Cust: Customer IP Transit" 200:
lcp: "xe1-0.3102.11" description: "Cust: Some sub-interface with LCP"
lcp: e0.200
20011:
description: "Cust: Some QinQ sub-interface with LCP"
encapsulation:
dot1q: 200
inner-dot1q: 11
exact-match: true
lcp: e0.200.11
``` ```
This configuration file is completely optional. If the `-c` flag is empty, or it's set but the file does 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 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: the `ifName`. However, if the config file is read, it will change the behavior as follows:
* The `ifAlias` OID for an interface will be set to the `description` field.
* Any `tapNN` interface names from VPP will be matched to their PHY by looking up their Linux Control Plane * 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 interface:
become `xe1-0` while `tap3.310211` will become `xe1-0.3102.11`. * The `ifName` field will be rewritten to the _LIP_ `host-if`, which is specified by the `lcp`
* The `ifAlias` OID for a PHY will be set to the `description` field. field. For example, `tap3` above will become `e0` while `tap3.20011` will become `e0.200.11`.
* The `ifAlias` OID for a TAP will be set to the string `LCP ` followed by its PHY `ifName`. For example, * 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)` `e0.200.11` will become `LCP GigabitEthernet3/0/0.20011 (tap3)`
## SNMPd config ## SNMPd config

View File

@ -26,13 +26,28 @@ def get_phy_by_sw_if_index(ifaces, sw_if_index):
def get_lcp_by_host_sw_if_index(lcp, host_sw_if_index): def get_lcp_by_host_sw_if_index(lcp, host_sw_if_index):
try: try:
for k,v in lcp.items(): for k,v in lcp.items():
if v['host_sw_if_index'] == host_sw_if_index: if v.host_sw_if_index == host_sw_if_index:
return v return v
except: except:
pass pass
return None return None
def get_description_by_ifname(config, ifname):
try:
for phy_name, phy in config['interfaces'].items():
if ifname == phy_name:
return phy['description']
if 'sub-interfaces' in phy:
for sub_id, sub_int in config['interfaces'][phy_name]['sub-interfaces'].items():
sub_ifname = "%s.%d" % (phy_name, sub_id)
if ifname == sub_ifname:
return sub_int['description']
except:
pass
return None
class MyAgent(agentx.Agent): class MyAgent(agentx.Agent):
def setup(self): def setup(self):
global vppstat, vpp, logger, args global vppstat, vpp, logger, args
@ -110,11 +125,10 @@ class MyAgent(agentx.Agent):
host_sw_if_index = ifaces[ifname].sw_if_index host_sw_if_index = ifaces[ifname].sw_if_index
lip = get_lcp_by_host_sw_if_index(lcp, host_sw_if_index) lip = get_lcp_by_host_sw_if_index(lcp, host_sw_if_index)
if lip: if lip:
phy = get_phy_by_sw_if_index(ifaces, lip['phy_sw_if_index']) phy = get_phy_by_sw_if_index(ifaces, lip.phy_sw_if_index)
self.logger.debug("LIP: %s PHY: %s" % (lip, phy)) ifName = lip.host_if_name
self.logger.debug("Setting ifName of %s to '%s'" % (ifname, ifName))
if phy: if phy:
ifName = self.config['interfaces'][phy.interface_name]['lcp']
self.logger.debug("Setting ifName of %s to '%s'" % (ifname, ifName))
ifAlias = "LCP %s (%s)" % (phy.interface_name,ifname) ifAlias = "LCP %s (%s)" % (phy.interface_name,ifname)
self.logger.debug("Setting ifAlias of %s to '%s'" % (ifname, ifAlias)) self.logger.debug("Setting ifAlias of %s to '%s'" % (ifname, ifAlias))
except: except:
@ -216,11 +230,14 @@ class MyAgent(agentx.Agent):
if self.config and not ifAlias: if self.config and not ifAlias:
try: try:
ifAlias = self.config['interfaces'][ifname]['description'] descr = get_description_by_ifname(self.config, ifname)
self.logger.debug("Setting ifAlias of %s to '%s'" % (ifname, ifAlias)) if descr:
self.logger.debug("Setting ifAlias of %s to config description '%s'" % (ifname, descr))
ifAlias = descr
except: except:
pass pass
if not ifAlias: if not ifAlias:
self.logger.debug("Setting ifAlias of %s to ifname %s" % (ifname, ifname))
ifAlias = ifname ifAlias = ifname
ds.set('1.3.6.1.2.1.31.1.1.1.18.%u' % (idx), 'str', ifAlias) ds.set('1.3.6.1.2.1.31.1.1.1.18.%u' % (idx), 'str', ifAlias)
ds.set('1.3.6.1.2.1.31.1.1.1.19.%u' % (idx), 'ticks', 0) # Hardcode to Timeticks: (0) 0:00:00.00 ds.set('1.3.6.1.2.1.31.1.1.1.19.%u' % (idx), 'ticks', 0) # Hardcode to Timeticks: (0) 0:00:00.00
@ -232,7 +249,7 @@ def main():
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-a', dest='address', default="localhost:705", type=str, help="""Location of the SNMPd agent (unix-path or host:port), default localhost:705""") parser.add_argument('-a', dest='address', default="localhost:705", type=str, help="""Location of the SNMPd agent (unix-path or host:port), default localhost:705""")
parser.add_argument('-p', dest='period', type=int, default=30, help="""Period to poll VPP, default 30 (seconds)""") parser.add_argument('-p', dest='period', type=int, default=30, help="""Period to poll VPP, default 30 (seconds)""")
parser.add_argument('-c', dest='config', type=str, help="""Optional YAML configuration file, default empty""") parser.add_argument('-c', dest='config', type=str, help="""Optional vppcfg YAML configuration file, default empty""")
parser.add_argument('-d', dest='debug', action='store_true', help="""Enable debug, default False""") parser.add_argument('-d', dest='debug', action='store_true', help="""Enable debug, default False""")
args = parser.parse_args() args = parser.parse_args()

View File

@ -4,37 +4,41 @@
block_cipher = None block_cipher = None
a = Analysis(['vpp-snmp-agent.py'], a = Analysis(
pathex=['/home/pim/src/vpp-snmp-agentx'], ['vpp-snmp-agent.py'],
binaries=[], pathex=[],
datas=[], binaries=[],
hiddenimports=[], datas=[],
hookspath=[], hiddenimports=[],
hooksconfig={}, hookspath=[],
runtime_hooks=[], hooksconfig={},
excludes=[], runtime_hooks=[],
win_no_prefer_redirects=False, excludes=[],
win_private_assemblies=False, win_no_prefer_redirects=False,
cipher=block_cipher, win_private_assemblies=False,
noarchive=False) cipher=block_cipher,
pyz = PYZ(a.pure, a.zipped_data, noarchive=False,
cipher=block_cipher) )
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(pyz, exe = EXE(
a.scripts, pyz,
a.binaries, a.scripts,
a.zipfiles, a.binaries,
a.datas, a.zipfiles,
[], a.datas,
name='vpp-snmp-agent', [],
debug=False, name='vpp-snmp-agent',
bootloader_ignore_signals=False, debug=False,
strip=False, bootloader_ignore_signals=False,
upx=True, strip=False,
upx_exclude=[], upx=True,
runtime_tmpdir=None, upx_exclude=[],
console=True, runtime_tmpdir=None,
disable_windowed_traceback=False, console=True,
target_arch=None, disable_windowed_traceback=False,
codesign_identity=None, argv_emulation=False,
entitlements_file=None ) target_arch=None,
codesign_identity=None,
entitlements_file=None,
)