Re: [RFC net-next] ipv6: update NUD_FAILED neighbors from NA messages
From: Ido Schimmel
Date: Tue Aug 25 2026 - 07:57:28 EST
On Thu, Aug 13, 2026 at 11:33:44PM +0000, Lawrence Lee wrote:
> I noticed an inconsistency between IPv4 and IPv6 in how the kernel handles
> neighbor advertisements/ARP replies for NUD_FAILED neighbor entries
> and would like some guidance/input from maintainers.
>
> For an existing IPv4 neighbor that is in the NUD_FAILED state, receiving an
> ARP reply for the neighbor IP will update the entry in the kernel to
> either NUD_STALE or NUD_REACHABLE depending on if the reply is unicast or
> broadcast.
>
> For an existing IPv6 neighbor that is in the NUD_FAILED state, receiving a
> neighbor advertisement (NA) for the neighbor IP does nothing as
> ndisc_recv_na() explicitly ignores NUD_FAILED neighbor entries:
>
> if (READ_ONCE(neigh->nud_state) & NUD_FAILED)
> goto out;
>
> This check was added by commit titled "[IPV6] Don't update FAILED
> entries on receipt of NAs." (Hideaki Yoshifuji, 2005-01-16; pre-git, in
> mainline since v2.6.12-rc2) with the justification "As NAs do not create
> new entries (RFC2461 7.2.5), NA should not change state of FAILED entries."
>
> However, RFC9131 introduced a method for NAs to create new neighbor entries
> (implemented as `accept_unsolicited_na` and later renamed to
> `accept_untracked_na`), which means the original justification for ignoring
> NAs for NUD_FAILED neighbor entries is no longer 100% correct. I think to
> remain logically consistent, it makes sense to allow NAs to update
> NUD_FAILED entries anytime we allow creating new entries with
> `accept_untracked_na`.
>
> I realize that RFC9131 section 4.2 states the following:
>
> ... routers create a new Neighbor Cache entry upon
> receiving an unsolicited Neighbor Advertisement for an address that
> does not already have a Neighbor Cache entry. These changes do not
> modify the router behavior specified in [RFC4861] for the scenario
> when the corresponding Neighbor Cache entry already exists.
>
> However, I would argue that since NUD_FAILED is purely a kernel construct
> and has no equivalent state defined in RFC4861 section 7.3.2, a neighbor in
> state NUD_FAILED does not actually have a valid Neighbor Cache entry as
> defined by RFC4861 and should be treated as if the neighbor entry doesn't
> exist; therefore NUD_FAILED neighbors does fall within the scope of
> RFC9131.
>
> The motivation for this question comes from my work on SONiC, a network OS
> which is built on top of Debian and runs on switching hardware. We have
> encountered an issue where the switch receives traffic for an IPv6 neighbor
> before that neighbor is resolvable, which leads to the kernel neighbor
> being set to NUD_FAILED. When the IPv6 neighbor becomes ready to receive
> traffic, it sends an unsolicited NA to the switch which gets ignored
> because the kernel neighbor is NUD_FAILED. Subsequent traffic destined to
> this neighbor stays entirely within the switch ASIC and isn't visible to
> the kernel, so there's no stimulus for the kernel to send neighbor
> solicitations; as a result, the neighbor entry stays unresolved and traffic
> to the neighbor is dropped.
Why "Subsequent traffic destined to this neighbor stays entirely within
the switch ASIC and isn't visible to the kernel"? If the neighbour is
unresolved and you're relying on the kernel to perform the resolution,
then you should trap these packets and inject them to the kernel's Rx
path. This should provide "stimulus for the kernel to send neighbor
solicitations".
If you can't do this for some reason (please explain why), then you can
either:
1. Trigger the resolution from user space via NTF_USE.
2. Configure offloaded neighbours with NTF_EXT_MANAGED so that the
kernel will periodically probe them and keep them reachable when
possible.
>
> The main questions I'd like to pose:
>
> 1. When RFC9131 was implemented (`accept_untracked_na`), was an intentional
> choice made to not update the handling of NUD_FAILED neighbors? I
> searched through the discussions for all three commits relevant to this
> feature but did not find any mention of NUD_FAILED handling:
> commit f9a2fb73318e ("net/ipv6: Introduce accept_unsolicited_na knob to implement router-side changes for RFC9131")
> commit 3e0b8f529c10 ("net/ipv6: Expand and rename accept_unsolicited_na to accept_untracked_na")
> commit aaa5f515b16b ("net: ipv6: new accept_untracked_na option to accept na only if in-network")
AFAIK it wasn't an intentional decision to not update NUD_FAILED
neighbours.
>
> 2. Should unsolicited NAs be allowed to update NUD_FAILED neighbors when
> `accept_untracked_na` is enabled (this would align with existing
> IPv4/ARP behavior that allows ARP replies to update NUD_FAILED
> neighbors).
Looks fine, but I suggest first evaluating the alternatives above. They
don't require any kernel changes. Besides, dropping traffic to an
unresolved neighbour instead of trapping to the CPU doesn't make a lot
of sense.
Also, note that "align with existing IPv4/ARP behavior" is not accurate:
arp_process() updates an existing NUD_FAILED entry unconditionally and
it can transition from NUD_FAILED to NUD_REACHABLE. So, your patch is
strictly more restrictive than IPv4 rather than aligned with it.