Thread (4 messages) read the whole thread 4 messages, 1 author, 4d ago

[RFC net-next v2 1/3] ipv6: ndisc: export the route attach as ndisc_attach_dst()

From: Xiang Mei (Microsoft) <hidden>
Date: 2026-07-29 23:01:32
Also in: lkml
Subsystem: networking [general], networking [ipv4/ipv6], the rest · Maintainers: "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds

ndisc_send_skb() pushes the IPv6 header and transmits in one go, so a
caller that has to build the link-layer header and transmit the skb
itself cannot use it.  bonding needs that split to insert VLAN tags
into its NS monitor probes.

Such a caller still has to attach a route before handing the packet to
netfilter: ip6t_mangle_out() calls ip6_route_me_harder() whenever a
rule changes the addresses, mark, hop limit or flow label, and that
dereferences skb_dst(skb) unconditionally.  Neither icmp6_dst_alloc()
nor icmpv6_flow_init() is exported, so a module cannot attach one
itself.

Move the route attach into ndisc_attach_dst() and export it.  It is a
no-op when the skb already carries a route, so ndisc_send_skb() is
unchanged for existing callers.

Signed-off-by: Xiang Mei (Microsoft) <redacted>
---
v2: v1 fixed the crash, ignoring the data corruption.
    v2 tries to fix both.

 include/net/ndisc.h |  3 +++
 net/ipv6/ndisc.c    | 53 ++++++++++++++++++++++++++++++++-------------
 2 files changed, 41 insertions(+), 15 deletions(-)
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 3da1a6f8d3f9..f3e3c3e5c61e 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -411,6 +411,9 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
 		   const struct in6_addr *daddr, const struct in6_addr *saddr,
 		   u64 nonce);
 
+int ndisc_attach_dst(struct sk_buff *skb, const struct in6_addr *daddr,
+		     const struct in6_addr *saddr);
+
 void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
 		    const struct in6_addr *saddr);
 
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index fe36b3f51285..91ffbfec9e5d 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -465,13 +465,44 @@ static void ip6_nd_hdr(struct sk_buff *skb,
 	hdr->daddr = *daddr;
 }
 
+/* Attach a route to a locally generated ndisc message; @skb is not consumed
+ * on failure.  Split out of ndisc_send_skb() for callers that build the
+ * link-layer header themselves.
+ */
+int ndisc_attach_dst(struct sk_buff *skb, const struct in6_addr *daddr,
+		     const struct in6_addr *saddr)
+{
+	u8 type = icmp6_hdr(skb)->icmp6_type;
+	struct dst_entry *dst;
+	struct flowi6 fl6;
+	struct sock *sk;
+	struct net *net;
+
+	if (skb_dst(skb))
+		return 0;
+
+	rcu_read_lock();
+	net = dev_net_rcu(skb->dev);
+	sk = net->ipv6.ndisc_sk;
+	icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
+	dst = icmp6_dst_alloc(skb->dev, &fl6);
+	rcu_read_unlock();
+
+	if (IS_ERR(dst))
+		return PTR_ERR(dst);
+
+	skb_dst_set(skb, dst);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ndisc_attach_dst);
+
 void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
 		    const struct in6_addr *saddr)
 {
 	struct icmp6hdr *icmp6h = icmp6_hdr(skb);
-	struct dst_entry *dst = skb_dst(skb);
 	struct net_device *dev;
 	struct inet6_dev *idev;
+	struct dst_entry *dst;
 	struct net *net;
 	struct sock *sk;
 	int err;
@@ -479,24 +510,16 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
 
 	type = icmp6h->icmp6_type;
 
+	if (ndisc_attach_dst(skb, daddr, saddr)) {
+		kfree_skb(skb);
+		return;
+	}
+
 	rcu_read_lock();
 
 	net = dev_net_rcu(skb->dev);
 	sk = net->ipv6.ndisc_sk;
-	if (!dst) {
-		struct flowi6 fl6;
-		int oif = skb->dev->ifindex;
-
-		icmpv6_flow_init(sk, &fl6, type, saddr, daddr, oif);
-		dst = icmp6_dst_alloc(skb->dev, &fl6);
-		if (IS_ERR(dst)) {
-			rcu_read_unlock();
-			kfree_skb(skb);
-			return;
-		}
-
-		skb_dst_set(skb, dst);
-	}
+	dst = skb_dst(skb);
 
 	icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
 					      IPPROTO_ICMPV6,
-- 
2.43.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help