Re: [PATCH 1/2 net] ipv6: addrconf: fix temp address generation after prefix deprecation

Fernando Fernandez Mancera
2026-05-04T19:52:09Z

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
>>