Re: [PATCH] net/ipv6: repeat route lookup with saddr set for ECMP
From: Paolo Abeni <pabeni@redhat.com>
Date: 2026-03-30 07:56:32
Also in:
lkml
On 3/29/26 11:12 AM, Maximilian Moehl wrote:
quoted hunk ↗ jump to hunk
When the routing decision involves ECMP, the initial hash is calculated with saddr being :: and the decision which interface to select from an ECMP group is based on that hash. If the route lookup has to be repeated, e.g. because a route was updated, the hash is calculated with saddr set to the previously selected address. This can cause the selected interface to change, breaking ongoing connections. To ensure the initial interface selection is based on an actual saddr the route lookup is repeated after the source address selection if a hash was calculated. Signed-off-by: Maximilian Moehl <redacted> Link: https://lore.kernel.org/all/aOYLRyIlc7XU7-7n@shredder/ (local) --- I've created a write-up of what I've done, including the steps taken to test the patch: https://moehl.eu/blog/linux-ipv6-ecmp-instability.html net/ipv6/ip6_output.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 8e2a6b28cea7..465fce51d017 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c@@ -1148,6 +1148,18 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk, *dst = NULL; } + /* If ECMP was involved the initial hash was calculted + * with saddr=:: which can result in instability + * when it is later re-calculated with the selected + * saddr. Lookup the route again with the chosen + * saddr to get a stable result. + */ + if (fl6->mp_hash) { + fl6->mp_hash = 0; + dst_release(*dst); + *dst = NULL; + } + if (fl6->flowi6_oif) flags |= RT6_LOOKUP_F_IFACE; }
This apparently breaks ipv6 fib tests (fib_tests.sh): # IPv6 multipath load balance test # TEST: IPv6 multipath loadbalance [FAIL] see https://github.com/linux-netdev/nipa/wiki/How-to-run-netdev-selftests-CI-style on how to reproduce the tests. Also this would deserve additional testcases. Without diving much inside the code I have the feeling this change is plugged into the wrong place: multipath selection logic should be encapsulated by fib6_select_path(). /P