Netdev List
 help / color / mirror / Atom feed
* IPv6: wrong routing from local socket with multiple routing tables
@ 2026-10-19 11:35 Girlich, Franz
  2026-10-20 15:03 ` Ido Schimmel
  0 siblings, 1 reply; 2+ messages in thread
From: Girlich, Franz @ 2026-10-19 11:35 UTC (permalink / raw)
  To: netdev@vger.kernel.org

Hi!

IPv6 routing from a local socket breaks when using multiple routing
tables and changing them while the socket is in use. When a different
routing table is changed, i.e., one not "used" by the local socket, so
that the best path for the socket changes, packets from the socket
still use the old path.

The behavior fixes itself, when the routing rules are touched, the
table currently in use is touched, or the socket is re-opened.

I was able to reproduce this bug with multiple kernel versions,
including current master 7.3.0-rc7 and 6.12.113 LTS: 

----------------------------
# add 2 dummy interfaces
ip link add d0 type dummy
ip link set d0 up
ip link add d1 type dummy
ip link set d1 up

# setup 2 table, add default route to lower prio one
ip -6 rule add prio 10 lookup 10
ip -6 rule add prio 20 lookup 20
ip -6 route add table 20 default dev d1

# start traffic from a local socket
iperf -u -c fc::1 -t0 &

# packets are routed correctly to d1
tcpdump -ni any -c 10

# add route to higher prio table
ip -6 route add table 10 default dev d0

# routing lookup correctly produces route to d0
ip -6 route get fc::1

# BUG: traffic from old socket is still routed to d1 instead of d0
tcpdump -ni any -c 10

# cleanup
pkill iperf
ip -6 rule del prio 10
ip -6 rule del prio 20
ip -6 route flush table 20
ip -6 route flush table 10
ip link del d0
ip link del d1
----------------------------

I used deepseek-v4.1-flash to attempt a fix for this issue. The fix
does work for the reproduction above, but I am not confident that it is
regression free. So I am attaching it for reference only.

----------------------------
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 9ff761962..516176599 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -2059,6 +2059,8 @@ static void fib6_del_route(struct fib6_table
*table, struct fib6_node *fn,
        if (!info->skip_notify)
                inet6_rt_del_notify(rt, info, del_reason);

+       fib6_new_sernum(net);
+
        fib6_info_release(rt);
 }

diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a5e955e56..b21ef70f1 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1430,8 +1430,7 @@ static struct rt6_info *ip6_rt_pcpu_alloc(const
struct fib6_result *res)
        ip6_rt_copy_init(pcpu_rt, res);
        pcpu_rt->rt6i_flags |= RTF_PCPU;

-       if (f6i->nh)
-               pcpu_rt->sernum = rt_genid_ipv6(dev_net(dev));
+       pcpu_rt->sernum = rt_genid_ipv6(dev_net(dev));

        return pcpu_rt;
 }
----------------------------


-- 
Franz Girlich
Senior Software Developer
PA PD Network
Division Public Authorities
secunet Security Networks AG

Tel.: +49 201 5454 1099
E-Mail: franz.girlich@secunet.com
Werner-von-Siemens-Straße 6, 98693 Ilmenau
www.secunet.com

______________________________________________________________________

secunet Security Networks AG
Sitz: Kurfürstenstraße 58, 45138 Essen, Deutschland
Amtsgericht Essen HRB 13615
Vorstand: Marc-Julian Siewert (Vors.), Torsten Henn, Dr. Kai Martius,
Aufsichtsratsvorsitzender: Dr. Ralf Wintergerst
______________________________________________________________________


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: IPv6: wrong routing from local socket with multiple routing tables
  2026-10-19 11:35 IPv6: wrong routing from local socket with multiple routing tables Girlich, Franz
@ 2026-10-20 15:03 ` Ido Schimmel
  0 siblings, 0 replies; 2+ messages in thread
From: Ido Schimmel @ 2026-10-20 15:03 UTC (permalink / raw)
  To: Girlich, Franz; +Cc: netdev@vger.kernel.org

On Mon, Oct 19, 2026 at 11:35:43AM +0000, Girlich, Franz wrote:
> Hi!
> 
> IPv6 routing from a local socket breaks when using multiple routing
> tables and changing them while the socket is in use. When a different
> routing table is changed, i.e., one not "used" by the local socket, so
> that the best path for the socket changes, packets from the socket
> still use the old path.
> 
> The behavior fixes itself, when the routing rules are touched, the
> table currently in use is touched, or the socket is re-opened.
> 
> I was able to reproduce this bug with multiple kernel versions,
> including current master 7.3.0-rc7 and 6.12.113 LTS: 

Thanks for the report. AFAICT, this is not a regression (never worked).

[...]

> 
> I used deepseek-v4.1-flash to attempt a fix for this issue. The fix
> does work for the reproduction above, but I am not confident that it is
> regression free. So I am attaching it for reference only.
> 
> ----------------------------
> diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
> index 9ff761962..516176599 100644
> --- a/net/ipv6/ip6_fib.c
> +++ b/net/ipv6/ip6_fib.c
> @@ -2059,6 +2059,8 @@ static void fib6_del_route(struct fib6_table
> *table, struct fib6_node *fn,
>         if (!info->skip_notify)
>                 inet6_rt_del_notify(rt, info, del_reason);
> 
> +       fib6_new_sernum(net);
> +
>         fib6_info_release(rt);
>  }

This looks correct.

> 
> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> index a5e955e56..b21ef70f1 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -1430,8 +1430,7 @@ static struct rt6_info *ip6_rt_pcpu_alloc(const
> struct fib6_result *res)
>         ip6_rt_copy_init(pcpu_rt, res);
>         pcpu_rt->rt6i_flags |= RTF_PCPU;
> 
> -       if (f6i->nh)
> -               pcpu_rt->sernum = rt_genid_ipv6(dev_net(dev));
> +       pcpu_rt->sernum = rt_genid_ipv6(dev_net(dev));
> 
>         return pcpu_rt;
>  }

But this one is problematic. It's similar to IPv4, but invalidating the
cache in IPv4 is cheaper since there are fewer entries to recreate. An
IPv4 nexthop can be shared by many IPv4 routes, whereas in IPv6 each
route is using a different nexthop (unless you're using nexthop object).

It also doesn't solve the problem when the socket is caching a dst entry
that is not per-CPU (such as an exception). 

I need to think about a different solution for this, but it will take me
some time given other commitments.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-20 15:05 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-19 11:35 IPv6: wrong routing from local socket with multiple routing tables Girlich, Franz
2026-10-20 15:03 ` Ido Schimmel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox