* [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation
@ 2026-05-03 22:11 Fernando Fernandez Mancera
2026-05-03 22:11 ` [PATCH 2/2 net] selftests: fib_tests: add temporary IPv6 address renewal test Fernando Fernandez Mancera
2026-05-04 16:35 ` [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation Ido Schimmel
0 siblings, 2 replies; 7+ messages in thread
From: Fernando Fernandez Mancera @ 2026-05-03 22:11 UTC (permalink / raw)
To: netdev
Cc: linux-kselftest, horms, pabeni, kuba, edumazet, davem, idosch,
dsahern, Fernando Fernandez Mancera, Łukasz Stelmach
When a router temporarily deprecates an IPv6 prefix (either by sending a
Router Advertisement with Preferred Lifetime = 0 or by letting the
lifetime expire) and later restores it, the kernel permanently loses its
ability to generate temporary privacy addresses (RFC 8981) for that
prefix.
This happens because the address worker attempts to generate a
replacement temporary address when the current one nears expiration. As
the base prefix is deprecated already, the generation fails, burning the
retry counter for temporary address generation of that prefix.
When the router eventually restores the prefix, the temporary address
becomes active again. However, once it naturally expires, the kernel
sees the exhausted retry limit and permanently stops generating new
privacy addresses.
Fix this by verifying that the base prefix has sufficient preferred
lifetime remaining before attempting to generate a new temporary
address. This prevents the worker from burning through its retry counter
during temporary network deprecation events like a router reboot.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: Łukasz Stelmach <steelman@post.pl>
Closes: https://lore.kernel.org/netdev/87340td30q.fsf%25steelman@post.pl/
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
---
net/ipv6/addrconf.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 5476b6536eb7..f6a3d9da3cb1 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -4654,9 +4654,11 @@ static void addrconf_verify_rtnl(struct net *net)
!ifp->regen_count && ifp->ifpub) {
/* This is a non-regenerated temporary addr. */
+ unsigned long pub_age = (now - READ_ONCE(ifp->ifpub->tstamp)) / HZ;
unsigned long regen_advance = ipv6_get_regen_advance(ifp->idev);
- if (age + regen_advance >= ifp->prefered_lft) {
+ if (age + regen_advance >= ifp->prefered_lft &&
+ pub_age + regen_advance < READ_ONCE(ifp->ifpub->prefered_lft)) {
struct inet6_ifaddr *ifpub = ifp->ifpub;
if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
next = ifp->tstamp + ifp->prefered_lft * HZ;
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/2 net] selftests: fib_tests: add temporary IPv6 address renewal test
2026-05-03 22:11 [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation Fernando Fernandez Mancera
@ 2026-05-03 22:11 ` Fernando Fernandez Mancera
2026-05-04 16:41 ` Ido Schimmel
2026-05-04 16:35 ` [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation Ido Schimmel
1 sibling, 1 reply; 7+ messages in thread
From: Fernando Fernandez Mancera @ 2026-05-03 22:11 UTC (permalink / raw)
To: netdev
Cc: linux-kselftest, horms, pabeni, kuba, edumazet, davem, idosch,
dsahern, Fernando Fernandez Mancera
Add a test to check that temporary IPv6 address is regenerated properly
after the base prefix is deprecated and restored.
Fib6 temporary address renewal test
TEST: IPv6 temporary address cleanly deprecated and regenerated [ OK ]
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
---
tools/testing/selftests/net/fib_tests.sh | 55 +++++++++++++++++++++++-
1 file changed, 54 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh
index af64f93bb2e1..6a6e545cb40d 100755
--- a/tools/testing/selftests/net/fib_tests.sh
+++ b/tools/testing/selftests/net/fib_tests.sh
@@ -12,7 +12,7 @@ TESTS="unregister down carrier nexthop suppress ipv6_notify ipv4_notify \
ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr \
ipv6_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh fib6_gc_test \
ipv4_mpath_list ipv6_mpath_list ipv4_mpath_balance ipv6_mpath_balance \
- ipv4_mpath_balance_preferred fib6_ra_to_static"
+ ipv4_mpath_balance_preferred fib6_ra_to_static fib6_temp_addr_renewal"
VERBOSE=0
PAUSE_ON_FAIL=no
@@ -1611,6 +1611,58 @@ fib6_ra_to_static()
cleanup &> /dev/null
}
+fib6_temp_addr_renewal() {
+ setup
+
+ echo
+ echo "Fib6 temporary address renewal test"
+ set -e
+
+ # ra6 is required for the test. (ipv6toolkit)
+ if [ ! -x "$(command -v ra6)" ]; then
+ echo "SKIP: ra6 not found."
+ set +e
+ cleanup &> /dev/null
+ return
+ fi
+
+ # Create a pair of veth devices to send a RA message from one
+ # device to another.
+ $IP link add veth1 type veth peer name veth2
+ $IP link set dev veth1 up
+ $IP link set dev veth2 up
+
+ # Make veth1 ready to receive RA messages.
+ $NS_EXEC sysctl -wq net.ipv6.conf.veth1.accept_ra=2
+ $NS_EXEC sysctl -wq net.ipv6.conf.veth1.use_tempaddr=2
+ $NS_EXEC sysctl -wq net.ipv6.conf.veth1.temp_prefered_lft=15
+ $NS_EXEC sysctl -wq net.ipv6.conf.veth1.max_desync_factor=0
+
+ # Send a RA message with a prefix from veth2.
+ $NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#3600 -e
+ sleep 2
+
+ # Deprecate it
+ $NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#0 -e
+ sleep 2
+
+ # Restore it
+ $NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#3600 -e
+
+ ret=1
+ for i in $(seq 1 25); do
+ sleep 1
+ num_dep="$($IP -6 addr | grep -c "temporary deprecated" || true)"
+ num_tot="$($IP -6 addr | grep -c "temporary" || true)"
+
+ if [ "$num_dep" -eq 1 ] && [ "$num_tot" -ge 2 ]; then
+ ret=0
+ break
+ fi
+ done
+ log_test "$ret" 0 "IPv6 temporary address cleanly deprecated and regenerated"
+}
+
# add route for a prefix, flushing any existing routes first
# expected to be the first step of a test
add_route()
@@ -3002,6 +3054,7 @@ do
ipv6_mpath_balance) ipv6_mpath_balance_test;;
ipv4_mpath_balance_preferred) ipv4_mpath_balance_preferred_test;;
fib6_ra_to_static) fib6_ra_to_static;;
+ fib6_temp_addr_renewal) fib6_temp_addr_renewal;;
help) echo "Test names: $TESTS"; exit 0;;
esac
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation
2026-05-03 22:11 [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation Fernando Fernandez Mancera
2026-05-03 22:11 ` [PATCH 2/2 net] selftests: fib_tests: add temporary IPv6 address renewal test Fernando Fernandez Mancera
@ 2026-05-04 16:35 ` Ido Schimmel
2026-05-04 19:51 ` Fernando Fernandez Mancera
1 sibling, 1 reply; 7+ messages in thread
From: Ido Schimmel @ 2026-05-04 16:35 UTC (permalink / raw)
To: Fernando Fernandez Mancera
Cc: netdev, linux-kselftest, horms, pabeni, kuba, edumazet, davem,
dsahern, Łukasz Stelmach
On Mon, May 04, 2026 at 12:11:40AM +0200, Fernando Fernandez Mancera wrote:
> When a router temporarily deprecates an IPv6 prefix (either by sending a
> Router Advertisement with Preferred Lifetime = 0 or by letting the
> lifetime expire) and later restores it, the kernel permanently loses its
> ability to generate temporary privacy addresses (RFC 8981) for that
> prefix.
>
> This happens because the address worker attempts to generate a
> replacement temporary address when the current one nears expiration. As
> the base prefix is deprecated already, the generation fails, burning the
> retry counter for temporary address generation of that prefix.
>
> When the router eventually restores the prefix, the temporary address
> becomes active again. However, once it naturally expires, the kernel
> sees the exhausted retry limit and permanently stops generating new
> privacy addresses.
It's not clear to me to which "retry counter" you are referring to. Are
you referring to the counter of the temporary address or to that of the
"public address" from which it was generated?
AFAICT, in the case of temporary addresses (those w/o "mngtmpaddr") this
isn't really a counter, but a boolean that tells you if an address was
already spawned from this address.
>
> Fix this by verifying that the base prefix has sufficient preferred
> lifetime remaining before attempting to generate a new temporary
> address. This prevents the worker from burning through its retry counter
> during temporary network deprecation events like a router reboot.
Again, I think that "retry counter" here is confusing. IIUC, what
happens is that the kernel marks the temporary address as having spawned
an address ('ifp->regen_count++'), then tries to spawn an address by
calling ipv6_create_tempaddr(), which fails because the preferred
lifetime of the public address is 0.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reported-by: Łukasz Stelmach <steelman@post.pl>
> Closes: https://lore.kernel.org/netdev/87340td30q.fsf%25steelman@post.pl/
> Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
> ---
> net/ipv6/addrconf.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index 5476b6536eb7..f6a3d9da3cb1 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -4654,9 +4654,11 @@ static void addrconf_verify_rtnl(struct net *net)
> !ifp->regen_count && ifp->ifpub) {
> /* This is a non-regenerated temporary addr. */
>
> + unsigned long pub_age = (now - READ_ONCE(ifp->ifpub->tstamp)) / HZ;
> unsigned long regen_advance = ipv6_get_regen_advance(ifp->idev);
>
> - if (age + regen_advance >= ifp->prefered_lft) {
> + if (age + regen_advance >= ifp->prefered_lft &&
> + pub_age + regen_advance < READ_ONCE(ifp->ifpub->prefered_lft)) {
> struct inet6_ifaddr *ifpub = ifp->ifpub;
> if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
> next = ifp->tstamp + ifp->prefered_lft * HZ;
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2 net] selftests: fib_tests: add temporary IPv6 address renewal test
2026-05-03 22:11 ` [PATCH 2/2 net] selftests: fib_tests: add temporary IPv6 address renewal test Fernando Fernandez Mancera
@ 2026-05-04 16:41 ` Ido Schimmel
2026-05-04 19:45 ` Fernando Fernandez Mancera
0 siblings, 1 reply; 7+ messages in thread
From: Ido Schimmel @ 2026-05-04 16:41 UTC (permalink / raw)
To: Fernando Fernandez Mancera
Cc: netdev, linux-kselftest, horms, pabeni, kuba, edumazet, davem,
dsahern
On Mon, May 04, 2026 at 12:11:41AM +0200, Fernando Fernandez Mancera wrote:
> Add a test to check that temporary IPv6 address is regenerated properly
> after the base prefix is deprecated and restored.
>
> Fib6 temporary address renewal test
> TEST: IPv6 temporary address cleanly deprecated and regenerated [ OK ]
Thanks for the test, but I reverted the fix and it still passes :(
>
> Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
> ---
> tools/testing/selftests/net/fib_tests.sh | 55 +++++++++++++++++++++++-
> 1 file changed, 54 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh
> index af64f93bb2e1..6a6e545cb40d 100755
> --- a/tools/testing/selftests/net/fib_tests.sh
> +++ b/tools/testing/selftests/net/fib_tests.sh
> @@ -12,7 +12,7 @@ TESTS="unregister down carrier nexthop suppress ipv6_notify ipv4_notify \
> ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr \
> ipv6_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh fib6_gc_test \
> ipv4_mpath_list ipv6_mpath_list ipv4_mpath_balance ipv6_mpath_balance \
> - ipv4_mpath_balance_preferred fib6_ra_to_static"
> + ipv4_mpath_balance_preferred fib6_ra_to_static fib6_temp_addr_renewal"
>
> VERBOSE=0
> PAUSE_ON_FAIL=no
> @@ -1611,6 +1611,58 @@ fib6_ra_to_static()
> cleanup &> /dev/null
> }
>
> +fib6_temp_addr_renewal() {
> + setup
> +
> + echo
> + echo "Fib6 temporary address renewal test"
> + set -e
> +
> + # ra6 is required for the test. (ipv6toolkit)
> + if [ ! -x "$(command -v ra6)" ]; then
> + echo "SKIP: ra6 not found."
> + set +e
> + cleanup &> /dev/null
> + return
> + fi
> +
> + # Create a pair of veth devices to send a RA message from one
> + # device to another.
> + $IP link add veth1 type veth peer name veth2
> + $IP link set dev veth1 up
> + $IP link set dev veth2 up
> +
> + # Make veth1 ready to receive RA messages.
> + $NS_EXEC sysctl -wq net.ipv6.conf.veth1.accept_ra=2
> + $NS_EXEC sysctl -wq net.ipv6.conf.veth1.use_tempaddr=2
> + $NS_EXEC sysctl -wq net.ipv6.conf.veth1.temp_prefered_lft=15
> + $NS_EXEC sysctl -wq net.ipv6.conf.veth1.max_desync_factor=0
> +
> + # Send a RA message with a prefix from veth2.
> + $NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#3600 -e
> + sleep 2
> +
> + # Deprecate it
> + $NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#0 -e
> + sleep 2
> +
> + # Restore it
> + $NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#3600 -e
> +
> + ret=1
> + for i in $(seq 1 25); do
> + sleep 1
> + num_dep="$($IP -6 addr | grep -c "temporary deprecated" || true)"
> + num_tot="$($IP -6 addr | grep -c "temporary" || true)"
> +
> + if [ "$num_dep" -eq 1 ] && [ "$num_tot" -ge 2 ]; then
> + ret=0
> + break
> + fi
> + done
> + log_test "$ret" 0 "IPv6 temporary address cleanly deprecated and regenerated"
Missing:
set +e
cleanup &> /dev/null
Like in fib6_ra_to_static() and the skip path?
> +}
> +
> # add route for a prefix, flushing any existing routes first
> # expected to be the first step of a test
> add_route()
> @@ -3002,6 +3054,7 @@ do
> ipv6_mpath_balance) ipv6_mpath_balance_test;;
> ipv4_mpath_balance_preferred) ipv4_mpath_balance_preferred_test;;
> fib6_ra_to_static) fib6_ra_to_static;;
> + fib6_temp_addr_renewal) fib6_temp_addr_renewal;;
>
> help) echo "Test names: $TESTS"; exit 0;;
> esac
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2 net] selftests: fib_tests: add temporary IPv6 address renewal test
2026-05-04 16:41 ` Ido Schimmel
@ 2026-05-04 19:45 ` Fernando Fernandez Mancera
0 siblings, 0 replies; 7+ messages in thread
From: Fernando Fernandez Mancera @ 2026-05-04 19:45 UTC (permalink / raw)
To: Ido Schimmel
Cc: netdev, linux-kselftest, horms, pabeni, kuba, edumazet, davem,
dsahern
On 5/4/26 6:41 PM, Ido Schimmel wrote:
> On Mon, May 04, 2026 at 12:11:41AM +0200, Fernando Fernandez Mancera wrote:
>> Add a test to check that temporary IPv6 address is regenerated properly
>> after the base prefix is deprecated and restored.
>>
>> Fib6 temporary address renewal test
>> TEST: IPv6 temporary address cleanly deprecated and regenerated [ OK ]
>
> Thanks for the test, but I reverted the fix and it still passes :(
>
Ugh sorry for that. I lowered the sleep time so it takes less time to
run and I messed up the test. It seems 2 seconds isn't enough and to
reliable reproduce it, 3 seconds are required.
I am reposting with the test fixed, sorry again for the noise.
>>
>> Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
>> ---
>> tools/testing/selftests/net/fib_tests.sh | 55 +++++++++++++++++++++++-
>> 1 file changed, 54 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh
>> index af64f93bb2e1..6a6e545cb40d 100755
>> --- a/tools/testing/selftests/net/fib_tests.sh
>> +++ b/tools/testing/selftests/net/fib_tests.sh
>> @@ -12,7 +12,7 @@ TESTS="unregister down carrier nexthop suppress ipv6_notify ipv4_notify \
>> ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr \
>> ipv6_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh fib6_gc_test \
>> ipv4_mpath_list ipv6_mpath_list ipv4_mpath_balance ipv6_mpath_balance \
>> - ipv4_mpath_balance_preferred fib6_ra_to_static"
>> + ipv4_mpath_balance_preferred fib6_ra_to_static fib6_temp_addr_renewal"
>>
>> VERBOSE=0
>> PAUSE_ON_FAIL=no
>> @@ -1611,6 +1611,58 @@ fib6_ra_to_static()
>> cleanup &> /dev/null
>> }
>>
>> +fib6_temp_addr_renewal() {
>> + setup
>> +
>> + echo
>> + echo "Fib6 temporary address renewal test"
>> + set -e
>> +
>> + # ra6 is required for the test. (ipv6toolkit)
>> + if [ ! -x "$(command -v ra6)" ]; then
>> + echo "SKIP: ra6 not found."
>> + set +e
>> + cleanup &> /dev/null
>> + return
>> + fi
>> +
>> + # Create a pair of veth devices to send a RA message from one
>> + # device to another.
>> + $IP link add veth1 type veth peer name veth2
>> + $IP link set dev veth1 up
>> + $IP link set dev veth2 up
>> +
>> + # Make veth1 ready to receive RA messages.
>> + $NS_EXEC sysctl -wq net.ipv6.conf.veth1.accept_ra=2
>> + $NS_EXEC sysctl -wq net.ipv6.conf.veth1.use_tempaddr=2
>> + $NS_EXEC sysctl -wq net.ipv6.conf.veth1.temp_prefered_lft=15
>> + $NS_EXEC sysctl -wq net.ipv6.conf.veth1.max_desync_factor=0
>> +
>> + # Send a RA message with a prefix from veth2.
>> + $NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#3600 -e
>> + sleep 2
>> +
>> + # Deprecate it
>> + $NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#0 -e
>> + sleep 2
>> +
>> + # Restore it
>> + $NS_EXEC ra6 -i veth2 -s fe80::1 -d ff02::1 -P 2001:12::/64\#LA\#3600\#3600 -e
>> +
>> + ret=1
>> + for i in $(seq 1 25); do
>> + sleep 1
>> + num_dep="$($IP -6 addr | grep -c "temporary deprecated" || true)"
>> + num_tot="$($IP -6 addr | grep -c "temporary" || true)"
>> +
>> + if [ "$num_dep" -eq 1 ] && [ "$num_tot" -ge 2 ]; then
>> + ret=0
>> + break
>> + fi
>> + done
>> + log_test "$ret" 0 "IPv6 temporary address cleanly deprecated and regenerated"
>
> Missing:
>
> set +e
>
> cleanup &> /dev/null
>
> Like in fib6_ra_to_static() and the skip path?
Oops, thanks!
>
>> +}
>> +
>> # add route for a prefix, flushing any existing routes first
>> # expected to be the first step of a test
>> add_route()
>> @@ -3002,6 +3054,7 @@ do
>> ipv6_mpath_balance) ipv6_mpath_balance_test;;
>> ipv4_mpath_balance_preferred) ipv4_mpath_balance_preferred_test;;
>> fib6_ra_to_static) fib6_ra_to_static;;
>> + fib6_temp_addr_renewal) fib6_temp_addr_renewal;;
>>
>> help) echo "Test names: $TESTS"; exit 0;;
>> esac
>> --
>> 2.53.0
>>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation
2026-05-04 16:35 ` [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation Ido Schimmel
@ 2026-05-04 19:51 ` Fernando Fernandez Mancera
2026-05-04 22:58 ` Fernando Fernandez Mancera
0 siblings, 1 reply; 7+ messages in thread
From: Fernando Fernandez Mancera @ 2026-05-04 19:51 UTC (permalink / raw)
To: Ido Schimmel
Cc: netdev, linux-kselftest, horms, pabeni, kuba, edumazet, davem,
dsahern, Łukasz Stelmach
On 5/4/26 6:35 PM, Ido Schimmel wrote:
> On Mon, May 04, 2026 at 12:11:40AM +0200, Fernando Fernandez Mancera wrote:
>> When a router temporarily deprecates an IPv6 prefix (either by sending a
>> Router Advertisement with Preferred Lifetime = 0 or by letting the
>> lifetime expire) and later restores it, the kernel permanently loses its
>> ability to generate temporary privacy addresses (RFC 8981) for that
>> prefix.
>>
>> This happens because the address worker attempts to generate a
>> replacement temporary address when the current one nears expiration. As
>> the base prefix is deprecated already, the generation fails, burning the
>> retry counter for temporary address generation of that prefix.
>>
>> When the router eventually restores the prefix, the temporary address
>> becomes active again. However, once it naturally expires, the kernel
>> sees the exhausted retry limit and permanently stops generating new
>> privacy addresses.
>
> It's not clear to me to which "retry counter" you are referring to. Are
> you referring to the counter of the temporary address or to that of the
> "public address" from which it was generated?
>
> AFAICT, in the case of temporary addresses (those w/o "mngtmpaddr") this
> isn't really a counter, but a boolean that tells you if an address was
> already spawned from this address.
>
>>
>> Fix this by verifying that the base prefix has sufficient preferred
>> lifetime remaining before attempting to generate a new temporary
>> address. This prevents the worker from burning through its retry counter
>> during temporary network deprecation events like a router reboot.
>
> Again, I think that "retry counter" here is confusing. IIUC, what
> happens is that the kernel marks the temporary address as having spawned
> an address ('ifp->regen_count++'), then tries to spawn an address by
> calling ipv6_create_tempaddr(), which fails because the preferred
> lifetime of the public address is 0.
>
Yes, you are right. I used the word counter as the variable was
ifp->regen_count although for temporary addresses it is just a boolean.
Let me modify the commit message to make it clear.
Thanks Ido for reviewing!
>>
>> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
>> Reported-by: Łukasz Stelmach <steelman@post.pl>
>> Closes: https://lore.kernel.org/netdev/87340td30q.fsf%25steelman@post.pl/
>> Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
>> ---
>> net/ipv6/addrconf.c | 4 +++-
>> 1 file changed, 3 insertions(+), 1 deletion(-)
>>
>> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
>> index 5476b6536eb7..f6a3d9da3cb1 100644
>> --- a/net/ipv6/addrconf.c
>> +++ b/net/ipv6/addrconf.c
>> @@ -4654,9 +4654,11 @@ static void addrconf_verify_rtnl(struct net *net)
>> !ifp->regen_count && ifp->ifpub) {
>> /* This is a non-regenerated temporary addr. */
>>
>> + unsigned long pub_age = (now - READ_ONCE(ifp->ifpub->tstamp)) / HZ;
>> unsigned long regen_advance = ipv6_get_regen_advance(ifp->idev);
>>
>> - if (age + regen_advance >= ifp->prefered_lft) {
>> + if (age + regen_advance >= ifp->prefered_lft &&
>> + pub_age + regen_advance < READ_ONCE(ifp->ifpub->prefered_lft)) {
>> struct inet6_ifaddr *ifpub = ifp->ifpub;
>> if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
>> next = ifp->tstamp + ifp->prefered_lft * HZ;
>> --
>> 2.53.0
>>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation
2026-05-04 19:51 ` Fernando Fernandez Mancera
@ 2026-05-04 22:58 ` Fernando Fernandez Mancera
0 siblings, 0 replies; 7+ messages in thread
From: Fernando Fernandez Mancera @ 2026-05-04 22:58 UTC (permalink / raw)
To: Ido Schimmel
Cc: netdev, linux-kselftest, horms, pabeni, kuba, edumazet, davem,
dsahern, Łukasz Stelmach
On 5/4/26 9:51 PM, Fernando Fernandez Mancera wrote:
> On 5/4/26 6:35 PM, Ido Schimmel wrote:
>> On Mon, May 04, 2026 at 12:11:40AM +0200, Fernando Fernandez Mancera
>> wrote:
>>> When a router temporarily deprecates an IPv6 prefix (either by sending a
>>> Router Advertisement with Preferred Lifetime = 0 or by letting the
>>> lifetime expire) and later restores it, the kernel permanently loses its
>>> ability to generate temporary privacy addresses (RFC 8981) for that
>>> prefix.
>>>
>>> This happens because the address worker attempts to generate a
>>> replacement temporary address when the current one nears expiration. As
>>> the base prefix is deprecated already, the generation fails, burning the
>>> retry counter for temporary address generation of that prefix.
>>>
>>> When the router eventually restores the prefix, the temporary address
>>> becomes active again. However, once it naturally expires, the kernel
>>> sees the exhausted retry limit and permanently stops generating new
>>> privacy addresses.
>>
>> It's not clear to me to which "retry counter" you are referring to. Are
>> you referring to the counter of the temporary address or to that of the
>> "public address" from which it was generated?
>>
>> AFAICT, in the case of temporary addresses (those w/o "mngtmpaddr") this
>> isn't really a counter, but a boolean that tells you if an address was
>> already spawned from this address.
>>
>>>
>>> Fix this by verifying that the base prefix has sufficient preferred
>>> lifetime remaining before attempting to generate a new temporary
>>> address. This prevents the worker from burning through its retry counter
>>> during temporary network deprecation events like a router reboot.
>>
>> Again, I think that "retry counter" here is confusing. IIUC, what
>> happens is that the kernel marks the temporary address as having spawned
>> an address ('ifp->regen_count++'), then tries to spawn an address by
>> calling ipv6_create_tempaddr(), which fails because the preferred
>> lifetime of the public address is 0.
>>
>
> Yes, you are right. I used the word counter as the variable was ifp-
> >regen_count although for temporary addresses it is just a boolean. Let
> me modify the commit message to make it clear.
>
> Thanks Ido for reviewing!
>
I have checked sashiko feedback and it spotted another race condition.
To fix this altogether I believe we could improve ipv6_create_tempaddr()
to return meaningful return value. This way we could catch a
-ETIME/-ETIMEDOUT and reset the regen_count on the temporary address.
https://sashiko.dev/#/patchset/20260503221139.3742-3-fmancera%40suse.de?part=1
>>>
>>> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
>>> Reported-by: Łukasz Stelmach <steelman@post.pl>
>>> Closes: https://lore.kernel.org/
>>> netdev/87340td30q.fsf%25steelman@post.pl/
>>> Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
>>> ---
>>> net/ipv6/addrconf.c | 4 +++-
>>> 1 file changed, 3 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
>>> index 5476b6536eb7..f6a3d9da3cb1 100644
>>> --- a/net/ipv6/addrconf.c
>>> +++ b/net/ipv6/addrconf.c
>>> @@ -4654,9 +4654,11 @@ static void addrconf_verify_rtnl(struct net *net)
>>> !ifp->regen_count && ifp->ifpub) {
>>> /* This is a non-regenerated temporary addr. */
>>> + unsigned long pub_age = (now - READ_ONCE(ifp->ifpub-
>>> >tstamp)) / HZ;
>>> unsigned long regen_advance =
>>> ipv6_get_regen_advance(ifp->idev);
>>> - if (age + regen_advance >= ifp->prefered_lft) {
>>> + if (age + regen_advance >= ifp->prefered_lft &&
>>> + pub_age + regen_advance < READ_ONCE(ifp->ifpub-
>>> >prefered_lft)) {
>>> struct inet6_ifaddr *ifpub = ifp->ifpub;
>>> if (time_before(ifp->tstamp + ifp->prefered_lft
>>> * HZ, next))
>>> next = ifp->tstamp + ifp->prefered_lft * HZ;
>>> --
>>> 2.53.0
>>>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-05-04 22:58 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-03 22:11 [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation Fernando Fernandez Mancera
2026-05-03 22:11 ` [PATCH 2/2 net] selftests: fib_tests: add temporary IPv6 address renewal test Fernando Fernandez Mancera
2026-05-04 16:41 ` Ido Schimmel
2026-05-04 19:45 ` Fernando Fernandez Mancera
2026-05-04 16:35 ` [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation Ido Schimmel
2026-05-04 19:51 ` Fernando Fernandez Mancera
2026-05-04 22:58 ` Fernando Fernandez Mancera
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox