diff options
-rw-r--r-- | data/templates/frr/ldpd.frr.tmpl | 12 | ||||
-rw-r--r-- | interface-definitions/protocols-mpls.xml.in | 26 | ||||
-rwxr-xr-x | src/conf_mode/protocols_mpls.py | 24 | ||||
-rwxr-xr-x | src/op_mode/lldp_op.py | 180 |
4 files changed, 124 insertions, 118 deletions
diff --git a/data/templates/frr/ldpd.frr.tmpl b/data/templates/frr/ldpd.frr.tmpl index bbff88ae5..dbaa917e8 100644 --- a/data/templates/frr/ldpd.frr.tmpl +++ b/data/templates/frr/ldpd.frr.tmpl @@ -21,6 +21,18 @@ no discovery transport-address {{ old_ldp.d_transp_ipv4 }} {% if ldp.d_transp_ipv4 -%} discovery transport-address {{ ldp.d_transp_ipv4 }} {% endif -%} +{% if old_ldp.hello_holdtime -%} +no discovery hello holdtime {{ old_ldp.hello_holdtime }} +{% endif -%} +{% if ldp.hello_holdtime -%} +discovery hello holdtime {{ ldp.hello_holdtime }} +{% endif -%} +{% if old_ldp.hello_interval -%} +no discovery hello interval {{ old_ldp.hello_interval }} +{% endif -%} +{% if ldp.hello_interval -%} +discovery hello interval {{ ldp.hello_interval }} +{% endif -%} {% for interface in old_ldp.interfaces -%} no interface {{interface}} {% endfor -%} diff --git a/interface-definitions/protocols-mpls.xml.in b/interface-definitions/protocols-mpls.xml.in index 376323855..3e9edbf72 100644 --- a/interface-definitions/protocols-mpls.xml.in +++ b/interface-definitions/protocols-mpls.xml.in @@ -54,6 +54,30 @@ </valueHelp> </properties> <children> + <leafNode name="hello-holdtime"> + <properties> + <help>Hello holdtime</help> + <valueHelp> + <format>1-65535</format> + <description>Time in seconds</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + </properties> + </leafNode> + <leafNode name="hello-interval"> + <properties> + <help>Hello interval</help> + <valueHelp> + <format>1-65535</format> + <description>Time in seconds</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + </properties> + </leafNode> <leafNode name="transport-ipv4-address"> <properties> <help>Transport ipv4 address</help> @@ -95,4 +119,4 @@ </node> </children> </node> -</interfaceDefinition>
\ No newline at end of file +</interfaceDefinition> diff --git a/src/conf_mode/protocols_mpls.py b/src/conf_mode/protocols_mpls.py index 72208ffa1..bcb16fa04 100755 --- a/src/conf_mode/protocols_mpls.py +++ b/src/conf_mode/protocols_mpls.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019 VyOS maintainers and contributors +# Copyright (C) 2019-2020 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -38,13 +38,17 @@ def get_config(): 'interfaces' : [], 'neighbors' : {}, 'd_transp_ipv4' : None, - 'd_transp_ipv6' : None + 'd_transp_ipv6' : None, + 'hello_holdtime' : None, + 'hello_interval' : None }, 'ldp' : { 'interfaces' : [], 'neighbors' : {}, 'd_transp_ipv4' : None, - 'd_transp_ipv6' : None + 'd_transp_ipv6' : None, + 'hello_holdtime' : None, + 'hello_interval' : None } } if not (conf.exists('protocols mpls') or conf.exists_effective('protocols mpls')): @@ -61,6 +65,20 @@ def get_config(): if conf.exists('router-id'): mpls_conf['router_id'] = conf.return_value('router-id') + # Get hello holdtime + if conf.exists_effective('discovery hello-holdtime'): + mpls_conf['old_ldp']['hello_holdtime'] = conf.return_effective_value('discovery hello-holdtime') + + if conf.exists('discovery hello-holdtime'): + mpls_conf['ldp']['hello_holdtime'] = conf.return_value('discovery hello-holdtime') + + # Get hello interval + if conf.exists_effective('discovery hello-interval'): + mpls_conf['old_ldp']['hello_interval'] = conf.return_effective_value('discovery hello-interval') + + if conf.exists('discovery hello-interval'): + mpls_conf['ldp']['hello_interval'] = conf.return_value('discovery hello-interval') + # Get discovery transport-ipv4-address if conf.exists_effective('discovery transport-ipv4-address'): mpls_conf['old_ldp']['d_transp_ipv4'] = conf.return_effective_value('discovery transport-ipv4-address') diff --git a/src/op_mode/lldp_op.py b/src/op_mode/lldp_op.py index 0df6749aa..06958c605 100755 --- a/src/op_mode/lldp_op.py +++ b/src/op_mode/lldp_op.py @@ -16,10 +16,10 @@ import argparse import jinja2 +import json from sys import exit from tabulate import tabulate -from xml.dom import minidom from vyos.util import cmd from vyos.config import Config @@ -35,106 +35,61 @@ lldp_out = """Capability Codes: R - Router, B - Bridge, W - Wlan r - Repeater, S Device ID Local Proto Cap Platform Port ID --------- ----- ----- --- -------- ------- -{% for n in neighbors -%} -{{ "%-25s" | format(n.chassis) }} {{ "%-9s" | format(n.interface) }} {{ "%-6s" | format(n.proto) }} {{ "%-5s" | format(n.cap) }} {{ "%-20s" | format(n.platform) }} {{ n.port }} -{% endfor -%} +{% for neighbor in neighbors %} +{% for local_if, info in neighbor.items() %} +{{ "%-25s" | format(info.chassis) }} {{ "%-9s" | format(local_if) }} {{ "%-6s" | format(info.proto) }} {{ "%-5s" | format(info.capabilities) }} {{ "%-20s" | format(info.platform[:18]) }} {{ info.remote_if }} +{% endfor %} +{% endfor %} """ def get_neighbors(): - return cmd('/usr/sbin/lldpcli -f xml show neighbors') - -def extract_neighbor(neighbor): - """ - Extract LLDP neighbor information from XML document passed as param neighbor - - <lldp> - <interface label="Interface" name="eth0" via="LLDP" rid="3" age="0 day, 00:17:42"> - <chassis label="Chassis"> - <id label="ChassisID" type="mac">00:50:56:9d:a6:11</id> - <name label="SysName">VyOS</name> - <descr label="SysDescr">VyOS unknown</descr> - <mgmt-ip label="MgmtIP">172.18.254.203</mgmt-ip> - <mgmt-ip label="MgmtIP">fe80::250:56ff:fe9d:a611</mgmt-ip> - <capability label="Capability" type="Bridge" enabled="off"/> - <capability label="Capability" type="Router" enabled="on"/> - <capability label="Capability" type="Wlan" enabled="off"/> - <capability label="Capability" type="Station" enabled="off"/> - </chassis> - <port label="Port"> - <id label="PortID" type="mac">00:50:56:9d:a6:11</id> - <descr label="PortDescr">eth0</descr> - <ttl label="TTL">120</ttl> - <auto-negotiation label="PMD autoneg" supported="no" enabled="no"> - <current label="MAU oper type">10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable</current> - </auto-negotiation> - </port> - <vlan label="VLAN" vlan-id="203">eth0.203</vlan> - <lldp-med label="LLDP-MED"> - <device-type label="Device Type">Network Connectivity Device</device-type> - <capability label="Capability" type="Capabilities" available="yes"/> - <capability label="Capability" type="Policy" available="yes"/> - <capability label="Capability" type="Location" available="yes"/> - <capability label="Capability" type="MDI/PSE" available="yes"/> - <capability label="Capability" type="MDI/PD" available="yes"/> - <capability label="Capability" type="Inventory" available="yes"/> - <inventory label="Inventory"> - <hardware label="Hardware Revision">None</hardware> - <software label="Software Revision">4.19.54-amd64-vyos</software> - <firmware label="Firmware Revision">6.00</firmware> - <serial label="Serial Number">VMware-42 1d cf 87 ab 7f da 7e-3</serial> - <manufacturer label="Manufacturer">VMware, Inc.</manufacturer> - <model label="Model">VMware Virtual Platform</model> - <asset label="Asset ID">No Asset Tag</asset> - </inventory> - </lldp-med> - </interface> - </lldp> - """ - - device = { - 'interface' : neighbor.getAttribute('name'), - 'chassis' : '', - 'proto' : neighbor.getAttribute('via'), - 'descr' : '', - 'cap' : '', - 'platform' : '', - 'port' : '' - } - - # first change to <chassis> node and then retrieve <name> and <descr> - chassis = neighbor.getElementsByTagName('chassis') - device['chassis'] = chassis[0].getElementsByTagName('name')[0].firstChild.data - # Cisco IOS comes with a ',' remove character .... - device['platform'] = chassis[0].getElementsByTagName('descr')[0].firstChild.data[:20].replace(',',' ') - - # extract capabilities - for capability in chassis[0].getElementsByTagName('capability'): - # we are only interested in enabled capabilities ... - if capability.getAttribute('enabled') == "on": - if capability.getAttribute('type') == "Router": - device['cap'] += 'R' - elif capability.getAttribute('type') == "Bridge": - device['cap'] += 'B' - elif capability.getAttribute('type') == "Wlan": - device['cap'] += 'W' - elif capability.getAttribute('type') == "Station": - device['cap'] += 'S' - elif capability.getAttribute('type') == "Repeater": - device['cap'] += 'r' - elif capability.getAttribute('type') == "Telephone": - device['cap'] += 'T' - elif capability.getAttribute('type') == "Docsis": - device['cap'] += 'D' - elif capability.getAttribute('type') == "Other": - device['cap'] += 'O' - - # first change to <port> node and then retrieve <descr> - port = neighbor.getElementsByTagName('port') - port = port[0].getElementsByTagName('descr')[0].firstChild.data - device['port'] = port - - - return device + return cmd('/usr/sbin/lldpcli -f json show neighbors') + +def parse_data(data): + output = [] + for tmp in data: + for local_if, values in tmp.items(): + for chassis, c_value in values.get('chassis', {}).items(): + capabilities = c_value['capability'] + if isinstance(capabilities, dict): + capabilities = [capabilities] + + cap = '' + for capability in capabilities: + if capability['enabled']: + if capability['type'] == 'Router': + cap += 'R' + if capability['type'] == 'Bridge': + cap += 'B' + if capability['type'] == 'Wlan': + cap += 'W' + if capability['type'] == 'Station': + cap += 'S' + if capability['type'] == 'Repeater': + cap += 'r' + if capability['type'] == 'Telephone': + cap += 'T' + if capability['type'] == 'Docsis': + cap += 'D' + if capability['type'] == 'Other': + cap += 'O' + + + remote_if = 'Unknown' + if 'descr' in values.get('port', {}): + remote_if = values.get('port', {}).get('descr') + elif 'id' in values.get('port', {}): + remote_if = values.get('port', {}).get('id').get('value', 'Unknown') + + output.append({local_if: {'chassis': chassis, + 'remote_if': remote_if, + 'proto': values.get('via','Unknown'), + 'platform': c_value.get('descr', 'Unknown'), + 'capabilities': cap}}) + + + output = {'neighbors': output} + return output if __name__ == '__main__': args = parser.parse_args() @@ -145,29 +100,26 @@ if __name__ == '__main__': print('Service LLDP is not configured') exit(0) - if args.all: - neighbors = minidom.parseString(get_neighbors()) - for neighbor in neighbors.getElementsByTagName('interface'): - tmp['neighbors'].append( extract_neighbor(neighbor) ) - - elif args.detail: - out = cmd('/usr/sbin/lldpctl -f plain') - print(out) + if args.detail: + print(cmd('/usr/sbin/lldpctl -f plain')) exit(0) + elif args.all or args.interface: + tmp = json.loads(get_neighbors()) - elif args.interface: - neighbors = minidom.parseString(get_neighbors()) - for neighbor in neighbors.getElementsByTagName('interface'): - # check if neighbor appeared on proper interface - if neighbor.getAttribute('name') == args.interface: - tmp['neighbors'].append( extract_neighbor(neighbor) ) + if args.all: + neighbors = tmp['lldp']['interface'] + elif args.interface: + neighbors = [] + for neighbor in tmp['lldp']['interface']: + if args.interface in neighbor: + neighbors.append(neighbor) else: parser.print_help() exit(1) - tmpl = jinja2.Template(lldp_out) - config_text = tmpl.render(tmp) + tmpl = jinja2.Template(lldp_out, trim_blocks=True) + config_text = tmpl.render(parse_data(neighbors)) print(config_text) exit(0) |