* [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; 5+ 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] 5+ 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-18 22:06 ` 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 2 siblings, 1 reply; 5+ 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 [flat|nested] 5+ messages in thread
* Re: [PATCH net-next 1/2] ipv6: Cache pmtu for all paths of a multipath route 2026-10-17 21:05 ` [PATCH net-next 1/2] ipv6: Cache pmtu for " Vladimir Vdovin @ 2026-10-18 22:06 ` netdev-bot+sashiko 0 siblings, 0 replies; 5+ messages in thread From: netdev-bot+sashiko @ 2026-10-18 22:06 UTC (permalink / raw) To: deliran Cc: netdev, dsahern, idosch, davem, edumazet, kuba, pabeni, horms, shuah, linux-kselftest, linux-kernel Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider. Critical: 0 · High: 1 · Medium: 2 · Low: 2 If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [High] The patch fans out to all paths only on the first Packet Too Big. - [Medium] A PTB on one path now replaces whatever exception the other paths already hold for the same daddr, even when that exception has a… - [Medium] The new legacy-sibling walk in __ip6_rt_update_pmtu() (route.c:2984-2998) relies only on f6i->fib6_nsiblings to decide… - [Low] The new comment in __ip6_rt_update_pmtu() (route.c:2970-2974) says 'A Packet Too Big only ever arrives through the path the… - [Low] The commit message has no Fixes: tag and does not say which tree it targets. -- ipv6: Cache pmtu for all paths of a multipath route This patch makes __ip6_rt_update_pmtu() create a PMTU exception on every path of a multipath route, not only on the selected one. For nexthop objects it walks all fib6_nh entries. For legacy multipath routes it walks the fib6_siblings list of the selected fib6_info, mirroring IPv4 commit 7d3f3b4367f3. Link: https://lore.kernel.org/netdev/ad29493c-9e48-4a94-b327-e47af3a9d137@kernel.org/ > Link: https://lore.kernel.org/netdev/ad29493c-9e48-4a94-b327-e47af3a9d137@kernel.org/ > Signed-off-by: Vladimir Vdovin <deliran@verdict.gg> [Severity: Low] This isn't a bug, but there is no Fixes: tag. The IPv4 counterpart 7d3f3b4367f3 was also applied without one, so this may be fine for netdev. It is only worth adding if a stable backport is intended. The target tree would go in the subject prefix. > diff --git a/net/ipv6/route.c b/net/ipv6/route.c > index 34ab7f330540c..d870c20f27281 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)); > } > [ ... ] > +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); [Severity: Medium] Can a PTB on one path now overwrite a lower PMTU or a redirect that another path has already learned? In __ip6_rt_update_pmtu() the only size check is mtu >= dst6_mtu(dst), and it uses the current path's dst. rt6_insert_exception() then compares the new clone only with fib6_mtu(res), and it removes any existing exception for the same key: if (dst_metric_raw(&nrt->dst, RTAX_MTU) >= fib6_mtu(res)) { err = -EINVAL; goto out; } rt6_ex = __rt6_find_exception_spinlock(&bucket, &nrt->rt6i_dst.addr, src_key); if (rt6_ex) rt6_remove_exception(bucket, rt6_ex); So there are two cases. Path B has learned PMTU 1280, and path A has no exception yet (or it expired or was evicted). A PTB of 1400 on A replaces B's 1280 exception with a 1400 one. B's flows then blackhole until B gets its own PTB. Path B has a redirect exception from rt6_do_redirect(), with rt6i_gateway set to the redirect target. A PTB on A replaces it with a PMTU-only clone that uses B's original gateway, so the redirect is lost. IPv4's update_or_create_fnhe() also overwrites fnhe_pmtu, but it keeps fnhe_gw when only a pmtu is passed. Before this patch, a PTB on one path never touched the exceptions of other paths. Should rt6_nh_insert_pmtu_exception() leave an existing exception on that nexthop alone if it already has a lower MTU or is a redirect? > + } > + > + 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) { [Severity: High] Does the fan-out to all paths only happen for the first Packet Too Big? The new code is only in this else branch, which is reached only when rt6_cache_allowed_for_pmtu() is true: return !(rt->rt6i_flags & RTF_CACHE) && (rt->rt6i_flags & RTF_PCPU || rcu_access_pointer(rt->from)); Once the first PTB has created exceptions, the next lookup through ip6_pol_route()->rt6_find_cached_rt() returns the RTF_CACHE exception for the hashed path. This covers both the ip6_route_output() call in ip6_update_pmtu() and TCP's re-route. A second, lower PTB then takes the first branch, for example from a further bottleneck or after a path change: if (!rt6_cache_allowed_for_pmtu(rt6)) { rt6_do_update_pmtu(rt6, mtu); /* update rt6_ex->stamp for cache */ if (rt6->rt6i_flags & RTF_CACHE) rt6_update_exception_stamp_rt(rt6); That branch updates only this one exception. Wouldn't the exceptions on the other siblings or nexthop group members keep the older, higher MTU? Flows hashed to them would then blackhole again. The expiry times also drift apart. The lowered path's exception now expires later than the others. When the others expire, those paths go back to the link MTU. Meanwhile, PTBs looked up through the still-cached path keep taking the single-path branch. IPv4's __ip_rt_update_pmtu() doesn't have this split. Whenever fib_info_num_path() > 1 it calls fib_lookup() and then update_or_create_fnhe() on every nhsel, whether or not the current dst is already a cached fnhe route. Should the RTF_CACHE branch also update every path? > + struct fib6_info *f6i, *sibling; [ ... ] > + /* 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. > + */ [Severity: Low] Is this comment accurate? The interface the ICMPv6 error arrives on isn't used here. The exception goes on the nexthop of the dst passed to ->update_pmtu. For TCP, that dst comes from inet6_csk_route_socket(), which sets the protocol, ports and multipath hash: fl6->flowi6_proto = sk->sk_protocol; ... if (sk->sk_protocol == IPPROTO_TCP) ip6_ecmp_set_mp_hash(sock_net(sk), fl6, sk->sk_txhash); ... fl6->fl6_sport = inet->inet_sport; fl6->fl6_dport = inet->inet_dport; So each TCP flow's PTB already lands on that flow's own transmit path. The cross-path mismatch seems to come from ip6_update_pmtu(), which UDP, raw, ping and tunnels use. Its flowi6 has no flowi6_proto and no ports: struct flowi6 fl6 = { .flowi6_oif = oif, .flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark), .daddr = iph->daddr, .saddr = iph->saddr, .flowlabel = ip6_flowinfo(iph), .flowi6_uid = uid, }; rt6_multipath_hash() uses fl6->flowi6_proto even with policy 0, so the path chosen here can differ from the transmit path. The comment also seems to contradict itself. If every PTB came back over the offending packet's own path, every path would get its own PTB. The rationale also differs from the one in IPv4 commit 7d3f3b4367f3. The commit message uses the same wording: __ip6_rt_update_pmtu() creates the exception route only on the nexthop the Packet Too Big came in through. Could the comment and changelog describe the actual mechanism? They could also mention that TCP flows, which were already handled per path, now get one path's PMTU applied to all paths. > + if (f6i->nh) { [ ... ] > + /* 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; > } [Severity: Medium] Is fib6_nsiblings enough to tell whether the fib6_siblings ring of f6i is still safe to walk? Only fib6_del_route() clears it. The ECMP NLM_F_REPLACE path in fib6_add_rt2node() unlinks the old leaf and its siblings from the node chain and queues them on purge_list. It does not call list_del_rcu() on their fib6_siblings or zero fib6_nsiblings: nsiblings = iter->fib6_nsiblings; iter->fib6_node = NULL; list_add(&iter->purge_link, purge_list); fib6_add() then calls fib6_purge_rt() and fib6_info_release() on each entry. list_add() puts the siblings ahead of the original leaf A, so the siblings are released before fib6_purge_rt(A) clears from on A's per-CPU dsts. In that window, could a PTB handler do the following? rcu_read_lock() f6i = rcu_dereference(rt6->from) /* still A */ READ_ONCE(f6i->fib6_nsiblings) /* still non-zero */ list_for_each_entry_rcu(sibling, &f6i->fib6_siblings, ...) sibling->fib6_flags, sibling->fib6_nh /* B or C, already released */ If the reader's critical section started after call_rcu() on B or C, they can be freed while it runs. That would be a use-after-free of the fib6_info. rt6_nh_insert_pmtu_exception() always returns 0, so the -ENOENT from the fib6_destroying check in rt6_insert_exception() doesn't stop the walk either. The window is narrow: it needs an admin route replace to race with PTB processing, and I didn't find a deterministic trigger. rt6_fill_node() already has a similar sibling walk anchored on dst->from. This one, though, can be reached from a remote ICMPv6 PTB. -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261017210508.71849-1-deliran%40verdict.gg ^ permalink raw reply [flat|nested] 5+ 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; 5+ 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 [flat|nested] 5+ 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; 5+ 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] 5+ messages in thread
end of thread, other threads:[~2026-10-18 22:06 UTC | newest] Thread overview: 5+ 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-18 22:06 ` 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
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®