The question posed to mine bad self was:
How long does a deprecated IPv6 address remain attached to an interface?
You may already know the answer. But in case you don't...
I packed a bag full of things I'd need - crab paste sandwiches, weak lemon drink, a compass, silk stockings and a plastic carrot - and set off on my journey through the Googles, a bit of oxygen but mainly laughing gas in my lungs.
My first stop, and first sip of weak lemon drink, was at an Oracle manpage:
An IPv6 deprecated address will eventually be deleted when not used,
Excellent! But when?
My next stop pointed out the bleeding obvious (good, old Wiki):
When an address is assigned to an interface it gets the status "preferred", which it holds during its preferred-lifetime. After that lifetime expires the status becomes "deprecated" and no new connections should be made using this address. The address becomes "invalid" after its valid-lifetime also expires
Er, yeah, that actually makes sense. Indeed:
$ ip addr | fgrep -A 1 temporary
inet6 fd3c:c307:7f95:0:6957:dcf5:f759:e2e9/64 scope global temporary dynamic
valid_lft 575828sec preferred_lft 56828sec
inet6 fd3c:c307:7f95:0:d5b5:b1d0:a807:21a9/64 scope global temporary deprecated dynamic
valid_lft 490031sec preferred_lft 0sec
inet6 fd3c:c307:7f95:0:10d:8171:ff7f:777f/64 scope global temporary deprecated dynamic
valid_lft 404233sec preferred_lft 0sec
inet6 fd3c:c307:7f95:0:4dc0:7c07:c401:490b/64 scope global temporary deprecated dynamic
valid_lft 318436sec preferred_lft 0sec
inet6 fd3c:c307:7f95:0:6957:dcf5:f759:e2e9/64 scope global temporary dynamic
valid_lft 575828sec preferred_lft 56828sec
inet6 fd3c:c307:7f95:0:d5b5:b1d0:a807:21a9/64 scope global temporary deprecated dynamic
valid_lft 490031sec preferred_lft 0sec
inet6 fd3c:c307:7f95:0:10d:8171:ff7f:777f/64 scope global temporary deprecated dynamic
valid_lft 404233sec preferred_lft 0sec
inet6 fd3c:c307:7f95:0:4dc0:7c07:c401:490b/64 scope global temporary deprecated dynamic
valid_lft 318436sec preferred_lft 0sec
When valid_lft = 0 then it's curtains for that address. The default on my computer seems to be to set a valid_lft = 604800 (7 days) that is seven times the preferred_lft = 86400 (24 hours). Not a massive deal but it does mean that after seven days I'd have six or seven deprecated ULA addresses hanging around per interface, and eventually another six or seven deprecated global unicast addresses per interface too, assuming privacy extensions are enabled. Messy.
I know, I know, I can disable ULA if I want to. But I don't want to. So that's that solved.
There is a max_addresses parameter (default 16). I tried to find out if the system would remove the old deprecated addresses or report a failure when this limit is reached, but the bloody stupid thing gave up long before I got near this limit and removed all deprecated addresses far too early, and refused to create more ULAs.. I may visit this again sometime. Of course with this default of 16 I could easily exceed this limit assuming two routers with two global IPv6 addresses are reachable via one NIC, and ULA is enabled - easily achievable using fibre and LTE on one router, for example.
RFC 4862 talks about how deprecated and invalid addresses should be treated but doesn't mention when the node should simply drop the address altogether. It makes sense for an operating system to simply rid itself of the burden as soon as the address has expired.
You may now enjoy the crab paste and put the plastic carrot to good use.
For reference (at time of writing):
valid_lft and preferred_lft can be set/queried in Linux at /proc/sys/net/ipv6/conf/default/temp_valid_lft and /proc/sys/net/ipv6/conf/default/temp_preferred_lft, respectively:
$ cat /proc/sys/net/ipv6/conf/default/temp_*
86400
604800
86400
604800