IPv6 Neighbor Discovery Troubleshooting: Stuck at Link-Local

An IPv6 host with only an FE80:: address is waiting on a Router Advertisement that never came. Captured on CML with IOS XE 17.18.2: the five NDP messages, the neighbor cache states, the A/M/O flags in a real RA, and why filtering ICMPv6 unplugs a segment.

Terminal showing an IPv6 interface with only a link-local address and an empty show ipv6 routers

An IPv6 host sitting on nothing but an FE80:: address is not broken the way an IPv4 host with no DHCP lease is broken. There is no server to check, no scope, no relay to blame. In IPv6 the address and the default gateway both arrive in a Router Advertisement, an ICMPv6 packet sent by a router on the segment, and if that packet is not sent or not delivered, the host stays link-local forever and tells you almost nothing about why.

Everything below came off a two-router CML lab on Cisco IOS XE 17.18.2 (iol-xe nodes): R1 with ipv6 unicast-routing and a /64 on Ethernet0/0, R2 running ipv6 address autoconfig, and the break baked into R1's startup config as ipv6 nd ra suppress all. For the surrounding context, the IPv6 addressing, routing and troubleshooting guide maps the cluster in reading order.

Short version: if the host has no global address, stop looking at the host. show ipv6 routers on the client answers the question in one line, and the answer is nearly always on the router side.

The Five Messages Neighbor Discovery Runs On

Neighbor Discovery (RFC 4861) is not a protocol sitting next to IPv6, it is part of how IPv6 works. It absorbs jobs that IPv4 split across ARP, ICMP redirects, router discovery and DHCP, using five ICMPv6 message types over link-local addresses and multicast.

Router Solicitation (RS)
ICMPv6 type133
Sent byHosts, to FF02::2
JobAsk for an RA now
Router Advertisement (RA)
ICMPv6 type134
Sent byRouters, to FF02::1
JobPrefix, flags, MTU, gateway
Neighbor Solicitation (NS)
ICMPv6 type135
Sent byAny node
JobResolve L2, probe, run DAD
Neighbor Advertisement (NA)
ICMPv6 type136
Sent byAny node
JobAnswer an NS, or announce
Redirect
ICMPv6 type137
Sent byRouters, to the host
JobUse a better first hop

The split that matters is RS/RA versus NS/NA. RS and RA are configuration: what prefix am I on, who is my default router. NS and NA are reachability: what MAC sits behind this address, and is it still answering. Different failures, different commands, so decide which half you are in first.

What This Was Captured On

PlatformCML, 2 x iol-xe nodes, Cisco IOS XE 17.18.2
LinkR1 Et0/0 to R2 Et0/0, back to back
R1 (the router)ipv6 unicast-routing, 2001:DB8:12::1/64
R2 (the client)ipv6 enable plus ipv6 address autoconfig
The breakR1 boots with ipv6 nd ra suppress all
Also present10.0.12.0/24 IPv4, dual-stack (see Gotchas)

R2 two minutes after boot, autoconfig configured, R1 silent:

R2# show ipv6 interface brief
Ethernet0/0            [up/up]
    FE80::A8BB:CCFF:FE00:D900

Up/up, IPv6 enabled, link-local present (which proves the stack is running and DAD passed on it). What is missing is any address from 2001:DB8:12::/64. The detail says why:

R2# show ipv6 interface Ethernet0/0
Ethernet0/0 is up, line protocol is up
  IPv6 is enabled, link-local address is FE80::A8BB:CCFF:FE00:D900
  Stateless address autoconfig enabled
  No global unicast address is configured
  Joined group address(es):
    FF02::1        (all-nodes)
    FF02::2        (all-routers... solicited)
    FF02::1:FF00:D900   (solicited-node multicast for DAD/ND)
  ND DAD is enabled, number of DAD attempts: 1
  Hosts use stateless autoconfig for addresses.

"Stateless address autoconfig enabled" plus "No global unicast address is configured" is the diagnostic pair: the client is doing its job, waiting for a prefix that never arrives. Note FF02::1:FF00:D900, the solicited-node group derived from the low 24 bits of its own address, which is how an NS reaches one node instead of shouting at the whole segment the way ARP does.

show ipv6 routers Answers It in One Line

Run this first on any host stuck at link-local. It lists the routers whose RAs this node actually received, and what those RAs said:

R2# show ipv6 routers
R2#

Nothing. No RA has been heard on this segment, from anybody, ever. That one empty result moves the investigation off the client and onto the router, in about three seconds. On Linux the equivalent is rdisc6 eth0 or a capture filtered on icmp6 and ip6[40] == 134.

Know the timing before you call it empty. A host sends an RS the moment its interface comes up and a router answers within a second or so; after that IOS sends unsolicited RAs every 200 seconds. Empty a full minute after link-up is a real finding, not impatience. To watch the exchange live, debug ipv6 nd shows RS, RA, NS and NA in both directions (lab only).

Root Cause: The Router Is Not Advertising

  • No ipv6 unicast-routing. The classic. The box accepts an IPv6 address, answers pings on it and looks fully configured, but until unicast routing is on globally it is a host: no RAs, no transit forwarding. Nothing in show ipv6 interface flags it, which is why people burn an hour on the client.
  • RAs suppressed on the interface. ipv6 nd ra suppress all is legitimate on links where you do not want hosts autoconfiguring, and it is what this lab boots with. It also arrives via a template and gets forgotten.
  • The RA is sent but not delivered. An ACL, an RA Guard policy on the access switch, or an SVI in the wrong VLAN. The router thinks it did its part and the counters agree.
  • The RA arrives but says the wrong thing. That is the flags, below.

The fix here was one line on R1, no ipv6 nd ra suppress all. Within a minute, R2, with no change to its own config:

R2# show ipv6 interface brief
Ethernet0/0            [up/up]
    FE80::A8BB:CCFF:FE00:D900
    2001:DB8:12:0:A8BB:CCFF:FE00:D900        <-- SLAAC global address

That is SLAAC in one screen. The client was never misconfigured; it got a routable address the moment a router started telling it what prefix it was on.

Reading the RA: the A, M and O Flags

R2# show ipv6 routers
Router FE80::A8BB:CCFF:FE00:D800 on Ethernet0/0, last update 0 min
  Hops 64, Lifetime 1800 sec, AddrFlag=0, OtherFlag=0, MTU=1500
  HomeAgentFlag=0, Preference=Medium
  Reachable time 0 (unspecified), Retransmit time 0 (unspecified)
  Prefix 2001:DB8:12::/64 onlink autoconfig
    Valid lifetime 2592000, preferred lifetime 604800

Three fields decide how a host gets addressed. AddrFlag is the M (Managed) bit: 1 means "get your address from DHCPv6". OtherFlag is O: 1 means "the address is your problem, but take DNS and other options from DHCPv6". autoconfig on the prefix line is the A flag in the Prefix Information option, the permission to build an address from that prefix.

Both flags are 0 here, so this is pure SLAAC with no DHCPv6 involved. The failure mode is a mismatch between what the router advertises and what the client can act on. M=1 with no DHCPv6 server or relay anywhere leaves hosts with no address at all. A prefix with A cleared and M cleared says "this prefix is on-link, but do not build an address from it", a legal RA that produces a host with a gateway and no source address. If you are choosing between the models, the difference between stateful and stateless DHCPv6 is exactly those two bits. One hard constraint: SLAAC only works with a /64, because the interface identifier is defined as 64 bits.

How the Address Got Built, and DAD

The host bits R2 chose, A8BB:CCFF:FE00:D900, are the same host bits as its link-local. That is a modified EUI-64 identifier built from the MAC aabb.cc00.d900: split the MAC in half, insert FFFE, flip the seventh bit of the first byte (which is why AA becomes A8). If that transform is still fuzzy, building an EUI-64 interface ID by hand makes it stick. Real hosts no longer do this: Windows and current Linux use opaque per-prefix identifiers (RFC 7217) plus rotating temporary addresses, so expect several global addresses that do not correlate to a MAC.

Before any address is usable it must pass Duplicate Address Detection: the node sends an NS for its own tentative address, sourced from ::, and if anyone answers with an NA, IOS marks the address DUPLICATE and refuses to use it. A DAD failure on the link-local address disables IPv6 on that interface entirely, which is a spectacular outage to get from one cloned VM. Note number of DAD attempts: 1 above; where a port takes a moment to start forwarding, one attempt can finish before anyone could have answered, so a real duplicate slips through. ipv6 nd dad attempts 3 is cheap insurance.

The RA also installs routing state:

R2# show ipv6 route
NDp 2001:DB8:12::/64 [2/0]
     via Ethernet0/0, directly connected
L   2001:DB8:12:0:A8BB:CCFF:FE00:D900/128 [0/0]
     via Ethernet0/0, receive

NDp is the ND-prefix route, learned from the RA rather than from a configured address, and it is a useful tell: NDp routes on a router you did not expect to be autoconfiguring mean an interface is taking directions from whatever else is on that segment.

The Neighbor Cache and Its Five States

Once addressing works, the other half of ND takes over: mapping IPv6 addresses to MACs. show ipv6 neighbors is the ARP table equivalent, except it exposes a state machine per entry.

INCMPNS sent, no NA back yet. Stuck here means nothing is answering.
REACHConfirmed reachable in the last 30 seconds. The only state that means good now.
STALEKnown but unconfirmed, because nothing has needed it. Normal, not a fault.
DELAYTraffic just used a STALE entry. Waiting a few seconds for upper-layer proof.
PROBESending unicast NS on a timer. Repeated PROBE then deletion means it is gone.

Most entries in a healthy cache are STALE and that is nothing to fix, because IPv6 confirms reachability from upper-layer progress rather than by re-resolving on a timer. An entry parked in INCMP is an incomplete ARP entry by another name: your solicitation goes out, nothing comes back. Check the L2 path, then check what is filtering ICMPv6.

Do Not Filter ICMPv6 the Way You Filtered ICMP

Blocking ICMP inbound on IPv4 is rude and breaks Path MTU Discovery, but the network keeps working. Do the same to ICMPv6 and you have not hardened the segment, you have unplugged it. Address resolution is ICMPv6. Router discovery is ICMPv6. DAD is ICMPv6. PMTUD is mandatory in IPv6 because routers never fragment, so dropping Packet Too Big (type 2) gives you the classic failure where pings work and TLS handshakes hang.

A blanket deny icmp any any in an IPv6 ACL stops hosts getting addresses, stops them resolving each other and stops large flows completing, all at once, and it looks entirely reasonable to whoever wrote it. Permit types 133 to 137, plus 2, 1, 3 and 4, before the deny. The same discipline applied more broadly is how ACLs on router interfaces actually treat protocol traffic. Routing protocols get caught by this too: OSPFv3 peers over link-local addresses, so a filter that interferes with ND tends to take the IGP with it.

An Address but No Default Gateway

The other failure shape is a host that autoconfigures perfectly and still cannot reach anything off-link. The gateway comes from exactly one place: the source of an RA whose Router Lifetime is non-zero. Above that is Lifetime 1800 sec, so R1's link-local FE80::A8BB:CCFF:FE00:D800 becomes R2's default router. Three things break it:

  • Router Lifetime 0. ipv6 nd ra lifetime 0 means "here is prefix information, but do not use me as a default router". Legitimate in some designs, catastrophic if it is the only router on the link.
  • DHCPv6 without RAs. DHCPv6 has no default gateway option. None. A stateful server hands out an address and DNS and still leaves the host with no route off-link, because that only ever comes from an RA.
  • RAs filtered after the fact. RA Guard or a later policy lets the first RA through and drops the refreshes. The lifetime expires, the default route vanishes, and off-link connectivity dies 30 minutes after nobody changed anything.

show ipv6 routers plus the default route in show ipv6 route separate them. Router listed with a non-zero lifetime but no default route means look at the host; router not listed at all puts you back on the RA problem.

Gotchas

  • An empty show ipv6 neighbors is not a failure. In this lab it stayed empty after SLAAC completed, because no data traffic had been exchanged. NS/NA resolution happens on demand, so ping the neighbor first, then read the cache.
  • Link-local presence proves nothing about routing. Every IPv6-enabled interface has one, with or without ipv6 unicast-routing, with or without an RA. It only says the stack is up and DAD passed.
  • An IPv6-only startup config can fail to load on iol-xe. A day-0 config with no IPv4 anywhere fell into the setup dialog and never applied; adding an IPv4 address per interface fixed it. If a CML node boots empty, check that before debugging IPv6.
  • RA suppression is per-interface, unicast-routing is global. Identical symptom from the client, two different places to fix, so check both.

Key Takeaways

  • IPv6 hosts get their prefix and their default gateway from Router Advertisements. No RA, no global address, whatever the host is configured to do.
  • show ipv6 routers is the first command: empty means no RA was heard and the problem is upstream, populated means read the flags.
  • AddrFlag is M, OtherFlag is O, and the prefix line's autoconfig is A. Those three bits decide SLAAC, DHCPv6, or nothing.
  • Neighbor cache states are a state machine, not a health score. STALE is normal, REACH is confirmed, INCMP means your NS is unanswered.
  • Filtering ICMPv6 wholesale breaks addressing, resolution and PMTUD at once. Permit types 133 to 137 and type 2 before any deny.
  • DHCPv6 never supplies a default gateway, so a stateful deployment still needs a router sending RAs.

Most IPv6 troubleshooting starts and ends at Neighbor Discovery, because addressing, gateway selection, address resolution and duplicate detection all ride the same five ICMPv6 messages. Once you can read an RA, the rest stops being mysterious: what you need to run IPv6 in production covers the addressing, transition and first-hop security material built on top of it.

Read next