IPv6 privacy extensions addresses are re-applied when network cable is unplugged

From: WGH <hidden>
Date: 2023-12-05 13:50:42

Originally discovered with systemd-networkd, and requested to be reported upstream there: https://github.com/systemd/systemd/issues/29701

These reproduction steps mention systemd-networkd, but I think it should be possible to reproduce it without it.

1. Have network with IPv6PrivacyExtensions=yes (corresponds to use_tempaddr).
2. Plug network cable.
3. Unplug network cable (putting the link down isn't sufficient, only unplugging the cable reproduces the issue)

What happens is the temporary address will be removed and immediately re-added, and will linger on the interface even though it has no cable attached.

I've debugged the issue a bit, I think the problem is as follows:

* the kernel removes the temporary address
* systemd-networkd removes the addresses it configured itself (EUI64 stable address)
* when removing said address, the kernel notices it has no temporary address configured, and re-adds it back, somehow missing the interface has no carrier anymore

Here's the kernel stack trace when address is re-added (|bpftrace -e 'kprobe:ipv6_add_addr { printf("%s\n%s\n", comm, kstack); }'|):

  systemd-network

         ipv6_add_addr+1
         ipv6_create_tempaddr.isra.0+686
         addrconf_verify_rtnl+1200
         inet6_addr_del+235
         inet6_rtm_deladdr+182
         rtnetlink_rcv_msg+355
         netlink_rcv_skb+87
         netlink_unicast+572
         netlink_sendmsg+585
         sock_sendmsg+149
         __sys_sendto+267
         __x64_sys_sendto+32
         do_syscall_64+58
         entry_SYSCALL_64_after_hwframe+9
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help