From nobody Mon Nov 02 15:49:29 2026 X-Original-To: dev-commits-src-all@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 4jJGNT6DrKz6xstG for ; Mon, 02 Nov 2026 15:49:29 +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) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 4jJGNT47tJz4cQh for ; Mon, 02 Nov 2026 15:49:29 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793634569; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=gs1rN+T7A4BpAEQvouYMD02B/BZGBRVLfXpWAn3yBYM=; b=y0eGyTt4asaF40fKolw7sfXj9tZEBY/T7Oh3OM3F72JRvPqWCZsHWJ0ASPdY7XDDgYgUqY hZEkMdRjC4kvdrbis1JhZ6laH/Tsd0ZbIOTNvUg80I3Id3UiQRM5ag/pzGBd/dP6YcAZaZ RKyN0I4ek2oyCfetqA0k3KJKdTK3/xvYaQEHwX6kSJjiLni9Knz4gamFkrCuDhtQmsinDz L9RDD0etCK6Fg99f+yl7Gph2WEotUxvogYQ9PCrf3BlEcEbRCd9zWc03CtHEmhJHe+XCdN vexiuT0ZhLFuA0Mr1TasyaaQTr3jI2PcexUeU/feY3Bq0xRM1QE7m+a8rt88+A== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1793634569; b=yC3STi8XRe5kRb4yTjud5kz7eJO2KMOYUcL4PJWjxMT3E36IF18Z13WK+MdMRCL0O5Aexg aFdkrdd0rcx5I3mho5aY8Kgy729oCPaHYKy0KnUpOLMCGWjEKz4fkrdf8mcYRgfDqeKLXw CurWqY/79T7E0cButTahQYSfC2SdjUpzVq34/gCaaXNRTijqhZkIay93Qcj38zg2/ySbz4 LusArRtfTVLi99LAG/9566+ArGmVcdlt6XDG6jVAcdePTckzWLnjjYyFb+Fw+3ur7wRzsh WYAaENxdhhNIUM8uWLjeTtliM+0Gj+aguzXhyn0LEnNOLkNNeTwozQZQDD4zJw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1793634569; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=gs1rN+T7A4BpAEQvouYMD02B/BZGBRVLfXpWAn3yBYM=; b=Nt1oalrjRrnht1rQ83CHiemyDDc6t2dEZ1+U6o1Z0DpvOhNEhWJnQ666CuLiEEUKoaontD reWn1qY7QVIVkUWGbWJO3skUnwh1NR2vfGjQHfIEJ5XB8TguUPfl4p6KM8+BbTUoQ0UZth 3Y8Ab00+e0r96OZfq5hKUwHJAjwXFgjC9811InzPGfr2Rl/roVhP5zj/GHLIau32YrROuB eNzemr+C9v35yOcZ0zAZDeqknJCm58iiU37P2udGZFYOgioevsfCN6UuGFto0kV7X5u/87 UWVUjeNReK7s6JUsMpjfe6JlV28L1MVPMu3t88WCKUfO81XPv8wN2tvYPBr2Lw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4jJGNT39kCzshp for ; Mon, 02 Nov 2026 15:49:29 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 452e3 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 02 Nov 2026 15:49:29 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Cc: =?utf-8?Q?Vin=C3=ADci?=us Fe=?utf-8?Q?rr=C3=A3o?= From: Adrian Chadd Subject: git: c4b6df9a7cc9 - stable/15 - netinet6: Fix ND link-layer address option layout for IPoIB (stable/15) List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: Commit messages for all branches of the src repository List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: adrian X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: c4b6df9a7cc977cbe842b4fa9499af15b48a1b88 Auto-Submitted: auto-generated Date: Mon, 02 Nov 2026 15:49:29 +0000 Message-Id: <6ae8b109.452e3.418479f4@gitrepo.freebsd.org> The branch stable/15 has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=c4b6df9a7cc977cbe842b4fa9499af15b48a1b88 commit c4b6df9a7cc977cbe842b4fa9499af15b48a1b88 Author: Vinícius Ferrão AuthorDate: 2026-11-02 15:45:03 +0000 Commit: Adrian Chadd CommitDate: 2026-11-02 15:46:42 +0000 netinet6: Fix ND link-layer address option layout for IPoIB (stable/15) RFC 4391 (IP over InfiniBand), section 9.3, lays the ND source/target link-layer address option out as type, length (3), two reserved zero octets, then the 20-octet IPoIB link-layer address. The ND code assumed the Ethernet layout (RFC 4861, section 4.6.1) everywhere and read/wrote the address directly after the option header, i.e. two octets early. The option-length sanity check computes 24 for both layouts for a 20-octet address, so the mismatch was silent. Against a conformant peer (e.g. Linux) this broke IPv6 over IPoIB in both directions: the address parsed from a received NS/NA option was shifted by two bytes, so the cached link-layer address embedded a GID that does not exist on the fabric and replies were sent nowhere, and the options we built carried our address at the wrong offset for the peer. IPv4/ARP was unaffected. This blocked everything IPv6 over IPoIB against Linux, including rdma_cm's IP-to-GID resolution and therefore NFS-over-RDMA-over-InfiniBand with IPv6. Add nd6_lladdr_opt_pad(), the analog of Linux's ndisc_addr_option_pad(): the number of reserved octets between the option header and the address (2 for IFT_INFINIBAND and IFT_INFINIBANDLAG, 0 otherwise). Apply it at the option parse sites (nd6_ns_input(), nd6_na_input(), nd6_rs_input(), nd6_ra_input(), icmp6_redirect_input()) and the option build sites (nd6_ns_output_fib(), nd6_na_output_fib(), icmp6_redirect_output()). Zero the redirect target option before filling it; previously its trailing pad bytes were left uninitialized on links with 20-octet addresses. No functional change for link types without reserved octets. This is a direct commit to stable/15, equivalent to main commit bac4760524a2a15ce75e35251f0c9cdf31732f3f (D58096). It could not be cherry-picked cleanly: the neighbor-discovery code diverged on main (the router advertisement parse was refactored into helpers), so the same fix is reimplemented against the stable/15 sources. PR: 296585 Sponsored by: VersatusHPC Reviewed by: pouria Differential Revision: https://reviews.freebsd.org/D58132 --- sys/netinet6/icmp6.c | 9 +++++++-- sys/netinet6/nd6.h | 1 + sys/netinet6/nd6_nbr.c | 35 +++++++++++++++++++++++++++++++---- sys/netinet6/nd6_rtr.c | 7 +++++-- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index ec2e5a22aa33..a2459bc82f23 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -2170,6 +2170,7 @@ icmp6_redirect_input(struct mbuf *m, int off) char ip6buf[INET6_ADDRSTRLEN]; char *lladdr; int icmp6len, is_onlink, is_router, lladdrlen; + u_int lladdr_pad; M_ASSERTPKTHDR(m); KASSERT(m->m_pkthdr.rcvif != NULL, ("%s: no rcvif", __func__)); @@ -2296,8 +2297,9 @@ icmp6_redirect_input(struct mbuf *m, int off) lladdr = NULL; lladdrlen = 0; + lladdr_pad = nd6_lladdr_opt_pad(ifp); if (ndopts.nd_opts_tgt_lladdr) { - lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1); + lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1) + lladdr_pad; lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3; } @@ -2490,6 +2492,7 @@ icmp6_redirect_output(struct mbuf *m0, struct nhop_object *nh) { /* target lladdr option */ int len; + u_int pad; struct nd_opt_hdr *nd_opt; char *lladdr; @@ -2497,6 +2500,7 @@ icmp6_redirect_output(struct mbuf *m0, struct nhop_object *nh) if (ln == NULL) goto nolladdropt; + pad = nd6_lladdr_opt_pad(ifp); len = sizeof(*nd_opt) + ifp->if_addrlen; len = (len + 7) & ~7; /* round by 8 */ /* safety check */ @@ -2505,9 +2509,10 @@ icmp6_redirect_output(struct mbuf *m0, struct nhop_object *nh) if (ln->la_flags & LLE_VALID) { nd_opt = (struct nd_opt_hdr *)p; + memset(nd_opt, 0, len); nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; nd_opt->nd_opt_len = len >> 3; - lladdr = (char *)(nd_opt + 1); + lladdr = (char *)(nd_opt + 1) + pad; bcopy(ln->ll_addr, lladdr, ifp->if_addrlen); p += len; } diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index e484c709e29a..566b92fc783f 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -390,6 +390,7 @@ void nd6_ns_input(struct mbuf *, int, int); void nd6_ns_output(struct ifnet *, const struct in6_addr *, const struct in6_addr *, const struct in6_addr *, uint8_t *); caddr_t nd6_ifptomac(struct ifnet *); +u_int nd6_lladdr_opt_pad(struct ifnet *); void nd6_dad_init(void); void nd6_dad_start(struct ifaddr *, int); void nd6_dad_stop(struct ifaddr *); diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 29151b29a071..d79bb17196a4 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -139,6 +139,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; char *lladdr; int anycast, lladdrlen, proxy, rflag, tentative, tlladdr; + u_int lladdr_pad; ifa = NULL; @@ -226,8 +227,9 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) lladdr = NULL; lladdrlen = 0; + lladdr_pad = nd6_lladdr_opt_pad(ifp); if (ndopts.nd_opts_src_lladdr) { - lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); + lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1) + lladdr_pad; lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; } @@ -559,6 +561,7 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6, struct nd_opt_hdr *nd_opt; char *mac; int optlen; + u_int pad; mac = NULL; if (ifp->if_carp) @@ -568,6 +571,7 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6, if (mac != NULL) { nd_opt = (struct nd_opt_hdr *)(nd_ns + 1); + pad = nd6_lladdr_opt_pad(ifp); optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; /* 8 byte alignments... */ optlen = (optlen + 7) & ~7; @@ -577,7 +581,8 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6, bzero(nd_opt, optlen); nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; nd_opt->nd_opt_len = optlen >> 3; - bcopy(mac, nd_opt + 1, ifp->if_addrlen); + memcpy((char *)(nd_opt + 1) + pad, mac, + ifp->if_addrlen); } } /* @@ -662,6 +667,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) size_t linkhdrsize; int flags, is_override, is_router, is_solicited; int lladdr_off, lladdrlen, checklink; + u_int lladdr_pad; bool flush_holdchain = false; NET_EPOCH_ASSERT(); @@ -730,8 +736,9 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) lladdr = NULL; lladdrlen = 0; + lladdr_pad = nd6_lladdr_opt_pad(ifp); if (ndopts.nd_opts_tgt_lladdr) { - lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1); + lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1) + lladdr_pad; lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3; } @@ -1072,6 +1079,7 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, } } if ((tlladdr & ND6_NA_OPT_LLA) && mac != NULL) { + u_int pad = nd6_lladdr_opt_pad(ifp); int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1); @@ -1084,7 +1092,7 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, bzero((caddr_t)nd_opt, optlen); nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; nd_opt->nd_opt_len = optlen >> 3; - bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen); + memcpy((char *)(nd_opt + 1) + pad, mac, ifp->if_addrlen); } else flags &= ~ND_NA_FLAG_OVERRIDE; @@ -1141,6 +1149,25 @@ nd6_ifptomac(struct ifnet *ifp) } } +/* + * Number of reserved octets between the header of an ND link-layer + * address option and the link-layer address itself. On IPoIB links + * two zero octets are prepended to the 20-octet link-layer address + * to fill the 24-octet option (RFC 4391, section 9.3); on all other + * link types the address immediately follows the option header. + */ +u_int +nd6_lladdr_opt_pad(struct ifnet *ifp) +{ + switch (ifp->if_type) { + case IFT_INFINIBAND: + case IFT_INFINIBANDLAG: + return (2); + default: + return (0); + } +} + struct dadq { TAILQ_ENTRY(dadq) dad_list; struct ifaddr *dad_ifa; diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 4735685a61cd..c497fc9fa6f1 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -169,6 +169,7 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len) char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; char *lladdr; int lladdrlen; + u_int lladdr_pad; ifp = m->m_pkthdr.rcvif; @@ -223,8 +224,9 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len) lladdr = NULL; lladdrlen = 0; + lladdr_pad = nd6_lladdr_opt_pad(ifp); if (ndopts.nd_opts_src_lladdr) { - lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); + lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1) + lladdr_pad; lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; } @@ -577,9 +579,10 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len) { char *lladdr = NULL; int lladdrlen = 0; + u_int lladdr_pad = nd6_lladdr_opt_pad(ifp); if (ndopts.nd_opts_src_lladdr) { - lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); + lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1) + lladdr_pad; lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; }