get_lldp_neighbors.py 5.39 KB
Newer Older
1
2
3
# ---------------------------------------------------------------------
# Generic.get_lldp_neighbors
# ---------------------------------------------------------------------
4
# Copyright (C) 2007-2020 The NOC Project
5
6
7
8
9
10
11
# See LICENSE for details
# ---------------------------------------------------------------------

# NOC modules
from noc.core.script.base import BaseScript
from noc.sa.interfaces.igetlldpneighbors import IGetLLDPNeighbors
from noc.core.mac import MAC
12
from noc.core.mib import mib
13
14
15
16
17
18
19
from noc.core.lldp import (
    LLDP_PORT_SUBTYPE_ALIAS,
    LLDP_PORT_SUBTYPE_MAC,
    LLDP_PORT_SUBTYPE_LOCAL,
    LLDP_PORT_SUBTYPE_COMPONENT,
    LLDP_CHASSIS_SUBTYPE_MAC,
)
20
21
from noc.core.comp import smart_text
from noc.core.snmp.render import render_bin
22
23
24
25
26
27
28


class Script(BaseScript):
    name = "Generic.get_lldp_neighbors"
    cache = True
    interface = IGetLLDPNeighbors

29
30
31
32
33
34
35
36
37
38
39
    # Lookup from different tables if port type is `Iface alias`
    # 1 - LLDP-MIB::lldpLocPortId
    # 2 - LLDP-MIB::lldpLocPortDesc
    LLDP_PORT_TABLE = 2

    def get_interface_alias(self, port_id, port_descr):
        if self.LLDP_PORT_TABLE == 1:
            return port_id
        else:
            return port_descr

40
41
    def get_local_iface(self):
        r = {}
42
        names = {x: y for y, x in self.scripts.get_ifindexes().items()}
43
44
        # Get LocalPort Table
        for port_num, port_subtype, port_id, port_descr in self.snmp.get_tables(
Dmitry Volodin's avatar
Dmitry Volodin committed
45
46
47
48
            [
                mib["LLDP-MIB::lldpLocPortIdSubtype"],
                mib["LLDP-MIB::lldpLocPortId"],
                mib["LLDP-MIB::lldpLocPortDesc"],
49
50
            ],
            max_retries=1,
Dmitry Volodin's avatar
Dmitry Volodin committed
51
        ):
52
            if port_subtype == LLDP_PORT_SUBTYPE_ALIAS:
53
                # Iface alias
54
                iface_name = self.get_interface_alias(port_id, port_descr)
55
            elif port_subtype == LLDP_PORT_SUBTYPE_MAC:
56
57
                # Iface MAC address
                raise NotImplementedError()
58
59
60
61
62
            elif (
                port_subtype == LLDP_PORT_SUBTYPE_LOCAL
                and port_id.isdigit()
                and int(port_id) in names
            ):
63
64
65
66
67
                # Iface local (ifindex)
                iface_name = names[int(port_id)]
            else:
                # Iface local
                iface_name = port_id
Dmitry Volodin's avatar
Dmitry Volodin committed
68
            r[port_num] = {"local_interface": iface_name, "local_interface_subtype": port_subtype}
69
        if not r:
Dmitry Volodin's avatar
Dmitry Volodin committed
70
71
72
            self.logger.warning(
                "Not getting local LLDP port mappings. Check 1.0.8802.1.1.2.1.3.7 table"
            )
73
74
75
            raise NotImplementedError()
        return r

76
    def execute_snmp(self):
77
        neighb = (
Dmitry Volodin's avatar
Dmitry Volodin committed
78
79
80
81
82
83
            "remote_chassis_id_subtype",
            "remote_chassis_id",
            "remote_port_subtype",
            "remote_port",
            "remote_port_description",
            "remote_system_name",
84
        )
85
        r = []
86
        local_ports = self.get_local_iface()
87
        if self.has_snmp():
Dmitry Volodin's avatar
Dmitry Volodin committed
88
89
90
91
92
93
94
95
96
97
            for v in self.snmp.get_tables(
                [
                    mib["LLDP-MIB::lldpRemLocalPortNum"],
                    mib["LLDP-MIB::lldpRemChassisIdSubtype"],
                    mib["LLDP-MIB::lldpRemChassisId"],
                    mib["LLDP-MIB::lldpRemPortIdSubtype"],
                    mib["LLDP-MIB::lldpRemPortId"],
                    mib["LLDP-MIB::lldpRemPortDesc"],
                    mib["LLDP-MIB::lldpRemSysName"],
                ],
98
                max_retries=1,
99
100
101
102
                display_hints={
                    "1.0.8802.1.1.2.1.4.1.1.7": render_bin,
                    "1.0.8802.1.1.2.1.4.1.1.5": render_bin,
                },
Dmitry Volodin's avatar
Dmitry Volodin committed
103
            ):
104
105
                if v:
                    neigh = dict(zip(neighb, v[2:]))
106
                    # cleaning
107
108
                    if neigh["remote_port_subtype"] == LLDP_PORT_SUBTYPE_COMPONENT:
                        neigh["remote_port_subtype"] = LLDP_PORT_SUBTYPE_ALIAS
109
                    neigh["remote_port"] = neigh["remote_port"].replace(b" \x00", b"")
110
                    if neigh["remote_chassis_id_subtype"] == LLDP_CHASSIS_SUBTYPE_MAC:
Dmitry Volodin's avatar
Dmitry Volodin committed
111
                        neigh["remote_chassis_id"] = MAC(neigh["remote_chassis_id"])
112
                    if neigh["remote_port_subtype"] == LLDP_PORT_SUBTYPE_MAC:
113
114
115
                        try:
                            neigh["remote_port"] = MAC(neigh["remote_port"])
                        except ValueError:
Dmitry Volodin's avatar
Dmitry Volodin committed
116
117
118
                            self.logger.warning(
                                "Bad MAC address on Remote Neighbor: %s", neigh["remote_port"]
                            )
119
                    else:
120
                        neigh["remote_port"] = smart_text(neigh["remote_port"]).rstrip("\x00")
121
                    if "remote_system_name" in neigh:
122
123
124
                        neigh["remote_system_name"] = smart_text(
                            neigh["remote_system_name"]
                        ).rstrip("\x00")
125
126
                    if "remote_port_description" in neigh:
                        neigh["remote_port_description"] = neigh["remote_port_description"].rstrip(
127
                            "\x00"
128
                        )
Dmitry Volodin's avatar
Dmitry Volodin committed
129
130
131
132
133
134
135
136
                    r += [
                        {
                            "local_interface": local_ports[v[0].split(".")[1]]["local_interface"],
                            # @todo if local interface subtype != 5
                            # "local_interface_id": 5,
                            "neighbors": [neigh],
                        }
                    ]
137
        return r