[Dnsmasq-discuss] [PATCH] radv: explicit lease time as a floor for constructed-prefix RA lifetimes
Giuseppe Piscitelli
ooonea at gmail.com
Fri Aug 7 00:16:43 UTC 2026
Hi,
on constructed prefixes (--dhcp-range=::,constructor:eth0,...) the RA
carries the residual lifetimes of the interface address, and an
explicitly configured lease time only caps them ("configured time is
ceiling" in radv.c).
Behind an upstream that delegates with very short lifetimes this
propagates the churn to every client. Starlink delegates a /56 with
about 300s valid / 150s preferred: the router refreshes forever, but a
client that sleeps through a few RAs -- every phone -- loses its
global address, and its established connections die with it. Seen live
on my LAN: phones answering on v4 and link-local while their GUA sat
FAILED in the router's neighbour cache, apps stalling mid-stream on
WiFi only.
With this patch an explicitly configured lease time on a constructed
range acts as a floor as well. Ranges without an explicit lease time
are unchanged. Deprecation still wins: a kernel-deprecated address or
a deprecated context still advertises preferred=0, and a vanished
prefix still goes through the old-prefix path, so renumbering behaves
as before.
Running in production here on 2.93 with a 12h lease on the constructed
range: clients hold 12h instead of the 300s residue and the
sleep-induced address loss is gone. The patch applies cleanly to
current master.
If changing the meaning of the existing lease-time field on
constructed ranges is not wanted, I can rework this behind a dedicated
keyword instead.
Patch inline below and attached too, in case my mailer mangles the
tabs.
ooonea
--- a/src/radv.c
+++ b/src/radv.c
@@ -608,6 +608,7 @@
int do_slaac = 0;
int deprecate = 0;
int constructed = 0;
+ int have_lease = 0;
int adv_router = 0;
int off_link = 0;
unsigned int time = 0xffffffff;
@@ -660,6 +661,8 @@
if (time < ((unsigned int)(3 * param->adv_interval)))
time = 3 * param->adv_interval;
}
+ if (context->flags & CONTEXT_SETLEASE)
+ have_lease = 1;
if (context->flags & CONTEXT_DEPRECATE)
deprecate = 1;
@@ -697,7 +700,19 @@
/* configured time is ceiling */
if (!constructed || valid > time)
valid = time;
-
+
+ /* For CONSTRUCTED prefixes an explicitly configured lease time is
+ also a floor: an upstream delegating with very short lifetimes
+ (mobile links) would otherwise churn the addresses of any client
+ that sleeps through a few RAs. Deprecation still wins below. */
+ if (constructed && have_lease && !deprecate && !(flags & IFACE_DEPRECATED))
+ {
+ if (valid < time)
+ valid = time;
+ if (preferred < time)
+ preferred = time;
+ }
+
if (flags & IFACE_DEPRECATED)
preferred = 0;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dnsmasq-constructed-ra-lifetime-floor.patch
Type: text/x-patch
Size: 1957 bytes
Desc: not available
URL: <http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/attachments/20260807/5462e859/attachment.bin>
More information about the Dnsmasq-discuss
mailing list