From nobody Thu Mar 19 16:22:58 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fc9wL426bz6VbZY for ; Thu, 19 Mar 2026 16:22:58 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fc9wL3F7Zz3bks for ; Thu, 19 Mar 2026 16:22:58 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1773937378; 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=N0iFKP40rOi1v1CbgxLQPxkN2Xr+oE6j4jNjXpensgU=; b=PTKh99XooSvpST8xUIG4HDBtBC3szspsED4uCde6rRhqwY0+Zm2Fa+2eKOL8vbSq1VL0Sd wznXyzA1rHMhkJOnQXRvkcGNZMp+Dvyry9GWTidbQ8mpDmcjjO48mXBIRIz12zrtGwCVxZ FAkk+hSrBF6jgYc0hQ6mucyx113VNMbD2rRaLthZ8U+XRkedSidqz8TomMRC/4h8Bv4Axc +7fJ5VbKZh8ytF9a7gDYXIghA7+fnyEIOtwRDcVNe+E4kx2nXiBLNfgdjjf7U+lghRdsbI NrLMBw5X/uHcEGm8W2XBjAKuPGK72QuQmHSwWXfZ/9lgH25Z3whNuvk3a3zDkg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1773937378; a=rsa-sha256; cv=none; b=JhtY1RUvzDwOOb8GWrM1dFslbZu0HBeEm6dvom4t5yRuMlLGe7cclXGIBGh3+RE8bpKjZZ XR/ymLXcVgYQTrgUwd7PatWagUKJbdN6Lbtf/TJR7KZIQ+AH3C2GaWmZNb+EpJD5UBIHxe qeH9ldAkVkNP9ZSWMTJa1fC4c0benXntIOO55SBByUgthonJWs1BScR/sAH7xQkSEo+STG TluUtuA7axX1AOI/ECZTM+E8jldCZ14YMmCQNX6zkzfufNIYkhm7VXBVPOyzkSXeq4ytqy iqNrG8Lthex7p7oU2EUiw1d7y9/tgJ9e5HSLaZGLrxnB/mRAs4+obQdFokcc+Q== 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=1773937378; 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=N0iFKP40rOi1v1CbgxLQPxkN2Xr+oE6j4jNjXpensgU=; b=XXeJs1OxPbu7rmxliyZOR3Hc0YSEX0BGI4h0NVC4I7IX50pqvtAcRhC56ap7zQebChbpJO FPINniaf25KKZPucD6Cqb+h6/OD0b/DFn7WSL+OMEQKuBrZSpkHqXNc82JNJq8WSZ53N3o 9OqwrVLfHg2AKQLLj1J7ebViDiaqkLa80NiBMBhjgSRerW4WPqu6m+tLteZigd4VcSwa69 +Hc1WaAgJjPGixOzq8Kb3riraa1NMG5fKm92YklD2x7IuLEF8R54Id1vNjZzAAw4/YOGIR soYCKTcbvBJvgvo3pY4Haz1mFLOgTCPUzCmIlezPs2RNdfg+ADjfB9jchD+jzA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fc9wL2mzbz12fR for ; Thu, 19 Mar 2026 16:22:58 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 26c0f by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 19 Mar 2026 16:22:58 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Pouria Mousavizadeh Tehrani Subject: git: 15ebee7c2ed3 - main - ndp: Accept multiple queued ND for non-GRAND NAs List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@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: 15ebee7c2ed34d2dad8457d6595010ea4ed7e1f2 Auto-Submitted: auto-generated Date: Thu, 19 Mar 2026 16:22:58 +0000 Message-Id: <69bc22e2.26c0f.6a079009@gitrepo.freebsd.org> The branch main has been updated by pouria: URL: https://cgit.FreeBSD.org/src/commit/?id=15ebee7c2ed34d2dad8457d6595010ea4ed7e1f2 commit 15ebee7c2ed34d2dad8457d6595010ea4ed7e1f2 Author: Pouria Mousavizadeh Tehrani AuthorDate: 2026-03-17 20:09:42 +0000 Commit: Pouria Mousavizadeh Tehrani CommitDate: 2026-03-19 16:20:06 +0000 ndp: Accept multiple queued ND for non-GRAND NAs Multiple delayed NAs on the same ifa can occur simultaneously. Therefore: * Differentiate between GRAND and solicited replies. * Cancel previous pending GRAND NA for same ifa. * Reuse ndq memory for GRAND. * Free non-GRAND replies immediately. * Don't limit non-GRAND NAs. Reviewed by: glebius Differential Revision: https://reviews.freebsd.org/D55905 --- sys/netinet6/nd6.h | 6 ++- sys/netinet6/nd6_nbr.c | 120 ++++++++++++++++++++++++++++--------------------- 2 files changed, 73 insertions(+), 53 deletions(-) diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index d9fccce33980..70cd6dfbdb62 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -155,7 +155,10 @@ 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 */ +#define ND6_QUEUE_FLAG_ANYCAST 0x04 /* delay NA for anycast address */ + +/* GRAND specific flags */ +#define ND6_QUEUE_GRAND_MASK (ND6_QUEUE_FLAG_NEWGUA|ND6_QUEUE_FLAG_LLADDR) /* protocol constants */ #define MAX_RTR_SOLICITATION_DELAY 1 /* 1sec */ @@ -375,7 +378,6 @@ 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 5cc0553fe7c6..44677a9637bd 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -98,6 +98,7 @@ static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *, const struct in6_addr *, u_long, int, struct sockaddr *, u_int); static void nd6_ns_output_fib(struct ifnet *, const struct in6_addr *, const struct in6_addr *, const struct in6_addr *, uint8_t *, u_int); +static void nd6_queue_add(struct ifaddr *, struct in6_addr *, int, uint32_t); static struct ifaddr *nd6_proxy_fill_sdl(struct ifnet *, const struct in6_addr *, struct sockaddr_dl *); @@ -365,7 +366,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) 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() % + nd6_queue_add(ifa, &saddr6, arc4random() % (MAX_ANYCAST_DELAY_TIME * hz), ND6_QUEUE_FLAG_ANYCAST); freeit: if (ifa != NULL) @@ -1652,15 +1653,16 @@ static void nd6_queue_rel(void *arg) { struct nd_queue *ndq = arg; - struct ifaddr *ifa = ndq->ndq_ifa; + struct ifaddr *ifa; + ifa = ndq->ndq_ifa; IF_ADDR_WLOCK_ASSERT(ifa->ifa_ifp); - /* Remove ndq from the nd_queue and free it */ + /* Remove ndq from the nd_queue list and free it */ TAILQ_REMOVE(&ifa->ifa_ifp->if_inet6->nd_queue, ndq, ndq_list); - free(ndq, M_IP6NDP); IF_ADDR_WUNLOCK(ifa->ifa_ifp); + free(ndq, M_IP6NDP); ifa_free(ifa); } @@ -1670,7 +1672,6 @@ nd6_queue_timer(void *arg) struct nd_queue *ndq = arg; struct ifaddr *ifa = ndq->ndq_ifa; struct ifnet *ifp; - struct in6_ifextra *ext; struct in6_addr daddr; struct epoch_tracker et; int delay, tlladdr; @@ -1679,14 +1680,13 @@ nd6_queue_timer(void *arg) KASSERT(ifa != NULL, ("ND6 queue entry %p with no address", ndq)); ifp = ifa->ifa_ifp; - ext = ifp->if_inet6; CURVNET_SET(ifp->if_vnet); NET_EPOCH_ENTER(et); daddr = ndq->ndq_daddr; tlladdr = ND6_NA_OPT_LLA; flags = (V_ip6_forwarding) ? ND_NA_FLAG_ROUTER : 0; - if ((ext->nd_flags & ND6_IFF_ACCEPT_RTADV) != 0 && V_ip6_norbit_raif) + if ((ifp->if_inet6->nd_flags & ND6_IFF_ACCEPT_RTADV) != 0 && V_ip6_norbit_raif) flags &= ~ND_NA_FLAG_ROUTER; /* @@ -1699,7 +1699,7 @@ nd6_queue_timer(void *arg) * then the Override flag MUST NOT be set. * We don't support RFC 4429 yet. */ - if ((ext->nd_flags & ND6_IFF_PREFER_SOURCE) == 0) + if ((ifp->if_inet6->nd_flags & ND6_IFF_PREFER_SOURCE) == 0) flags |= ND_NA_FLAG_OVERRIDE; } /* @@ -1712,10 +1712,16 @@ nd6_queue_timer(void *arg) 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 it was GRAND, wait at least a RetransTimer + * before removing from queue. + */ + if ((ndq->ndq_flags & ND6_QUEUE_GRAND_MASK) != 0) { + delay = ifp->if_inet6->nd_retrans * hz / 1000; + callout_reset(&ndq->ndq_callout, delay, nd6_queue_rel, ndq); + IF_ADDR_WUNLOCK(ifp); + } else + nd6_queue_rel(ndq); if (__predict_true(in6_setscope(&daddr, ifp, NULL) == 0)) nd6_na_output_fib(ifp, &daddr, IFA_IN6(ifa), flags, tlladdr, @@ -1729,37 +1735,52 @@ static void 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; - struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; - struct in6_ifextra *ext = ifp->if_inet6; + struct nd_queue *ndq = NULL; + struct ifnet *ifp; + struct in6_ifextra *ext; char ip6buf[INET6_ADDRSTRLEN]; NET_EPOCH_ASSERT(); - ndq = malloc(sizeof(*ndq), M_IP6NDP, M_NOWAIT | M_ZERO); - if (ndq == NULL) { - log(LOG_ERR, "nd6_queue_add: memory allocation failed for " - "%s(%s)\n", - ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), - ifp ? if_name(ifp) : "???"); - return; + ifp = ifa->ifa_ifp; + ext = ifp->if_inet6; + IF_ADDR_WLOCK(ifp); + /* + * if request comes from GRAND, check whether another delayed + * GRAND NA exists in the queue. + * If it exists, cancel previous one and reuse its ndq. + */ + if ((flags & ND6_QUEUE_GRAND_MASK) != 0) { + TAILQ_FOREACH(ndq, &ext->nd_queue, ndq_list) { + if (ndq->ndq_ifa == ifa && + (flags & ND6_QUEUE_GRAND_MASK) != 0) + break; + } } + if (ndq == NULL) { + ndq = malloc(sizeof(*ndq), M_IP6NDP, M_NOWAIT | M_ZERO); + if (ndq == NULL) { + log(LOG_ERR, "%s: memory allocation failed for %s(%s)\n", + __func__, ip6_sprintf(ip6buf, IFA_IN6(ifa)), + ifp ? if_name(ifp) : "???"); + IF_ADDR_WUNLOCK(ifp); + return; + } - IF_ADDR_WLOCK(ifa->ifa_ifp); - callout_init_mtx(&ndq->ndq_callout, &ifp->if_addr_lock, - CALLOUT_TRYLOCK | CALLOUT_RETURNUNLOCKED); - nd6log((LOG_DEBUG, "%s: send delayed IPv6 ND for %s\n", if_name(ifp), - ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); + callout_init_mtx(&ndq->ndq_callout, &ifp->if_addr_lock, + CALLOUT_TRYLOCK | CALLOUT_RETURNUNLOCKED); + ifa_ref(ifa); + ndq->ndq_ifa = ifa; + TAILQ_INSERT_TAIL(&ext->nd_queue, ndq, ndq_list); + } - 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); + nd6log((LOG_DEBUG, "%s: delay IPv6 NA for %s\n", if_name(ifp), + ip6_sprintf(ip6buf, IFA_IN6(ifa)))); callout_reset(&ndq->ndq_callout, delay, nd6_queue_timer, ndq); - IF_ADDR_WUNLOCK(ifa->ifa_ifp); + IF_ADDR_WUNLOCK(ifp); } /* @@ -1795,7 +1816,12 @@ nd6_grand_start(struct ifaddr *ifa, uint32_t flags) * up to MAX_NEIGHBOR_ADVERTISEMENT Neighbor Advertisement messages. * Make sure we don't queue GRAND more than V_ip6_grand_count * per interface. + * Since this limitation only applies to GRAND, don't + * count non-GRAND ndq. */ + if ((ndq->ndq_flags & ND6_QUEUE_GRAND_MASK) == 0) + continue; + count++; if (count >= V_ip6_grand_count) return; @@ -1825,29 +1851,21 @@ nd6_grand_start(struct ifaddr *ifa, uint32_t flags) void nd6_queue_stop(struct ifaddr *ifa) { - struct nd_queue *ndq; + struct nd_queue *ndq, *dndq; + struct ifnet *ifp; - IF_ADDR_WLOCK(ifa->ifa_ifp); - TAILQ_FOREACH(ndq, &ifa->ifa_ifp->if_inet6->nd_queue, ndq_list) { + ifp = ifa->ifa_ifp; + IF_ADDR_WLOCK(ifp); + TAILQ_FOREACH_SAFE(ndq, &ifp->if_inet6->nd_queue, ndq_list, dndq) { if (ndq->ndq_ifa != ifa) continue; callout_stop(&ndq->ndq_callout); - nd6_queue_rel(ndq); - return; - } - 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); + /* Remove ndq from the nd_queue list and free it */ + TAILQ_REMOVE(&ifa->ifa_ifp->if_inet6->nd_queue, ndq, ndq_list); + free(ndq, M_IP6NDP); + ifa_free(ifa); + } + IF_ADDR_WUNLOCK(ifp); }