Folks,

IPv6 SLAAC reacts pretty badly to renumbering events -- actually, it doesn't react ;-) (The problem is described in detail here: https://tools.ietf.org/html/draft-ietf-v6ops-slaac-renum-01)

There are multiple improvements to be applied (please see: https://tools.ietf.org/html/draft-gont-6man-slaac-renum-05). This one is the long-hanging fruit: employ saner lifetimes -- that is e.g. in the case of PIOs, never prefer an address/prefix for longer than the Router Lifetime.

I compiled and tested the code. And submitted a pull request (https://github.com/systemd/systemd/pull/15260).

Thoughts?

The patch is this one, anyway:

---- cut here ----
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index fe1de6387e..e43ecaea19 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -19,6 +19,8 @@
 #define NDISC_DNSSL_MAX 64U
 #define NDISC_RDNSS_MAX 64U
 #define NDISC_PREFIX_LFT_MIN 7200U
+#define NDISC_PREFIX_LFT_MAX ((uint64_t) 0xffffffff)
+#define DFLT_VLTIME_MULT ((uint64_t) 48)

 #define DAD_CONFLICTS_IDGEN_RETRIES_RFC7217 3

@@ -344,6 +346,7 @@ static int ndisc_router_generate_addresses(Link *link, unsigned prefixlen, uint3
 }

static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
+        uint16_t router_lifetime;
         uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
         _cleanup_set_free_free_ Set *addresses = NULL;
         _cleanup_(address_freep) Address *address = NULL;
@@ -368,10 +371,19 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
         if (r < 0)
return log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");

+        r = sd_ndisc_router_get_lifetime(rt, &router_lifetime);
+        if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to get gateway lifetime from RA: %m");
+
+        if(router_lifetime * DFLT_VLTIME_MULT < NDISC_PREFIX_LFT_MAX)
+ lifetime_valid = MIN(lifetime_valid, router_lifetime * DFLT_VLTIME_MULT);
+
r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred);
         if (r < 0)
return log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");

+        lifetime_preferred = MIN(lifetime_preferred, router_lifetime);
+
/* The preferred lifetime is never greater than the valid lifetime */
         if (lifetime_preferred > lifetime_valid)
                 return 0;
@@ -425,6 +437,7 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
         _cleanup_(route_freep) Route *route = NULL;
         usec_t time_now;
+        uint16_t router_lifetime;
         uint32_t lifetime;
         unsigned prefixlen;
         int r;
@@ -444,6 +457,16 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
         if (r < 0)
return log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");

+        r = sd_ndisc_router_get_lifetime(rt, &router_lifetime);
+        if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to get gateway lifetime from RA: %m");
+
+ /* On-link prefix Valid Lifetimes are capped to Router Lifetime * DFLT_VLTIME_MULT.
+           See draft-gont-6man-slaac-renum
+         */
+        if(router_lifetime * DFLT_VLTIME_MULT < NDISC_PREFIX_LFT_MAX)
+ lifetime = MIN(lifetime, router_lifetime * DFLT_VLTIME_MULT);
+
         r = route_new(&route);
         if (r < 0)
return log_link_error_errno(link, r, "Could not allocate route: %m"); @@ -477,6 +500,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
         struct in6_addr gateway;
         uint32_t lifetime;
         unsigned preference, prefixlen;
+        uint16_t router_lifetime;
         usec_t time_now;
         int r;

@@ -486,6 +510,13 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
         if (r < 0)
return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");

+        r = sd_ndisc_router_get_lifetime(rt, &router_lifetime);
+        if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to get gateway lifetime from RA: %m");
+
+ /* Route Lifetimes are capped to Router Lifetime. See draft-gont-6man-slaac-renum */
+        lifetime = MIN(lifetime, router_lifetime);
+
         if (lifetime == 0)
                 return 0;

---- cut here ----

Patch also available at: https://www.gont.com.ar/code/patch-fgont-systemd-networkd-cap-lifetimes.txt

Thanks!

Cheers,
--
Fernando Gont
SI6 Networks
e-mail: fg...@si6networks.com
PGP Fingerprint: 6666 31C6 D484 63B2 8FB1 E3C4 AE25 0D55 1D4E 7492




_______________________________________________
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/systemd-devel

Reply via email to