From 59948a5f9fe6c83b81c6964c8f09a5bb75283fa3 Mon Sep 17 00:00:00 2001 From: Carlo Maragno Date: Mon, 28 Nov 2022 14:14:10 +0100 Subject: [PATCH 1/4] Fix issue in lldp neighbors discovery for IOS devices. The parsing logic incorrectly assumes that "remote_chassis_id" and "remote_port" will always contain MAC addresses --- napalm/ios/ios.py | 16 ++++- .../no_mac_support/expected_result.json | 15 ++++ .../no_mac_support/show_lldp_neighbors.txt | 8 +++ .../show_lldp_neighbors_detail.txt | 68 +++++++++++++++++++ 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json create mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt create mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 6235f5880..21374fae6 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -44,6 +44,7 @@ generate_regex_or, sanitize_configs, ) +from netaddr.core import AddrFormatError from napalm.base.netmiko_helpers import netmiko_args # Easier to store these as constants @@ -985,9 +986,20 @@ def get_lldp_neighbors(self): port = lldp_entry["remote_port"] # Match IOS behaviour of taking remote chassis ID # When lacking a system name (in show lldp neighbors) + # This implementation is compliant with the spec, as we can't assume remote_chassis_id or remote_port + # are mac address. See IEEE 802.1AB-2005 and rfc2922, specifically PtopoChassisId if not hostname: - hostname = napalm.base.helpers.mac(lldp_entry["remote_chassis_id"]) - port = napalm.base.helpers.mac(port) + try: + hostname = napalm.base.helpers.mac( + lldp_entry["remote_chassis_id"] + ) + except AddrFormatError: + hostname = lldp_entry["remote_chassis_id"] + + try: + port = napalm.base.helpers.mac(port) + except AddrFormatError: + pass lldp_dict = {"port": port, "hostname": hostname} lldp[intf_name].append(lldp_dict) diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json new file mode 100644 index 000000000..49bc80227 --- /dev/null +++ b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json @@ -0,0 +1,15 @@ +{ + "GigabitEthernet9/48": [ + { + "port": "Gi0", + "hostname": "COMPUTER.company.example.com" + } + ] + , + "GigabitEthernet9/8": [ + { + "port": "A1:8B:95:B5:E4:6F", + "hostname": "NICEHOSTNAME" + } + ] +} diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt new file mode 100644 index 000000000..f7074e0d7 --- /dev/null +++ b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt @@ -0,0 +1,8 @@ + +Capability codes: + (R) Router, (B) Bridge, (T) Telephone, (C) DOCSIS Cable Device + (W) WLAN Access Point, (P) Repeater, (S) Station, (O) Other + +Device ID Local Intf Hold-time Capability Port ID +ACOMPUTER.company.exGi9/48 120 B Gi0 +NICEHOSTNAME Gi9/8 3601 a18b.95b5.e46f diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt new file mode 100644 index 000000000..5908277d6 --- /dev/null +++ b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt @@ -0,0 +1,68 @@ +------------------------------------------------ +Local Intf: Gi9/48 +Chassis id: 4a07.d0f3.fbb6 +Port id: Gi0 +Port Description: GigabitEthernet0 +System Name: COMPUTER.company.example.com + +System Description: +Cisco IOS Software, C3600 Software (AP3G2-K9W8-M), Version 15.3(3)JC15, RELEASE SOFTWARE (fc1) +Technical Support: http://www.cisco.com/techsupport +Copyright (c) 1986-2018 by Cisco Systems, Inc. +Compiled Thu 07-Jun-18 16:43 by prod_rel_team + +Time remaining: 95 seconds +System Capabilities: B +Enabled Capabilities: B +Management Addresses: + IP: 10.31.18.65 +Auto Negotiation - supported, enabled +Physical media capabilities: + 1000baseT(FD) + 1000baseT(HD) + 100base-TX(FD) + 100base-TX(HD) + 10base-T(FD) + 10base-T(HD) +Media Attachment Unit type: 30 +Vlan ID: - not advertised +PoE+ Power-via-MDI TLV: + Power Pair: Signal + Power Class: Class 4 + Power Device Type: Type 1 PD + Power Source: PSE + Power Priority: high + Power Requested: 13000 mW + Power Allocated: 13000 mW + +------------------------------------------------ +Local Intf: Gi9/8 +Chassis id: NICEHOSTNAME +Port id: a18b.95b5.e46f +Port Description - not advertised +System Name - not advertised +System Description - not advertised + +Time remaining: 2690 seconds +System Capabilities - not advertised +Enabled Capabilities - not advertised +Management Addresses - not advertised +Auto Negotiation - supported, enabled +Physical media capabilities: + 1000baseT(FD) +Media Attachment Unit type - not advertised +Vlan ID: - not advertised + +MED Information: + + MED Codes: + (NP) Network Policy, (LI) Location Identification + (PS) Power Source Entity, (PD) Power Device + (IN) Inventory + + Inventory information - not advertised + Capabilities: + Device type: Endpoint Class I + Network Policies - not advertised + Power requirements - not advertised + Location - not advertised From e92bdb76d37f7e3923d1ebe9e474757ef74742a1 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Thu, 16 Feb 2023 12:09:38 -0800 Subject: [PATCH 2/4] Fix linting issue, minor change to port normalization --- napalm/ios/ios.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 21374fae6..9bfd1d723 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -985,9 +985,10 @@ def get_lldp_neighbors(self): hostname = lldp_entry["remote_system_name"] port = lldp_entry["remote_port"] # Match IOS behaviour of taking remote chassis ID - # When lacking a system name (in show lldp neighbors) - # This implementation is compliant with the spec, as we can't assume remote_chassis_id or remote_port - # are mac address. See IEEE 802.1AB-2005 and rfc2922, specifically PtopoChassisId + # when lacking a system name (in show lldp neighbors) + + # We can't assume remote_chassis_id or remote_port are MAC Addresses + # See IEEE 802.1AB-2005 and rfc2922, specifically PtopoChassisId if not hostname: try: hostname = napalm.base.helpers.mac( @@ -996,10 +997,12 @@ def get_lldp_neighbors(self): except AddrFormatError: hostname = lldp_entry["remote_chassis_id"] - try: - port = napalm.base.helpers.mac(port) - except AddrFormatError: - pass + # If port is a mac-address, normalize it. + try: + port = napalm.base.helpers.mac(port) + except AddrFormatError: + pass + lldp_dict = {"port": port, "hostname": hostname} lldp[intf_name].append(lldp_dict) From 6202302ad6928ab9433b17ba02e7145821077394 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Thu, 16 Feb 2023 12:23:16 -0800 Subject: [PATCH 3/4] Fix bug with incorrect port conversion to mac address --- napalm/ios/ios.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 9bfd1d723..9bd385ca6 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -998,10 +998,12 @@ def get_lldp_neighbors(self): hostname = lldp_entry["remote_chassis_id"] # If port is a mac-address, normalize it. - try: - port = napalm.base.helpers.mac(port) - except AddrFormatError: - pass + # The MAC helper library will normalize "15" to "00:00:00:00:00:0F" + if port.count(":") == 5 or port.count("-") == 5 or port.count(".") == 2: + try: + port = napalm.base.helpers.mac(port) + except AddrFormatError: + pass lldp_dict = {"port": port, "hostname": hostname} lldp[intf_name].append(lldp_dict) From 041c7a228b04153b9e97e2f36b2d83a7e295e6a0 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Thu, 16 Feb 2023 12:25:20 -0800 Subject: [PATCH 4/4] Linter --- napalm/ios/ios.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 9bd385ca6..6d6f8e540 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -998,7 +998,7 @@ def get_lldp_neighbors(self): hostname = lldp_entry["remote_chassis_id"] # If port is a mac-address, normalize it. - # The MAC helper library will normalize "15" to "00:00:00:00:00:0F" + # The MAC helper library will normalize "15" to "00:00:00:00:00:0F" if port.count(":") == 5 or port.count("-") == 5 or port.count(".") == 2: try: port = napalm.base.helpers.mac(port)