7xcmUEZ1audvr3U5QVqiyYG6nyVOdWdrVJQ3UyGVsnjAYYU0DOoxC CeBFgcHbtNWdz5vNu2UHKvrrzArd+yGroqtIeEiPromH+XiDqf9EkD8EgAptsyi+2Mx+3k /nBtvFT+uVOXzT8mC69zL0Eq8eEzhElF6Kk6VinJZ2hX5wtjLqpyU2iw1AI506dNxDlVwi WQFWP62oE//bkxVByEdJT1R3UONTVLM1/f4XN71y6UFL+H/zY1nGm2hxuyDPgSZ55EDAbI +MFGRfsySODGa6gyJ9QcmehGP9SC0UoLWMyIyp9GTzZdJpYObCgXdgevG1YWUA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1773083161; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=gx4tWZeKtVZygXhoN8cJQ1ogN5wWq7JXOPDeXjL2BwM=; b=NWxzc62m7A+zMpEA3doPIH9LCRhkMDO+lm2dZK7IEMWss4VmXRu1OuXg/Px5y+k1aRrgzC Ysz05cZpChZnkgkXOIj+M9jVAnoOJa6pQlZyYe9SWq7wTrO2iE0auH8/ISfkRa956yQ2HX ozitS6OCKHQ3U8NrBytfN6ZVuTPRr1KGRGGMrQvquy18TfM+OqruqGiLM//pO5kNS1Hjxk aN+WabHyY2pJLVlbKDSDmSVRhx8/9tQt/GsCIEgyoQPTGY4swx8gUq7K3nUxuGeiyW1RbD k8u61/NfsvhkM7KxoyC0gQMMItMiekYy6V4Ztrxm5f46vR5QY7F2DC7blmmdEw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fV6152zk1zfrt for ; Mon, 09 Mar 2026 19:06:01 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 235dd by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 09 Mar 2026 19:05:56 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Pouria Mousavizadeh Tehrani Subject: git: f37fbe30f559 - main - ndp: implement delayed anycast and proxy NA List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: pouria X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: f37fbe30f559acfb269f67d3efe59569878a3ee1 Auto-Submitted: auto-generated Date: Mon, 09 Mar 2026 19:05:56 +0000 Message-Id: <69af1a14.235dd.3027cfe1@gitrepo.freebsd.org> The branch main has been updated by pouria: URL: https://cgit.FreeBSD.org/src/commit/?id=f37fbe30f559acfb269f67d3efe59569878a3ee1 commit f37fbe30f559acfb269f67d3efe59569878a3ee1 Author: Pouria Mousavizadeh Tehrani AuthorDate: 2026-03-09 17:00:15 +0000 Commit: Pouria Mousavizadeh Tehrani CommitDate: 2026-03-09 19:00:49 +0000 ndp: implement delayed anycast and proxy NA Reviewed by: bms Differential Revision: https://reviews.freebsd.org/D55141 --- sys/netinet6/nd6.h | 3 ++ sys/netinet6/nd6_nbr.c | 78 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index eca9f6262568..d9fccce33980 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -155,11 +155,13 @@ struct in6_ndifreq { /* ND6 queue flags */ #define ND6_QUEUE_FLAG_NEWGUA 0x01 /* new global unicast address event */ #define ND6_QUEUE_FLAG_LLADDR 0x02 /* link-layer address change event */ +#define ND6_QUEUE_FLAG_ANYCAST 0x04 /* delay NA for anycast or proxy address */ /* protocol constants */ #define MAX_RTR_SOLICITATION_DELAY 1 /* 1sec */ #define RTR_SOLICITATION_INTERVAL 4 /* 4sec */ #define MAX_RTR_SOLICITATIONS 3 +#define MAX_ANYCAST_DELAY_TIME 1 /* 1sec */ #define ND6_INFINITE_LIFETIME 0xffffffff @@ -373,6 +375,7 @@ void nd6_dad_start(struct ifaddr *, int); void nd6_dad_stop(struct ifaddr *); void nd6_grand_start(struct ifaddr *, uint32_t); void nd6_queue_stop(struct ifaddr *); +void nd6_delayed_na_start(struct ifaddr *, struct in6_addr *, u_int, uint32_t); /* nd6_rtr.c */ void nd6_rs_input(struct mbuf *, int, int); diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 6a1f29c31eed..0a34e0e3628e 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -124,6 +124,7 @@ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_ONLINKNSRFC4861, struct nd_queue { TAILQ_ENTRY(nd_queue) ndq_list; struct ifaddr *ndq_ifa; + struct in6_addr ndq_daddr; uint32_t ndq_flags; struct callout ndq_callout; }; @@ -355,8 +356,17 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) rflag |= ND_NA_FLAG_SOLICITED; } - nd6_na_output_fib(ifp, &saddr6, &taddr6, rflag, tlladdr, - proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m)); + /* + * RFC 4861, anycast or proxy NA sent in response to a NS SHOULD + * be delayed by a random time between 0 and MAX_ANYCAST_DELAY_TIME + * to reduce the probability of network congestion. + */ + if (anycast == 0 && proxy == 0) + nd6_na_output_fib(ifp, &saddr6, &taddr6, rflag, tlladdr, + proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m)); + else + nd6_delayed_na_start(ifa, &saddr6, arc4random() % + (MAX_ANYCAST_DELAY_TIME * hz), ND6_QUEUE_FLAG_ANYCAST); freeit: if (ifa != NULL) ifa_free(ifa); @@ -648,10 +658,6 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *saddr6, * * Based on RFC 2461 * Based on RFC 2462 (duplicate address detection) - * - * the following items are not implemented yet: - * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) - * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) */ void nd6_na_input(struct mbuf *m, int off, int icmp6len) @@ -966,10 +972,6 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * * Based on RFC 2461 * - * the following items are not implemented yet: - * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) - * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) - * * tlladdr: * - 0x01 if include target link-layer address * - 0x02 if target address is CARP MASTER @@ -1669,7 +1671,6 @@ nd6_queue_timer(void *arg) struct ifaddr *ifa = ndq->ndq_ifa; struct ifnet *ifp = ifa->ifa_ifp; struct in6_ifextra *ext = ifp->if_inet6; - struct in6_addr taddr6 = IN6ADDR_ANY_INIT; struct epoch_tracker et; int delay, tlladdr; u_long flags; @@ -1685,12 +1686,10 @@ nd6_queue_timer(void *arg) flags &= ~ND_NA_FLAG_ROUTER; /* - * RFC 9131 Section 6.1.2: if new global address added, - * use the all-routers multicast address. - * If the address is preferred, then the Override flag SHOULD NOT be set. + * RFC 9131 Section 6.1.2: If the address is preferred, + * then the Override flag SHOULD NOT be set. */ if ((ndq->ndq_flags & ND6_QUEUE_FLAG_NEWGUA) != 0) { - taddr6 = in6addr_linklocal_allrouters; /* * XXX: If the address is in the Optimistic state, * then the Override flag MUST NOT be set. @@ -1700,29 +1699,31 @@ nd6_queue_timer(void *arg) flags |= ND_NA_FLAG_OVERRIDE; } /* - * RFC 4891 Section 7.2.6: if link-layer address changed, - * use the all-nodes multicast address. + * RFC 4861 Section 7.2.6: if link-layer address changed, * The Override flag MAY be set to either zero or one. */ - if ((ndq->ndq_flags & ND6_QUEUE_FLAG_LLADDR) != 0) { - taddr6 = in6addr_linklocal_allnodes; + if ((ndq->ndq_flags & ND6_QUEUE_FLAG_LLADDR) != 0) flags |= ND_NA_FLAG_OVERRIDE; - } + /* anycast advertisement delay rule (RFC 4861 7.2.7, SHOULD) */ + if ((ndq->ndq_flags & ND6_QUEUE_FLAG_ANYCAST) != 0) + flags |= ND_NA_FLAG_SOLICITED; /* Wait at least a RetransTimer before removing from queue */ delay = ext->nd_retrans * hz / 1000; callout_reset(&ndq->ndq_callout, delay, nd6_queue_rel, ndq); IF_ADDR_WUNLOCK(ifp); - if (__predict_true(in6_setscope(&taddr6, ifp, NULL) == 0)) - nd6_na_output_fib(ifp, &taddr6, IFA_IN6(ifa), flags, tlladdr, NULL, ifp->if_fib); + if (__predict_true(in6_setscope(&ndq->ndq_daddr, ifp, NULL) == 0)) + nd6_na_output_fib(ifp, &ndq->ndq_daddr, IFA_IN6(ifa), flags, tlladdr, + NULL, ifp->if_fib); NET_EPOCH_EXIT(et); CURVNET_RESTORE(); } static void -nd6_queue_add(struct ifaddr *ifa, int delay, uint32_t flags) +nd6_queue_add(struct ifaddr *ifa, struct in6_addr *daddr, + int delay, uint32_t flags) { struct nd_queue *ndq; struct ifnet *ifp = ifa->ifa_ifp; @@ -1749,6 +1750,7 @@ nd6_queue_add(struct ifaddr *ifa, int delay, uint32_t flags) ndq->ndq_ifa = ifa; ifa_ref(ndq->ndq_ifa); + memcpy(&ndq->ndq_daddr, daddr, sizeof(struct in6_addr)); ndq->ndq_flags = flags; TAILQ_INSERT_TAIL(&ext->nd_queue, ndq, ndq_list); @@ -1765,6 +1767,7 @@ nd6_grand_start(struct ifaddr *ifa, uint32_t flags) { struct nd_queue *ndq; struct in6_ifextra *ext = ifa->ifa_ifp->if_inet6; + struct in6_addr daddr = IN6ADDR_ANY_INIT; int delay, count = 0; NET_EPOCH_ASSERT(); @@ -1794,8 +1797,22 @@ nd6_grand_start(struct ifaddr *ifa, uint32_t flags) return; } + /* + * RFC 9131 Section 6.1.2: if new global address added, + * use the all-routers multicast address. + */ + if ((flags & ND6_QUEUE_FLAG_NEWGUA) != 0) + daddr = in6addr_linklocal_allrouters; + + /* + * RFC 4861 Section 7.2.6: if link-layer address changed, + * use the all-nodes multicast address. + */ + if ((flags & ND6_QUEUE_FLAG_LLADDR) != 0) + daddr = in6addr_linklocal_allnodes; + delay = ext->nd_retrans * hz / 1000; - nd6_queue_add(ifa, count * delay, flags); + nd6_queue_add(ifa, &daddr, count * delay, flags); } /* @@ -1817,3 +1834,16 @@ nd6_queue_stop(struct ifaddr *ifa) } IF_ADDR_WUNLOCK(ifa->ifa_ifp); } + +/* + * Send delayed NA for specified address. + * Called by nd6_ns_input for anycast or proxy NA + */ +void +nd6_delayed_na_start(struct ifaddr *ifa, struct in6_addr *daddr, + u_int delay, uint32_t flags) +{ + + NET_EPOCH_ASSERT(); + nd6_queue_add(ifa, daddr, delay, flags); +}