From 509f347d0858e37de9fdeaa1a7aeeb6888fb4b7b Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 19 Aug 2020 18:30:33 +0200 Subject: lldp: op-mode: convert data processing from XML to JSON --- src/op_mode/lldp_op.py | 180 ++++++++++++++++++------------------------------- 1 file changed, 66 insertions(+), 114 deletions(-) (limited to 'src/op_mode/lldp_op.py') 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 - - - - - 00:50:56:9d:a6:11 - VyOS - VyOS unknown - 172.18.254.203 - fe80::250:56ff:fe9d:a611 - - - - - - - 00:50:56:9d:a6:11 - eth0 - 120 - - 10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable - - - eth0.203 - - Network Connectivity Device - - - - - - - - None - 4.19.54-amd64-vyos - 6.00 - VMware-42 1d cf 87 ab 7f da 7e-3 - VMware, Inc. - VMware Virtual Platform - No Asset Tag - - - - - """ - - device = { - 'interface' : neighbor.getAttribute('name'), - 'chassis' : '', - 'proto' : neighbor.getAttribute('via'), - 'descr' : '', - 'cap' : '', - 'platform' : '', - 'port' : '' - } - - # first change to node and then retrieve and - 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 node and then retrieve - 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) -- cgit v1.2.3