[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1117959: ipv6_route flags RTF_ADDRCONF and RTF_PREFIX_RT are not cleared when static on-link routes are added during IPv6 address configuration



Package: linux-image-amd64
Version: 6.12.48-1

Dear Debian Linux Kernel Maintainers,

I noticed that the ipv6_route flags RTF_ADDRCONF and RTF_PREFIX_RT are
not cleared when static on-link routes are added during IPv6 address
configuration, and it leads to situations when the kernel updates the
static on-link routes with expiration time.

To replicate the problem I used the latest Debian 13.1 distribution
with the kernel 6.12.48-1 and radvd (on the second machine) with the
following configuration:

root@localhost:~# cat /etc/debian_version
13.1

root@localhost:~# uname -a
Linux localhost 6.12.48+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian
6.12.48-1 (2025-09-20) x86_64 GNU/Linux

radvd.conf (on a directly connected machine):
interface veth1
{
        AdvSendAdvert on;
        MinRtrAdvInterval 45;
        MaxRtrAdvInterval 60;
        AdvDefaultLifetime 0;
        AdvDefaultPreference low;
        AdvHomeAgentFlag off;
        prefix fd00::/64
        {
                AdvOnLink on;
                AdvAutonomous on;
                AdvRouterAddr off;
                AdvPreferredLifetime 60;
                AdvValidLifetime 120;
        };
};


When I first add a manual IPv6 address to the interface receiving
ICMPv6 RA packets and then receive an ICMPv6 RA with the same on-link
prefix, the packet is silently ignored and no ipv6_route flags,
including RTF_EXPIRES, get set on the static route. Everything works as
expected.

However, if an ICMPv6 RA is received before a manual IPv6 address is
set on the interface, and the RA route is installed in the IPv6 route
table, along with the ipv6_route flags RTF_ADDRCONF, RTF_PREFIX_RT, and
RTF_EXPIRES, only the flag RTF_EXPIRES gets cleared when a manual IPv6
address is configured on the interface later. As a result, after
configuring the IPv6 address, it does not have any associated
expiration time, but the kernel still treats it as an RA-learned route,
so the next received RA packet sets the expiration time again.

Below are the steps leading to the described issue:


# RAs are accepted by the inteface ens4
root@localhost:~# cat /proc/sys/net/ipv6/conf/ens4/accept_ra
1


# Nothing is assigned to ens4 yet
root@localhost:~# ip -6 addr show dev ens4
root@localhost:~# ip -6 ro show dev ens4
root@localhost:~#


# No fd00::/64 routes are present in the IPv6 route table
root@localhost:~# egrep '^fd0+\ ' /proc/net/ipv6_route
root@localhost:~#


# Received on-link prefix fd00::/64 from the router
root@localhost:~# tcpdump -vi ens4 'icmp6[0] = 134'
tcpdump: listening on ens4, link-type EN10MB (Ethernet), snapshot
length 262144 bytes

20:41:57.733151 IP6 (flowlabel 0x15aa0, hlim 255, next-header ICMPv6
(58) payload length: 56) fe80::f83a:f0ff:fe69:27d2 > ip6-allnodes:
[icmp6 sum ok] ICMP6, router advertisement, length 56
        hop limit 64, Flags [none], pref low, router lifetime 0s,
reachable time 0ms, retrans timer 0ms
          prefix info option (3), length 32 (4): fd00::/64, Flags
[onlink, auto], valid time 120s, pref. time 60s
          source link-address option (1), length 8 (1):
fa:3a:f0:69:27:d2
    
        
# The RA route is installed in the ipv6_route structure with the flags
0x004c0001
# 0x4c: RTF_ADDRCONF, RTF_PREFIX_RT, and RTF_EXPIRES
root@localhost:~# egrep '^fd0+\ ' /proc/net/ipv6_route
fd000000000000000000000000000000 40 00000000000000000000000000000000 00
00000000000000000000000000000000 00000100 00000002 00000000 004c0001  
ens4


# The route has an expiration time assigned as expected
root@localhost:~# ip -6 ro show dev ens4
fd00::/64 proto kernel metric 256 expires 88sec pref medium


# Now, the manual IPv6 address from the subnet fd00::/64 is configured
on the interface
root@localhost:~# ip addr add fd00::2/64 dev ens4
root@localhost:~# ip -6 addr show dev ens4
3: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel
state UP group default qlen 1000
    altname enp0s4
    altname enx525400123457
    inet6 fd00::2/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fd00::5054:ff:fe12:3457/64 scope global dynamic mngtmpaddr
proto kernel_ra
       valid_lft 88sec preferred_lft 28sec


# The ipv6_route entry for fd00::/64 gets updated: the flags are
changed to 0x000c0001.
# 0x0c: RTF_ADDRCONF, RTF_PREFIX_RT
# The flag RTF_EXPIRES is removed but the RA-specific flags
RTF_ADDRCONF, RTF_PREFIX_RT are still set.
root@localhost:~# egrep '^fd0+\ ' /proc/net/ipv6_route
fd000000000000000000000000000000 40 00000000000000000000000000000000 00
00000000000000000000000000000000 00000100 00000001 00000000 000c0001  
ens4


# From user's perspective the on-link route looks permanent, no
expiration time is present
root@localhost:~# ip -6 ro show dev ens4
fd00::/64 proto kernel metric 256 pref medium


# Next RA packet has come at this point


# And the permanent route turned into a temporary one again
(0x004c0001)
root@localhost:~# egrep '^fd0+\ ' /proc/net/ipv6_route
fd000000000000000000000000000000 40 00000000000000000000000000000000 00
00000000000000000000000000000000 00000100 00000002 00000000 004c0001  
ens4

root@localhost:~# ip -6 ro show dev ens4
fd00::/64 proto kernel metric 256 expires 77sec pref medium


# The kernel is instructed not to accept RAs anymore
root@localhost:~# echo 0 > /proc/sys/net/ipv6/conf/ens4/accept_ra
root@localhost:~# cat /proc/sys/net/ipv6/conf/ens4/accept_ra
0


# After 2 minutes, the on-link route gets vanished
# while the manual IPv6 address is still installed on the interface
root@localhost:~# ping -Oi 10 fd00::1
PING fd00::1 (fd00::1) 56 data bytes
64 bytes from fd00::1: icmp_seq=1 ttl=64 time=0.508 ms
64 bytes from fd00::1: icmp_seq=2 ttl=64 time=1.18 ms
64 bytes from fd00::1: icmp_seq=3 ttl=64 time=0.519 ms
64 bytes from fd00::1: icmp_seq=4 ttl=64 time=0.565 ms
64 bytes from fd00::1: icmp_seq=5 ttl=64 time=0.702 ms
64 bytes from fd00::1: icmp_seq=6 ttl=64 time=0.737 ms
64 bytes from fd00::1: icmp_seq=7 ttl=64 time=1.10 ms
64 bytes from fd00::1: icmp_seq=8 ttl=64 time=0.643 ms
64 bytes from fd00::1: icmp_seq=9 ttl=64 time=0.668 ms
64 bytes from fd00::1: icmp_seq=10 ttl=64 time=0.679 ms
64 bytes from fd00::1: icmp_seq=11 ttl=64 time=0.529 ms
64 bytes from fd00::1: icmp_seq=12 ttl=64 time=1.24 ms
64 bytes from fd00::1: icmp_seq=13 ttl=64 time=0.738 ms
no answer yet for icmp_seq=14
no answer yet for icmp_seq=15

root@localhost:~# ip -6 ro show dev ens4
root@localhost:~# egrep '^fd0+\ ' /proc/net/ipv6_route
root@localhost:~#

root@localhost:~# ip -6 addr show dev ens4
3: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel
state UP group default qlen 1000
    altname enp0s4
    altname enx525400123457
    inet6 fd00::2/64 scope global
       valid_lft forever preferred_lft forever


In some environements, in which RA-sending routers are present and the
RA processing is disabled by the interface init scripts, a race
condition may lead to automatic removal of the permanent on-link
routes. For example:

1. the OS boots, RAs are accepted;
2. RA with PIO is received from router #1;
3. the kernel installs a temporary on-link route;
4. the OS's init scripts configure a manual IPv6 address;
5. the kernel removes the expiration time from the on-link route;
6. RA with PIO is received from router #2;
7. the kernel sets the expiration time to the on-link route;
8. the OS's init scripts set 'net.ipv6.conf.xxx.accept_ra = 0' for the
interface;
9. the installed IPv6 route is no longer updated by the RAs;
10. the installed IPv6 route expires after N seconds leading to IPv6
reachability issues


The problem was first noticed in a Debian 11 system running kernel
5.10.197-1. The respective bug report [1] in the upstream tracker was
created a year ago.

Thank you.

Regards,
Garri

[1] https://bugzilla.kernel.org/show_bug.cgi?id=219205


Reply to: