Netdev List
 help / color / mirror / Atom feed
From: Vladimir Vdovin <deliran@verdict.gg>
To: netdev@vger.kernel.org
Cc: dsahern@kernel.org, idosch@nvidia.com, davem@davemloft.net,
	edumazet@kernel.org, kuba@kernel.org, pabeni@redhat.com,
	horms@kernel.org, shuah@kernel.org,
	linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org,
	Vladimir Vdovin <deliran@verdict.gg>
Subject: [PATCH net-next 1/2] ipv6: Cache pmtu for all paths of a multipath route
Date: Sun, 18 Oct 2026 00:05:07 +0300	[thread overview]
Message-ID: <20261017210508.71849-2-deliran@verdict.gg> (raw)
In-Reply-To: <20261017210508.71849-1-deliran@verdict.gg>

__ip6_rt_update_pmtu() creates the exception route only on the nexthop
the Packet Too Big came in through. With a multipath route the other
paths never see that ICMP error and keep sending with the link MTU, so
flows hashed to them blackhole.

Same problem and same fix as for IPv4 in commit 7d3f3b4367f3 ("net:
ipv4: Cache pmtu for all packet paths if multipath enabled"): create
the exception on every path. For a nexthop object walk all of its
fib6_nh, for a legacy multipath route walk the siblings of the selected
fib6_info.

Link: https://lore.kernel.org/netdev/ad29493c-9e48-4a94-b327-e47af3a9d137@kernel.org/
Signed-off-by: Vladimir Vdovin <deliran@verdict.gg>
---
 net/ipv6/route.c | 88 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 61 insertions(+), 27 deletions(-)

diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 34ab7f330540..d870c20f2728 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2888,6 +2888,30 @@ static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
 		(rt->rt6i_flags & RTF_PCPU || rcu_access_pointer(rt->from));
 }
 
+struct rt6_pmtu_exception_arg {
+	struct fib6_result	*res;
+	const struct in6_addr	*daddr;
+	const struct in6_addr	*saddr;
+	u32			mtu;
+};
+
+static int rt6_nh_insert_pmtu_exception(struct fib6_nh *nh, void *_arg)
+{
+	struct rt6_pmtu_exception_arg *arg = _arg;
+	struct fib6_result *res = arg->res;
+	struct rt6_info *nrt6;
+
+	res->nh = nh;
+	nrt6 = ip6_rt_cache_alloc(res, arg->daddr, arg->saddr);
+	if (nrt6) {
+		rt6_do_update_pmtu(nrt6, arg->mtu);
+		if (rt6_insert_exception(nrt6, res))
+			dst_release_immediate(&nrt6->dst);
+	}
+
+	return 0;
+}
+
 static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
 				 const struct ipv6hdr *iph, u32 mtu,
 				 bool confirm_neigh)
@@ -2925,42 +2949,52 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
 		if (rt6->rt6i_flags & RTF_CACHE)
 			rt6_update_exception_stamp_rt(rt6);
 	} else if (daddr) {
+		struct fib6_info *f6i, *sibling;
 		struct fib6_result res = {};
-		struct rt6_info *nrt6;
+		struct rt6_pmtu_exception_arg arg = {
+			.res = &res,
+			.daddr = daddr,
+			.saddr = saddr,
+			.mtu = mtu,
+		};
 
 		rcu_read_lock();
-		res.f6i = rcu_dereference(rt6->from);
-		if (!res.f6i)
+		f6i = rcu_dereference(rt6->from);
+		if (!f6i)
 			goto out_unlock;
 
-		res.fib6_flags = res.f6i->fib6_flags;
-		res.fib6_type = res.f6i->fib6_type;
+		res.f6i = f6i;
+		res.fib6_flags = f6i->fib6_flags;
+		res.fib6_type = f6i->fib6_type;
 
-		if (res.f6i->nh) {
-			struct fib6_nh_match_arg arg = {
-				.dev = dst_dev_rcu(dst),
-				.gw = &rt6->rt6i_gateway,
-			};
-
-			nexthop_for_each_fib6_nh(res.f6i->nh,
-						 fib6_nh_find_match, &arg);
+		/* A Packet Too Big only ever arrives through the path the
+		 * offending packet took, so cache the pmtu on every path of a
+		 * multipath route: the other paths will not get their own
+		 * ICMP error and would keep sending with the link MTU.
+		 */
+		if (f6i->nh) {
+			nexthop_for_each_fib6_nh(f6i->nh,
+						 rt6_nh_insert_pmtu_exception,
+						 &arg);
+			goto out_unlock;
+		}
 
-			/* fib6_info uses a nexthop that does not have fib6_nh
-			 * using the dst->dev + gw. Should be impossible.
-			 */
-			if (!arg.match)
-				goto out_unlock;
+		rt6_nh_insert_pmtu_exception(f6i->fib6_nh, &arg);
 
-			res.nh = arg.match;
-		} else {
-			res.nh = res.f6i->fib6_nh;
-		}
+		if (!READ_ONCE(f6i->fib6_nsiblings))
+			goto out_unlock;
 
-		nrt6 = ip6_rt_cache_alloc(&res, daddr, saddr);
-		if (nrt6) {
-			rt6_do_update_pmtu(nrt6, mtu);
-			if (rt6_insert_exception(nrt6, &res))
-				dst_release_immediate(&nrt6->dst);
+		/* fib6_del_route() zeroes fib6_nsiblings before unlinking
+		 * f6i, stop then as its list_head may no longer be reached.
+		 */
+		list_for_each_entry_rcu(sibling, &f6i->fib6_siblings,
+					fib6_siblings) {
+			res.f6i = sibling;
+			res.fib6_flags = sibling->fib6_flags;
+			res.fib6_type = sibling->fib6_type;
+			rt6_nh_insert_pmtu_exception(sibling->fib6_nh, &arg);
+			if (!READ_ONCE(f6i->fib6_nsiblings))
+				break;
 		}
 out_unlock:
 		rcu_read_unlock();
-- 
2.56.0


  reply	other threads:[~2026-10-17 21:05 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-17 21:05 [PATCH net-next 0/2] ipv6: Cache pmtu on all paths of a multipath route Vladimir Vdovin
2026-10-17 21:05 ` Vladimir Vdovin [this message]
2026-10-18 22:06   ` [PATCH net-next 1/2] ipv6: Cache pmtu for " netdev-bot+sashiko
2026-10-17 21:05 ` [PATCH net-next 2/2] selftests: net: pmtu: Add IPv6 multipath exceptions test Vladimir Vdovin
2026-10-18 13:47 ` [PATCH net-next 0/2] ipv6: Cache pmtu on all paths of a multipath route Ido Schimmel

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=20261017210508.71849-2-deliran@verdict.gg \
    --to=deliran@verdict.gg \
    --cc=davem@davemloft.net \
    --cc=dsahern@kernel.org \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --cc=idosch@nvidia.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=shuah@kernel.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