]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkd: RFC compliant autonomous prefix handling (#5636)
authorhendrikw01 <hendrik@gestorf.com>
Fri, 31 Mar 2017 13:10:59 +0000 (15:10 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 31 Mar 2017 13:10:59 +0000 (15:10 +0200)
Previously, `lifetime_valid` of a Router Advertisement was not handled
the way RFC4862 has specified.

In particular: Sections 5.5.3.d and  5.5.3.e

src/network/networkd-ndisc.c

index 4fd5d8ae70312fcaa49d578a3e85ed653ebe66fa..d52b511bb55c5996cf058cae04ec7b00a9845597 100644 (file)
@@ -27,6 +27,7 @@
 
 #define NDISC_DNSSL_MAX 64U
 #define NDISC_RDNSS_MAX 64U
+#define NDISC_PREFIX_LFT_MIN 7200U
 
 static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
@@ -152,13 +153,21 @@ static void ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
 
 static void ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
         _cleanup_address_free_ Address *address = NULL;
-        uint32_t lifetime_valid, lifetime_preferred;
+        Address *existing_address;
+        uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
+        usec_t time_now;
         unsigned prefixlen;
         int r;
 
         assert(link);
         assert(rt);
 
+        r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
+                return;
+        }
+
         r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
         if (r < 0) {
                 log_link_error_errno(link, r, "Failed to get prefix length: %m");
@@ -207,7 +216,24 @@ static void ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *
         address->prefixlen = prefixlen;
         address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
         address->cinfo.ifa_prefered = lifetime_preferred;
-        address->cinfo.ifa_valid = lifetime_valid;
+
+        /* see RFC4862 section 5.5.3.e */
+        r = address_get(link, address->family, &address->in_addr, address->prefixlen, &existing_address);
+        if (r > 0) {
+                lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
+                if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
+                        address->cinfo.ifa_valid = lifetime_valid;
+                else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN)
+                        address->cinfo.ifa_valid = lifetime_remaining;
+                else
+                        address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN;
+        } else if (lifetime_valid > 0)
+                address->cinfo.ifa_valid = lifetime_valid;
+        else
+                return; /* see RFC4862 section 5.5.3.d */
+
+        if (address->cinfo.ifa_valid == 0)
+                return;
 
         r = address_configure(address, link, ndisc_netlink_handler, true);
         if (r < 0) {