Page MenuHomeVyOS Platform

lldp.py
No OneTemporary

Size
4 KB
Referenced Files
None
Subscribers
None
#!/usr/bin/env python3
#
# Copyright (C) 2023 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
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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 jmespath
import json
import sys
import typing
from tabulate import tabulate
from vyos.configquery import ConfigTreeQuery
from vyos.util import cmd
from vyos.util import dict_search
import vyos.opmode
unconf_message = 'LLDP is not configured'
capability_codes = """Capability Codes: R - Router, B - Bridge, W - Wlan r - Repeater, S - Station
D - Docsis, T - Telephone, O - Other
"""
def _verify(func):
"""Decorator checks if LLDP config exists"""
from functools import wraps
@wraps(func)
def _wrapper(*args, **kwargs):
config = ConfigTreeQuery()
if not config.exists(['service', 'lldp']):
raise vyos.opmode.UnconfiguredSubsystem(unconf_message)
return func(*args, **kwargs)
return _wrapper
def _get_raw_data(interface=None, detail=False):
"""
If interface name is not set - get all interfaces
"""
tmp = 'lldpcli -f json show neighbors'
if detail:
tmp += f' details'
if interface:
tmp += f' ports {interface}'
output = cmd(tmp)
data = json.loads(output)
if not data:
return []
return data
def _get_formatted_output(raw_data):
data_entries = []
for neighbor in dict_search('lldp.interface', raw_data):
for local_if, values in neighbor.items():
tmp = []
# Device field
if 'chassis' in values:
tmp.append(next(iter(values['chassis'])))
else:
tmp.append('')
# Local Port field
tmp.append(local_if)
# Protocol field
tmp.append(values['via'])
# Capabilities
cap = ''
capabilities = jmespath.search('chassis.[*][0][0].capability', values)
# One can not always ensure that "capability" is of type list, add
# safeguard. E.G. Unify US-24-250W only has a dict, not a list of dicts
if isinstance(capabilities, dict):
capabilities = [capabilities]
if capabilities:
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'
tmp.append(cap)
# Remote software platform
platform = jmespath.search('chassis.[*][0][0].descr', values)
tmp.append(platform[:37])
# Remote interface
interface = jmespath.search('port.descr', values)
if not interface:
interface = jmespath.search('port.id.value', values)
if not interface:
interface = 'Unknown'
tmp.append(interface)
# Add individual neighbor to output list
data_entries.append(tmp)
headers = ["Device", "Local Port", "Protocol", "Capability", "Platform", "Remote Port"]
output = tabulate(data_entries, headers, numalign="left")
return capability_codes + output
@_verify
def show_neighbors(raw: bool, interface: typing.Optional[str], detail: typing.Optional[bool]):
lldp_data = _get_raw_data(interface=interface, detail=detail)
if raw:
return lldp_data
else:
return _get_formatted_output(lldp_data)
if __name__ == "__main__":
try:
res = vyos.opmode.run(sys.modules[__name__])
if res:
print(res)
except (ValueError, vyos.opmode.Error) as e:
print(e)
sys.exit(1)

File Metadata

Mime Type
text/x-script.python
Expires
Sat, Oct 17, 12:02 AM (15 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4370137
Default Alt Text
lldp.py (4 KB)

Event Timeline