[systemd-devel] PATCH: Improve the reaction of IPv6 SLAAC to renumbering events

Fernando Gont fgont at si6networks.com
Sun Mar 29 21:40:10 UTC 2020


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: fgont at si6networks.com
PGP Fingerprint: 6666 31C6 D484 63B2 8FB1 E3C4 AE25 0D55 1D4E 7492






More information about the systemd-devel mailing list