Repository: napalm-automation/napalm
Pull request #1849 (2023-02-16 19:19:50)

Fix ios lldp discovery (rebase)

ktbyers: FYI @CarloMara 
ktbyers: @CarloMara Let me know if you see any issues:

FYI, I moved this port normalization to always happen:

```python
                # If port is a mac-address, normalize it.
                # 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
```

I also had to put the conditional as some port identifiers like "15" would incorrectly try to get converted to MAC addresses.

I didn't see a good reason why the port MAC normalization should only happen in the `if not hostname` case. 

Realistically, the NAPALM `mac` helper function should probably have more logic in it (to avoid incorrect MAC conversions) and my quick check shouldn't be needed.

Patch:
diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py
index 6235f588..6d6f8e54 100644
--- a/napalm/ios/ios.py
+++ b/napalm/ios/ios.py
@@ -44,6 +44,7 @@ from napalm.base.helpers import (
     generate_regex_or,
     sanitize_configs,
 )
+from netaddr.core import AddrFormatError
 from napalm.base.netmiko_helpers import netmiko_args
 
 # Easier to store these as constants
@@ -984,10 +985,26 @@ class IOSDriver(NetworkDriver):
                 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)
+                # 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:
-                    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"]
+
+                # If port is a mac-address, normalize it.
+                # 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)
 


Test patch:
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 00000000..49bc8022
--- /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 00000000..f7074e0d
--- /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 00000000..5908277d
--- /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