Repository: napalm-automation/napalm

Issue:
NAPALM w/junos driver fails to properly identify/sanitize the output of `junos_views.junos_ipv6_neighbors_table`
### Description of Issue/Question

NAPALM w/junos driver fails to properly identify/sanitize the output of `junos_views.junos_ipv6_neighbors_table` when the mac address returned by the device is `none`.

```
jsenecal@redacted> show ipv6 neighbors | match "Link|none"
IPv6 Address                            Linklayer Address  State       Exp   Rtr  Secure  Interface
redacted::3                             none               unreachable  2    no   no      ae0.3
redacted::4                             none               unreachable  4    no   no      ae0.3
redacted::44                            none               unreachable  5    no   no      ae0.20
redacted::66                            none               unreachable  1    no   no      ae0.451
redacted::81                            none               incomplete  1     no   no      ae0.60
redacted::91                            none               unreachable  4    no   no      ae0.126
redacted::136                           none               unreachable  5    no   no      ae0.223
redacted:1:7::119                       none               incomplete  1     no   no      ae0.59
redacted:1:143::2                       none               unreachable  2    no   no      ae0.143
```

### Did you follow the steps from https://github.com/napalm-automation/napalm#faq

- [x] Yes
- [ ] No


### Setup

### napalm version
(Paste verbatim output from `pip freeze | grep napalm` between quotes below)

```
napalm==4.1.0
```

### Network operating system version
(Paste verbatim output from `show version` - or equivalent - between quotes below)

```
show version
Hostname: redacted
Model: mx960
Junos: 20.2R3-S4.7
JUNOS OS Kernel 64-bit  [20220228.d118be0_builder_stable_11-204ab]
JUNOS OS libs [20220228.d118be0_builder_stable_11-204ab]
JUNOS OS runtime [20220228.d118be0_builder_stable_11-204ab]
JUNOS OS time zone information [20220228.d118be0_builder_stable_11-204ab]
JUNOS network stack and utilities [20220329.220026_builder_junos_202_r3_s4]
JUNOS libs [20220329.220026_builder_junos_202_r3_s4]
JUNOS OS libs compat32 [20220228.d118be0_builder_stable_11-204ab]
JUNOS OS 32-bit compatibility [20220228.d118be0_builder_stable_11-204ab]
JUNOS libs compat32 [20220329.220026_builder_junos_202_r3_s4]
JUNOS runtime [20220329.220026_builder_junos_202_r3_s4]
Junos vmguest package [20220329.220026_builder_junos_202_r3_s4]
JUNOS sflow mx [20220329.220026_builder_junos_202_r3_s4]
JUNOS py extensions2 [20220329.220026_builder_junos_202_r3_s4]
JUNOS py extensions [20220329.220026_builder_junos_202_r3_s4]
JUNOS py base2 [20220329.220026_builder_junos_202_r3_s4]
JUNOS py base [20220329.220026_builder_junos_202_r3_s4]
JUNOS OS vmguest [20220228.d118be0_builder_stable_11-204ab]
JUNOS OS crypto [20220228.d118be0_builder_stable_11-204ab]
JUNOS OS boot-ve files [20220228.d118be0_builder_stable_11-204ab]
JUNOS na telemetry [20.2R3-S4.7]
JUNOS Security Intelligence [20220329.220026_builder_junos_202_r3_s4]
JUNOS mx libs compat32 [20220329.220026_builder_junos_202_r3_s4]
JUNOS mx runtime [20220329.220026_builder_junos_202_r3_s4]
JUNOS RPD Telemetry Application [20.2R3-S4.7]
Redis [20220329.220026_builder_junos_202_r3_s4]
JUNOS common platform support [20220329.220026_builder_junos_202_r3_s4]
JUNOS Openconfig [20.2R3-S4.7]
JUNOS mtx network modules [20220329.220026_builder_junos_202_r3_s4]
JUNOS modules [20220329.220026_builder_junos_202_r3_s4]
JUNOS mx modules [20220329.220026_builder_junos_202_r3_s4]
JUNOS mx libs [20220329.220026_builder_junos_202_r3_s4]
JUNOS SQL Sync Daemon [20220329.220026_builder_junos_202_r3_s4]
JUNOS mtx Data Plane Crypto Support [20220329.220026_builder_junos_202_r3_s4]
JUNOS daemons [20220329.220026_builder_junos_202_r3_s4]
JUNOS mx daemons [20220329.220026_builder_junos_202_r3_s4]
JUNOS appidd-mx application-identification daemon [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services URL Filter package [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services TLB Service PIC package [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services Telemetry [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services TCP-LOG [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services SSL [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services SOFTWIRE [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services Stateful Firewall [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services RTCOM [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services RPM [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services PCEF package [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services NAT [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services Mobile Subscriber Service Container package [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services MobileNext Software package [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services Logging Report Framework package [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services LL-PDF Container package [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services Jflow Container package [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services Deep Packet Inspection package [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services IPSec [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services IDS [20220329.220026_builder_junos_202_r3_s4]
JUNOS IDP Services [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services HTTP Content Management package [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services Crypto [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services Captive Portal and Content Delivery Container package [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services COS [20220329.220026_builder_junos_202_r3_s4]
JUNOS AppId Services [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services Application Level Gateways [20220329.220026_builder_junos_202_r3_s4]
JUNOS Services AACL Container package [20220329.220026_builder_junos_202_r3_s4]
JUNOS SDN Software Suite [20220329.220026_builder_junos_202_r3_s4]
JUNOS Extension Toolkit [20220329.220026_builder_junos_202_r3_s4]
JUNOS Packet Forwarding Engine Support (wrlinux9) [20220329.220026_builder_junos_202_r3_s4]
JUNOS Packet Forwarding Engine Support (MX/EX92XX Common) [20220329.220026_builder_junos_202_r3_s4]
JUNOS Packet Forwarding Engine Support (M/T Common) [20220329.220026_builder_junos_202_r3_s4]
JUNOS Packet Forwarding Engine Support (aft) [20220329.220026_builder_junos_202_r3_s4]
JUNOS Packet Forwarding Engine Support (MX Common) [20220329.220026_builder_junos_202_r3_s4]
JUNOS Juniper Malware Removal Tool (JMRT) [1.0.0+20220329.220026_builder_junos_202_r3_s4]
JUNOS J-Insight [20220329.220026_builder_junos_202_r3_s4]
JUNOS jfirmware [20220329.220026_builder_junos_202_r3_s4]
JUNOS Online Documentation [20220329.220026_builder_junos_202_r3_s4]
JUNOS jail runtime [20220228.d118be0_builder_stable_11-204ab]
```

### Steps to Reproduce the Issue

```python
from napalm import get_network_driver
from rich import print

driver = get_network_driver("junos")

optional_args = {"port": 22, "config_lock": False, "ssh_config_file": "~/.ssh/config"}

device = driver("redacted", "jsenecal", "Juniper!1", optional_args=optional_args)
device.open()
v6_neighbors = device.get_ipv6_neighbors_table()

print(v6_neighbors)
device.close()
```

### Error Traceback
(Paste the complete traceback of the exception between quotes below)

```
Traceback (most recent call last):
  File "/home/jsenecal/Code/nornir-automation/napalm_get_ndb.py", line 10, in <module>
    v6_neighbors = device.get_ipv6_neighbors_table()
  File "/home/jsenecal/Code/nornir-automation/.env/lib/python3.10/site-packages/napalm/junos/junos.py", line 1641, in get_ipv6_neighbors_table
    ipv6_entry["mac"] = napalm.base.helpers.mac(ipv6_entry.get("mac"))
  File "/home/jsenecal/Code/nornir-automation/.env/lib/python3.10/site-packages/napalm/base/helpers.py", line 521, in mac
    return str(EUI(raw, dialect=_MACFormat))
  File "/home/jsenecal/Code/nornir-automation/.env/lib/python3.10/site-packages/netaddr/eui/__init__.py", line 389, in __init__
    self.value = addr
  File "/home/jsenecal/Code/nornir-automation/.env/lib/python3.10/site-packages/netaddr/eui/__init__.py", line 438, in _set_value
    raise AddrFormatError('failed to detect EUI version: %r'
netaddr.core.AddrFormatError: failed to detect EUI version: 'none'
```



Discussion:
I can submit a PR if we indentify what we want to do with this, aka skip the entry/return `None`/"" etc.
~~Probably related: #1767~~

actually not related, still using `netaddr`
Initial proposal for ipv6 neighbors: https://github.com/napalm-automation/napalm-base/pull/311
Base tests for IOS show incomplete entries: https://github.com/napalm-automation/napalm/blob/b90f184177c773da4cb650e9394d80c5f620beed/test/ios/mocked_data/test_get_ipv6_neighbors_table/normal/expected_result.json#L31-L35

Recommend explicitly testing state, only attempting to resolve/normalize MAC address when in a state where it would be present (REACH, STALE, DELAY, ?) 
So we could just catch the exception thrown in by netaddr and return `""`
I feel that an approach like that (purposely putting bad data in and catching an exception) may hide other issues that may also raise that same exception type -- explicitly bypassing the call to netaddr based on the output from the device would be safer, I think.
I submitted a pr in that direction - hope this helps :)

Resolving patch:
diff --git a/napalm/junos/junos.py b/napalm/junos/junos.py
--- a/napalm/junos/junos.py
+++ b/napalm/junos/junos.py
@@ -1638,7 +1638,11 @@ def get_ipv6_neighbors_table(self):
 
         for ipv6_table_entry in ipv6_neighbors_table_items:
             ipv6_entry = {elem[0]: elem[1] for elem in ipv6_table_entry[1]}
-            ipv6_entry["mac"] = napalm.base.helpers.mac(ipv6_entry.get("mac"))
+            ipv6_entry["mac"] = (
+                ""
+                if ipv6_entry.get("mac") == "none"
+                else napalm.base.helpers.mac(ipv6_entry.get("mac"))
+            )
             ipv6_entry["ip"] = napalm.base.helpers.ip(ipv6_entry.get("ip"))
             ipv6_neighbors_table.append(ipv6_entry)
 


Test patch:
diff --git a/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/expected_result.json b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/expected_result.json
new file mode 100644
--- /dev/null
+++ b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/expected_result.json
@@ -0,0 +1,10 @@
+[
+    {
+        "interface": "ae0.3",
+        "ip": "2001:db8::3",
+        "mac": "",
+        "age": 3.0,
+        "state": "unreachable"
+    }
+]
+
diff --git a/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/get-ipv6-nd-information.xml b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/get-ipv6-nd-information.xml
new file mode 100644
--- /dev/null
+++ b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/get-ipv6-nd-information.xml
@@ -0,0 +1,13 @@
+<ipv6-nd-information>
+    <ipv6-nd-entry>
+        <ipv6-nd-neighbor-address>2001:0DB8::3</ipv6-nd-neighbor-address>
+        <ipv6-nd-neighbor-l2-address>none</ipv6-nd-neighbor-l2-address>
+        <ipv6-nd-state>unreachable</ipv6-nd-state>
+        <ipv6-nd-expire>3</ipv6-nd-expire>
+        <ipv6-nd-isrouter>no</ipv6-nd-isrouter>
+        <ipv6-nd-issecure>no</ipv6-nd-issecure>
+        <ipv6-nd-interface-name>ae0.3</ipv6-nd-interface-name>
+    </ipv6-nd-entry>
+    <ipv6-nd-total>1</ipv6-nd-total>
+</ipv6-nd-information>
+