diff options
author | Marcus Hoff <marcus.hoff@ring2.dk> | 2020-09-05 09:58:03 +0200 |
---|---|---|
committer | Marcus Hoff <marcus.hoff@ring2.dk> | 2020-09-05 09:58:03 +0200 |
commit | 46fb580fa0131f6815bbcfc95631654f6fe999a8 (patch) | |
tree | 73ae9fcaa97d5cfab7883bc6fbf3ea036677c2a3 /src/op_mode/lldp_op.py | |
parent | 0377b8e40b0d3e424da11194e97659c5066c0a1d (diff) | |
parent | b6b61bc9ecf1328e67a0c15934f8bf3966a6b66d (diff) | |
download | vyos-1x-46fb580fa0131f6815bbcfc95631654f6fe999a8.tar.gz vyos-1x-46fb580fa0131f6815bbcfc95631654f6fe999a8.zip |
Merge remote-tracking branch 'upstream/current' into current
Diffstat (limited to 'src/op_mode/lldp_op.py')
-rwxr-xr-x | src/op_mode/lldp_op.py | 185 |
1 files changed, 70 insertions, 115 deletions
diff --git a/src/op_mode/lldp_op.py b/src/op_mode/lldp_op.py index 5d48e3210..06958c605 100755 --- a/src/op_mode/lldp_op.py +++ b/src/op_mode/lldp_op.py @@ -14,19 +14,19 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. - import argparse import jinja2 +import json -from xml.dom import minidom from sys import exit from tabulate import tabulate -from vyos.util import popen +from vyos.util import cmd from vyos.config import Config parser = argparse.ArgumentParser() parser.add_argument("-a", "--all", action="store_true", help="Show LLDP neighbors on all interfaces") +parser.add_argument("-d", "--detail", action="store_true", help="Show detailes LLDP neighbor information on all interfaces") parser.add_argument("-i", "--interface", action="store", help="Show LLDP neighbors on specific interface") # Please be careful if you edit the template. @@ -35,108 +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(): - command = '/usr/sbin/lldpcli -f xml show neighbors' - out,_ = popen(command) - return out - -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 +def get_neighbors(): + 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() @@ -147,24 +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) ) + 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) |