Files
infix/src/statd/python/yanger/infix_lldp.py
T

103 lines
3.7 KiB
Python

from .host import HOST
from collections import defaultdict
def operational():
"""Retrieve LLDP neighbor information and store in remote-systems-data under the correct port."""
# https://www.ieee802.org/1/files/public/YANGs/ieee802-types.yang
# <chassis-component> and <port-component> subtypes are not supported in
# https://github.com/lldpd/lldpd until v1.0.19
chassis_id_subtype_mapping = {
#"unhandled": "chassis-component",
"ifalias": "interface-alias",
#"unhandled": "port-component",
"mac": "mac-address",
"ip": "network-address",
"ifname": "interface-name",
"local": "local"
}
# https://www.ieee802.org/1/files/public/YANGs/ieee802-types.yang
# <port-component> and <agent-circuit-id> subtypes are not supported in
# https://github.com/lldpd/lldpd until v1.0.19
port_id_subtype_mapping = {
"ifalias": "interface-alias",
#"unhandled": "port-component",
"mac": "mac-address",
"ip": "network-address",
"ifname": "interface-name",
#"unhandled": "agent-circuit-id"
"local": "local"
}
LLDP_MULTICAST_MAC = "01:80:C2:00:00:0E"
port_data = defaultdict(lambda: {"remote-systems-data": [], "dest-mac-address": LLDP_MULTICAST_MAC})
data = HOST.run_json(["lldpcli", "show", "neighbors", "-f", "json"])
interfaces = data.get("lldp", {}).get("interface", [])
if isinstance(interfaces, dict):
interfaces = [interfaces]
for iface_entry in interfaces:
for iface_name, iface_data in iface_entry.items():
remote_index = int(iface_data.get("rid", 0))
time_mark = parse_time(iface_data.get("age"))
chassis = iface_data.get("chassis", {})
chassis_id_type, chassis_id_value = extract_chassis_id(chassis, chassis_id_subtype_mapping)
port_info = iface_data.get("port", {})
port_id_type = port_id_subtype_mapping.get(port_info.get("id", {}).get("type"), "unknown")
port_id_value = port_info.get("id", {}).get("value", "")
remote_entry = {
"time-mark": time_mark,
"remote-index": remote_index,
"chassis-id-subtype": chassis_id_type,
"chassis-id": chassis_id_value,
"port-id-subtype": port_id_type,
"port-id": port_id_value
}
port_data[iface_name]["remote-systems-data"].append(remote_entry)
formatted_output = {
"ieee802-dot1ab-lldp:lldp": {
"port": [
{
"name": port_name,
"dest-mac-address": port_info["dest-mac-address"],
"remote-systems-data": port_info["remote-systems-data"]
}
for port_name, port_info in port_data.items() if port_info["remote-systems-data"]
]
}
}
return formatted_output
def extract_chassis_id(chassis_block, subtype_mapping):
if "id" in chassis_block:
id_info = chassis_block["id"]
return subtype_mapping.get(id_info.get("type"), "unknown"), id_info.get("value", "")
for _, value in chassis_block.items():
if isinstance(value, dict) and "id" in value:
id_info = value["id"]
return subtype_mapping.get(id_info.get("type"), "unknown"), id_info.get("value", "")
return "unknown", ""
def parse_time(time_str):
"""Convert LLDP time format to seconds"""
import re
if time_str:
match = re.search(r"(\d+)\s*day[s]*,\s*(\d+):(\d+):(\d+)", time_str)
if match:
days, hours, minutes, seconds = map(int, match.groups())
return days * 86400 + hours * 3600 + minutes * 60 + seconds
return 0