From: Lawrence Lee <lfqlee314@gmail.com>
To: David Ahern <dsahern@kernel.org>,
Ido Schimmel <idosch@nvidia.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: Simon Horman <horms@kernel.org>,
Randy Dunlap <rdunlap@infradead.org>,
netdev@vger.kernel.org, Arun Ajith S <aajith@arista.com>,
Roopa Prabhu <roopa@nvidia.com>,
Jaehee Park <jhpark1013@gmail.com>,
Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
Shuah Khan <shuah@kernel.org>,
linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH net-next v3 1/2] ipv6: update NUD_FAILED neighbors from NA messages
Date: Fri, 18 Sep 2026 22:13:23 +0000 [thread overview]
Message-ID: <e5b7a4f8cbd7c436b463b3751bf283ce861fcfaa.1789734885.git.lfqlee314@gmail.com> (raw)
In-Reply-To: <cover.1789734885.git.lfqlee314@gmail.com>
Transition a FAILED neighbor entry to STALE upon receipt of an NA
message on routers when accept_untracked_na is enabled. This extends the
RFC 9131 accept_untracked_na behavior so that FAILED entries are treated
the same as non-existent entries.
RFC 4861 section 7.3.3 says that an entry should be deleted when address
resolution fails. Linux instead retains the entry in NUD_FAILED, so
treating it as untracked is consistent with the protocol model.
Trying to resolve FAILED neighbors via periodic probing (e.g. using
NTF_EXT_MANAGED) is more work compared to this approach which uses
information in NAs that the kernel may already be receiving. Note that
because this behavior in IPv6 is dependent on the accept_untracked_na
sysctl setting, this approach is more conservative than IPv4 which
transitions FAILED neighbors to STALE by default upon receiving GARPs.
Link: https://lore.kernel.org/r/20260813233344.445265-1-lfqlee314@gmail.com
Assisted-by: LLM Sashiko sparse
Signed-off-by: Lawrence Lee <lfqlee314@gmail.com>
---
The existing 6LoWPAN override-only handling also applies to INCOMPLETE
entries and is intentionally left unchanged. The existing
rt6_clean_tohost() source-versus-target behavior applies to all neighbor
states and is also left unchanged.
Documentation/networking/ip-sysctl.rst | 28 ++++++++-------
net/ipv6/ndisc.c | 47 ++++++++++++++------------
2 files changed, 41 insertions(+), 34 deletions(-)
diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
index f7af0286341c..685c84cf543d 100644
--- a/Documentation/networking/ip-sysctl.rst
+++ b/Documentation/networking/ip-sysctl.rst
@@ -3225,18 +3225,19 @@ drop_unsolicited_na - BOOLEAN
Default: 0 (disabled).
accept_untracked_na - INTEGER
- Define behavior for accepting neighbor advertisements from devices that
- are absent in the neighbor cache:
+ Define behavior for accepting neighbor advertisements for IPv6 addresses
+ that are absent from the neighbor cache or whose entries are in FAILED
+ state:
- - 0 - (default) Do not accept unsolicited and untracked neighbor
- advertisements.
+ - 0 - (default) Do not create new neighbor cache entries or update
+ FAILED entries from neighbor advertisements.
- - 1 - Add a new neighbor cache entry in STALE state for routers on
- receiving a neighbor advertisement (either solicited or unsolicited)
- with target link-layer address option specified if no neighbor entry
- is already present for the advertised IPv6 address. Without this knob,
- NAs received for untracked addresses (absent in neighbor cache) are
- silently ignored.
+ - 1 - For routers, add a new neighbor cache entry or update an existing
+ FAILED entry to STALE upon receiving a neighbor advertisement (either
+ solicited or unsolicited) with the target link-layer address option
+ specified. Without this knob, NAs received for untracked addresses
+ (absent from the neighbor cache or in FAILED state) are silently
+ ignored.
This is as per router-side behavior documented in RFC9131.
@@ -3251,9 +3252,10 @@ accept_untracked_na - INTEGER
used in conjunction with the ndisc_notify setting on the host to
satisfy this prerequisite.
- - 2 - Extend option (1) to add a new neighbor cache entry only if the
- source IP address is in the same subnet as an address configured on
- the interface that received the neighbor advertisement.
+ - 2 - Extend option (1) to add a new neighbor cache entry or update a
+ FAILED entry only if the source IP address is in the same subnet as
+ an address configured on the interface that received the neighbor
+ advertisement.
enhanced_dad - BOOLEAN
Include a nonce option in the IPv6 neighbor solicitation messages used for
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 90cd5d852569..12d85d7f8234 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -973,13 +973,13 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
static int accept_untracked_na(struct inet6_dev *idev, struct in6_addr *saddr)
{
switch (READ_ONCE(idev->cnf.accept_untracked_na)) {
- case 0: /* Don't accept untracked na (absent in neighbor cache) */
+ case 0: /* Don't accept untracked NA (absent or FAILED) */
return 0;
- case 1: /* Create new entries from na if currently untracked */
+ case 1: /* Create new or update FAILED entries from NA */
return 1;
- case 2: /* Create new entries from untracked na only if saddr is in the
+ case 2: /* Create new or update FAILED entries only if saddr is in the
* same subnet as an address configured on the interface that
- * received the na
+ * received the NA
*/
return !!ipv6_chk_prefix(saddr, idev->dev);
default:
@@ -1067,34 +1067,39 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
neigh = neigh_lookup(tbl, &msg->target, dev);
/* RFC 9131 updates original Neighbour Discovery RFC 4861.
- * NAs with Target LL Address option without a corresponding
- * entry in the neighbour cache can now create a STALE neighbour
- * cache entry on routers.
+ * NAs with Target LL Address option can now create a STALE neighbor
+ * cache entry on routers if the NA does not have a corresponding entry
+ * in the neighbour cache or has a corresponding FAILED entry.
*
- * entry accept fwding solicited behaviour
- * ------- ------ ------ --------- ----------------------
- * present X X 0 Set state to STALE
- * present X X 1 Set state to REACHABLE
- * absent 0 X X Do nothing
- * absent 1 0 X Do nothing
- * absent 1 1 X Add a new STALE entry
+ * entry accept fwding solicited behaviour
+ * ----------- ------ ------ --------- ----------------------
+ * non-FAILED X X 0 Set state to STALE
+ * non-FAILED X X 1 Set state to REACHABLE
+ * FAILED 0 X X Do nothing
+ * FAILED 1 0 X Do nothing
+ * FAILED 1 1 X Set state to STALE
+ * absent 0 X X Do nothing
+ * absent 1 0 X Do nothing
+ * absent 1 1 X Add a new STALE entry
*
* Note that we don't do a (daddr == all-routers-mcast) check.
*/
new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE;
- if (!neigh && lladdr && idev && READ_ONCE(idev->cnf.forwarding)) {
- if (accept_untracked_na(idev, saddr)) {
- neigh = neigh_create(tbl, &msg->target, dev);
- new_state = NUD_STALE;
+ if (!neigh || (READ_ONCE(neigh->nud_state) & NUD_FAILED)) {
+ if (!lladdr || !idev || !READ_ONCE(idev->cnf.forwarding) ||
+ !accept_untracked_na(idev, saddr)) {
+ if (neigh)
+ neigh_release(neigh);
+ return reason;
}
+ if (!neigh)
+ neigh = neigh_create(tbl, &msg->target, dev);
+ new_state = NUD_STALE;
}
if (neigh && !IS_ERR(neigh)) {
u8 old_flags = neigh->flags;
- if (READ_ONCE(neigh->nud_state) & NUD_FAILED)
- goto out;
-
/*
* Don't update the neighbor cache entry on a proxy NA from
* ourselves because either the proxied node is off link or it
--
2.43.0
next prev parent reply other threads:[~2026-09-18 22:13 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-18 22:13 [PATCH net-next v3 0/2] " Lawrence Lee
2026-09-18 22:13 ` Lawrence Lee [this message]
2026-09-20 8:09 ` [PATCH net-next v3 1/2] " Ido Schimmel
2026-09-18 22:13 ` [PATCH net-next v3 2/2] selftests: net: test untracked NA recovery of FAILED neighbors Lawrence Lee
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e5b7a4f8cbd7c436b463b3751bf283ce861fcfaa.1789734885.git.lfqlee314@gmail.com \
--to=lfqlee314@gmail.com \
--cc=aajith@arista.com \
--cc=corbet@lwn.net \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=jhpark1013@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=rdunlap@infradead.org \
--cc=roopa@nvidia.com \
--cc=shuah@kernel.org \
--cc=skhan@linuxfoundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®