* [PATCH net-next 0/2] ipv6: Cache pmtu on all paths of a multipath route
@ 2026-10-17 21:05 Vladimir Vdovin
2026-10-17 21:05 ` [PATCH net-next 1/2] ipv6: Cache pmtu for " Vladimir Vdovin
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Vladimir Vdovin @ 2026-10-17 21:05 UTC (permalink / raw)
To: netdev
Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms, shuah,
linux-kselftest, linux-kernel, Vladimir Vdovin
IPv6 counterpart of commit 7d3f3b4367f3 ("net: ipv4: Cache pmtu for
all packet paths if multipath enabled"), deferred back then:
https://lore.kernel.org/netdev/ad29493c-9e48-4a94-b327-e47af3a9d137@kernel.org/
Patch 1 creates the PMTU exception on every path of a multipath route,
patch 2 adds the IPv6 variant of the pmtu.sh multipath test, which
fails without patch 1.
Vladimir Vdovin (2):
ipv6: Cache pmtu for all paths of a multipath route
selftests: net: pmtu: Add IPv6 multipath exceptions test
net/ipv6/route.c | 88 ++++++++++-----
tools/testing/selftests/net/pmtu.sh | 162 +++++++++++++++++++++-------
2 files changed, 185 insertions(+), 65 deletions(-)
base-commit: 98c2ad4f5d805dbc1ea436a334ee59311806a48c
--
2.56.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH net-next 1/2] ipv6: Cache pmtu for all paths of a multipath route
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
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
2 siblings, 0 replies; 4+ messages in thread
From: Vladimir Vdovin @ 2026-10-17 21:05 UTC (permalink / raw)
To: netdev
Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms, shuah,
linux-kselftest, linux-kernel, Vladimir Vdovin
__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
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH net-next 2/2] selftests: net: pmtu: Add IPv6 multipath exceptions test
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 ` [PATCH net-next 1/2] ipv6: Cache pmtu for " Vladimir Vdovin
@ 2026-10-17 21:05 ` Vladimir Vdovin
2026-10-18 13:47 ` [PATCH net-next 0/2] ipv6: Cache pmtu on all paths of a multipath route Ido Schimmel
2 siblings, 0 replies; 4+ messages in thread
From: Vladimir Vdovin @ 2026-10-17 21:05 UTC (permalink / raw)
To: netdev
Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms, shuah,
linux-kselftest, linux-kernel, Vladimir Vdovin
Make pmtu_ipv4_mp_exceptions family agnostic and add
pmtu_ipv6_mp_exceptions: one oversized ping over a multipath route
must leave PMTU exceptions on both paths.
Without the preceding fix the IPv6 test fails with both legacy
nexthops and nexthop objects:
PMTU exception wasn't created after exceeding MTU (veth_A-R2)
Signed-off-by: Vladimir Vdovin <deliran@verdict.gg>
---
tools/testing/selftests/net/pmtu.sh | 162 +++++++++++++++++++++-------
1 file changed, 124 insertions(+), 38 deletions(-)
diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh
index c7cd271714ef..9ff46708fa03 100755
--- a/tools/testing/selftests/net/pmtu.sh
+++ b/tools/testing/selftests/net/pmtu.sh
@@ -203,6 +203,9 @@
# on host A and B on lo reachable via both routers. Host A and B
# addresses have multipath routes to each other, b_r1 mtu = 1500.
# Check that PMTU exceptions are created for both paths.
+#
+# - pmtu_ipv6_mp_exceptions
+# Same as above but with IPv6
source lib.sh
@@ -272,7 +275,8 @@ tests="
list_flush_ipv6_exception ipv6: list and flush cached exceptions 1
pmtu_ipv4_route_change ipv4: PMTU exception w/route replace 1
pmtu_ipv6_route_change ipv6: PMTU exception w/route replace 1
- pmtu_ipv4_mp_exceptions ipv4: PMTU multipath nh exceptions 1"
+ pmtu_ipv4_mp_exceptions ipv4: PMTU multipath nh exceptions 1
+ pmtu_ipv6_mp_exceptions ipv6: PMTU multipath nh exceptions 1"
# Addressing and routing for tests with routers: four network segments, with
# index SEGMENT between 1 and 4, a common prefix (PREFIX4 or PREFIX6) and an
@@ -352,6 +356,9 @@ tunnel6_mask="64"
host4_a_addr="192.168.99.99"
host4_b_addr="192.168.88.88"
+host6_a_addr="fc00:1000::a"
+host6_b_addr="fc00:1001::b"
+
dummy6_0_prefix="fc00:1000::"
dummy6_1_prefix="fc00:1001::"
dummy6_mask="64"
@@ -994,49 +1001,112 @@ setup_ovs_bridge() {
}
setup_multipath_new() {
- # Set up host A with multipath routes to host B host4_b_addr
- run_cmd ${ns_a} ip addr add ${host4_a_addr} dev lo
- run_cmd ${ns_a} ip nexthop add id 401 via ${prefix4}.${a_r1}.2 dev veth_A-R1
- run_cmd ${ns_a} ip nexthop add id 402 via ${prefix4}.${a_r2}.2 dev veth_A-R2
- run_cmd ${ns_a} ip nexthop add id 403 group 401/402
- run_cmd ${ns_a} ip route add ${host4_b_addr} src ${host4_a_addr} nhid 403
+ family=${1}
- # Set up host B with multipath routes to host A host4_a_addr
- run_cmd ${ns_b} ip addr add ${host4_b_addr} dev lo
- run_cmd ${ns_b} ip nexthop add id 401 via ${prefix4}.${b_r1}.2 dev veth_B-R1
- run_cmd ${ns_b} ip nexthop add id 402 via ${prefix4}.${b_r2}.2 dev veth_B-R2
- run_cmd ${ns_b} ip nexthop add id 403 group 401/402
- run_cmd ${ns_b} ip route add ${host4_a_addr} src ${host4_b_addr} nhid 403
+ if [ ${family} -eq 4 ]; then
+ host_a_addr=${host4_a_addr}
+ host_b_addr=${host4_b_addr}
+ nh_a_r1=${prefix4}.${a_r1}.2
+ nh_a_r2=${prefix4}.${a_r2}.2
+ nh_b_r1=${prefix4}.${b_r1}.2
+ nh_b_r2=${prefix4}.${b_r2}.2
+ else
+ host_a_addr=${host6_a_addr}
+ host_b_addr=${host6_b_addr}
+ nh_a_r1=${prefix6}:${a_r1}::2
+ nh_a_r2=${prefix6}:${a_r2}::2
+ nh_b_r1=${prefix6}:${b_r1}::2
+ nh_b_r2=${prefix6}:${b_r2}::2
+ fi
+
+ # Set up host A with multipath routes to host B host_b_addr
+ run_cmd ${ns_a} ip addr add ${host_a_addr} dev lo
+ run_cmd ${ns_a} ip nexthop add id ${family}01 via ${nh_a_r1} dev veth_A-R1
+ run_cmd ${ns_a} ip nexthop add id ${family}02 via ${nh_a_r2} dev veth_A-R2
+ run_cmd ${ns_a} ip nexthop add id ${family}03 group ${family}01/${family}02
+ run_cmd ${ns_a} ip route add ${host_b_addr} src ${host_a_addr} nhid ${family}03
+
+ # Set up host B with multipath routes to host A host_a_addr
+ run_cmd ${ns_b} ip addr add ${host_b_addr} dev lo
+ run_cmd ${ns_b} ip nexthop add id ${family}01 via ${nh_b_r1} dev veth_B-R1
+ run_cmd ${ns_b} ip nexthop add id ${family}02 via ${nh_b_r2} dev veth_B-R2
+ run_cmd ${ns_b} ip nexthop add id ${family}03 group ${family}01/${family}02
+ run_cmd ${ns_b} ip route add ${host_a_addr} src ${host_b_addr} nhid ${family}03
}
setup_multipath_old() {
- # Set up host A with multipath routes to host B host4_b_addr
- run_cmd ${ns_a} ip addr add ${host4_a_addr} dev lo
- run_cmd ${ns_a} ip route add ${host4_b_addr} \
- src ${host4_a_addr} \
- nexthop via ${prefix4}.${a_r1}.2 weight 1 \
- nexthop via ${prefix4}.${a_r2}.2 weight 1
+ family=${1}
- # Set up host B with multipath routes to host A host4_a_addr
- run_cmd ${ns_b} ip addr add ${host4_b_addr} dev lo
- run_cmd ${ns_b} ip route add ${host4_a_addr} \
- src ${host4_b_addr} \
- nexthop via ${prefix4}.${b_r1}.2 weight 1 \
- nexthop via ${prefix4}.${b_r2}.2 weight 1
+ if [ ${family} -eq 4 ]; then
+ host_a_addr=${host4_a_addr}
+ host_b_addr=${host4_b_addr}
+ nh_a_r1=${prefix4}.${a_r1}.2
+ nh_a_r2=${prefix4}.${a_r2}.2
+ nh_b_r1=${prefix4}.${b_r1}.2
+ nh_b_r2=${prefix4}.${b_r2}.2
+ else
+ host_a_addr=${host6_a_addr}
+ host_b_addr=${host6_b_addr}
+ nh_a_r1=${prefix6}:${a_r1}::2
+ nh_a_r2=${prefix6}:${a_r2}::2
+ nh_b_r1=${prefix6}:${b_r1}::2
+ nh_b_r2=${prefix6}:${b_r2}::2
+ fi
+
+ # Set up host A with multipath routes to host B host_b_addr
+ run_cmd ${ns_a} ip addr add ${host_a_addr} dev lo
+ run_cmd ${ns_a} ip route add ${host_b_addr} \
+ src ${host_a_addr} \
+ nexthop via ${nh_a_r1} weight 1 \
+ nexthop via ${nh_a_r2} weight 1
+
+ # Set up host B with multipath routes to host A host_a_addr
+ run_cmd ${ns_b} ip addr add ${host_b_addr} dev lo
+ run_cmd ${ns_b} ip route add ${host_a_addr} \
+ src ${host_b_addr} \
+ nexthop via ${nh_b_r1} weight 1 \
+ nexthop via ${nh_b_r2} weight 1
}
+
setup_multipath() {
+ family="$1"
+
+ if [ ${family} -eq 4 ]; then
+ host_a_addr=${host4_a_addr}
+ host_b_addr=${host4_b_addr}
+ nh_r1_a=${prefix4}.${a_r1}.1
+ nh_r1_b=${prefix4}.${b_r1}.1
+ nh_r2_a=${prefix4}.${a_r2}.1
+ nh_r2_b=${prefix4}.${b_r2}.1
+ else
+ host_a_addr=${host6_a_addr}
+ host_b_addr=${host6_b_addr}
+ nh_r1_a=${prefix6}:${a_r1}::1
+ nh_r1_b=${prefix6}:${b_r1}::1
+ nh_r2_a=${prefix6}:${a_r2}::1
+ nh_r2_b=${prefix6}:${b_r2}::1
+ fi
+
if [ "$USE_NH" = "yes" ]; then
- setup_multipath_new
+ setup_multipath_new ${family}
else
- setup_multipath_old
+ setup_multipath_old ${family}
fi
# Set up routers with routes to dummies
- run_cmd ${ns_r1} ip route add ${host4_a_addr} via ${prefix4}.${a_r1}.1
- run_cmd ${ns_r2} ip route add ${host4_a_addr} via ${prefix4}.${a_r2}.1
- run_cmd ${ns_r1} ip route add ${host4_b_addr} via ${prefix4}.${b_r1}.1
- run_cmd ${ns_r2} ip route add ${host4_b_addr} via ${prefix4}.${b_r2}.1
+ run_cmd ${ns_r1} ip route add ${host_a_addr} via ${nh_r1_a}
+ run_cmd ${ns_r2} ip route add ${host_a_addr} via ${nh_r2_a}
+ run_cmd ${ns_r1} ip route add ${host_b_addr} via ${nh_r1_b}
+ run_cmd ${ns_r2} ip route add ${host_b_addr} via ${nh_r2_b}
+}
+
+setup_multipath4() {
+ setup_multipath 4
+}
+
+setup_multipath6() {
+ setup_multipath 6
}
setup() {
@@ -2377,8 +2447,18 @@ test_pmtu_ipv6_route_change() {
test_pmtu_ipvX_route_change 6
}
-test_pmtu_ipv4_mp_exceptions() {
- setup namespaces routing multipath || return $ksft_skip
+test_pmtu_ipvX_mp_exceptions() {
+ family=${1}
+
+ if [ ${family} -eq 4 ]; then
+ ping=ping
+ dst="${host4_b_addr}"
+ else
+ ping=${ping6}
+ dst="${host6_b_addr}"
+ fi
+
+ setup namespaces routing multipath${family} || return $ksft_skip
trace "${ns_a}" veth_A-R1 "${ns_r1}" veth_R1-A \
"${ns_r1}" veth_R1-B "${ns_b}" veth_B-R1 \
@@ -2395,18 +2475,24 @@ test_pmtu_ipv4_mp_exceptions() {
mtu "${ns_r2}" veth_R2-A 2000
mtu "${ns_r2}" veth_R2-B 1500
mtu "${ns_b}" veth_B-R2 1500
-
# Ping and expect two nexthop exceptions for two routes
- run_cmd ${ns_a} ping -q -M want -i 0.1 -c 1 -s 1800 "${host4_b_addr}"
+ run_cmd ${ns_a} ${ping} -q -M want -i 0.1 -c 1 -s 1800 "${dst}"
# Check that exceptions have been created with the correct PMTU
- pmtu_a_R1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${host4_b_addr}" oif veth_A-R1)"
- pmtu_a_R2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${host4_b_addr}" oif veth_A-R2)"
-
+ pmtu_a_R1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst}" oif veth_A-R1)"
+ pmtu_a_R2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst}" oif veth_A-R2)"
check_pmtu_value "1500" "${pmtu_a_R1}" "exceeding MTU (veth_A-R1)" || return 1
check_pmtu_value "1500" "${pmtu_a_R2}" "exceeding MTU (veth_A-R2)" || return 1
}
+test_pmtu_ipv4_mp_exceptions() {
+ test_pmtu_ipvX_mp_exceptions 4
+}
+
+test_pmtu_ipv6_mp_exceptions() {
+ test_pmtu_ipvX_mp_exceptions 6
+}
+
usage() {
echo
echo "$0 [OPTIONS] [TEST]..."
--
2.56.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH net-next 0/2] ipv6: Cache pmtu on all paths of a multipath route
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 ` [PATCH net-next 1/2] ipv6: Cache pmtu for " Vladimir Vdovin
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 ` Ido Schimmel
2 siblings, 0 replies; 4+ messages in thread
From: Ido Schimmel @ 2026-10-18 13:47 UTC (permalink / raw)
To: Vladimir Vdovin
Cc: netdev, dsahern, davem, edumazet, kuba, pabeni, horms, shuah,
linux-kselftest, linux-kernel
On Sun, Oct 18, 2026 at 12:05:06AM +0300, Vladimir Vdovin wrote:
> IPv6 counterpart of commit 7d3f3b4367f3 ("net: ipv4: Cache pmtu for
> all packet paths if multipath enabled"), deferred back then:
> https://lore.kernel.org/netdev/ad29493c-9e48-4a94-b327-e47af3a9d137@kernel.org/
[...]
> net/ipv6/route.c | 88 ++++++++++-----
Given that this was deferred for two years, I would prefer not to rush
it in on the last day of the cycle. Please repost when net-next reopens
after the merge window.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-18 13:47 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH net-next 1/2] ipv6: Cache pmtu for " Vladimir Vdovin
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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox