diff --git a/README.md b/README.md index 56bc35e..4dc3968 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ optional arguments: -h, --help show this help message and exit -a ADDRESS Location of the SNMPd agent (unix-path or host:port), default localhost:705 -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 ## Install @@ -45,32 +45,43 @@ sudo cp dist/vpp-snmp-agent /usr/sbin/ ## Configuration file -A simple convenience configfile can provide a mapping between VPP interface names, Linux Control Plane -interface names, and descriptions. An example: +This SNMP Agent will read a [vppcfg](https://github.com/pimvanpelt/vppcfg) configuration file, +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: - "TenGigabitEthernet6/0/0": - description: "Infra: xsw0.chrma0:2" - lcp: "xe1-0" - "TenGigabitEthernet6/0/0.3102": - description: "Infra: QinQ to L2 Provider" - lcp: "xe1-0.3102" - "TenGigabitEthernet6/0/0.310211": - description: "Cust: Customer IP Transit" - lcp: "xe1-0.3102.11" + GigabitEthernet3/0/0: + description: "Infra: Some interface" + lcp: e0 + mtu: 9000 + sub-interfaces: + 100: + description: "Cust: Some sub-interface" + 200: + 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 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 `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 - 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)` + interface: + * The `ifName` field will be rewritten to the _LIP_ `host-if`, which is specified by the `lcp` + 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, + `e0.200.11` will become `LCP GigabitEthernet3/0/0.20011 (tap3)` ## SNMPd config diff --git a/vpp-snmp-agent.py b/vpp-snmp-agent.py index 3ac61e5..a06d207 100755 --- a/vpp-snmp-agent.py +++ b/vpp-snmp-agent.py @@ -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): try: 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 except: pass 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): def setup(self): global vppstat, vpp, logger, args @@ -110,11 +125,10 @@ class MyAgent(agentx.Agent): host_sw_if_index = ifaces[ifname].sw_if_index lip = get_lcp_by_host_sw_if_index(lcp, host_sw_if_index) if lip: - phy = get_phy_by_sw_if_index(ifaces, lip['phy_sw_if_index']) - self.logger.debug("LIP: %s PHY: %s" % (lip, phy)) + phy = get_phy_by_sw_if_index(ifaces, lip.phy_sw_if_index) + ifName = lip.host_if_name + self.logger.debug("Setting ifName of %s to '%s'" % (ifname, ifName)) 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) self.logger.debug("Setting ifAlias of %s to '%s'" % (ifname, ifAlias)) except: @@ -216,11 +230,14 @@ class MyAgent(agentx.Agent): if self.config and not ifAlias: try: - ifAlias = self.config['interfaces'][ifname]['description'] - self.logger.debug("Setting ifAlias of %s to '%s'" % (ifname, ifAlias)) + descr = get_description_by_ifname(self.config, ifname) + if descr: + self.logger.debug("Setting ifAlias of %s to config description '%s'" % (ifname, descr)) + ifAlias = descr except: pass if not ifAlias: + self.logger.debug("Setting ifAlias of %s to ifname %s" % (ifname, 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.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.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('-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""") args = parser.parse_args() diff --git a/vpp-snmp-agent.spec b/vpp-snmp-agent.spec index 3edb07d..c642fdb 100644 --- a/vpp-snmp-agent.spec +++ b/vpp-snmp-agent.spec @@ -4,37 +4,41 @@ block_cipher = None -a = Analysis(['vpp-snmp-agent.py'], - pathex=['/home/pim/src/vpp-snmp-agentx'], - binaries=[], - datas=[], - hiddenimports=[], - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=[], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher, - noarchive=False) -pyz = PYZ(a.pure, a.zipped_data, - cipher=block_cipher) +a = Analysis( + ['vpp-snmp-agent.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) -exe = EXE(pyz, - a.scripts, - a.binaries, - a.zipfiles, - a.datas, - [], - name='vpp-snmp-agent', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - upx_exclude=[], - runtime_tmpdir=None, - console=True, - disable_windowed_traceback=False, - target_arch=None, - codesign_identity=None, - entitlements_file=None ) +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='vpp-snmp-agent', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +)