]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
radv: Add prefixes with dynamically updated lifetimes
authorPatrik Flykt <patrik.flykt@linux.intel.com>
Thu, 4 Jan 2018 13:11:55 +0000 (15:11 +0200)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Thu, 4 Jan 2018 13:22:44 +0000 (15:22 +0200)
Add a boolean that indicates whether the prefixes will always exist
or if they will time out after the assigned valid lifetime. In the
latter case calculate the expiry times for both preferred and valid
lifetimes for the prefixes, and decrease the remaining lifetimes
each time when a Router Advertisement is sent.

Should the prefix be updated, re-calculate the prefix lifetime. When
updating, update the existing entry, if any, with the lifetimes of
the added entry as the existing entry has its lifetimes set
according to its previously calculated expiry times.

src/libsystemd-network/radv-internal.h
src/libsystemd-network/sd-radv.c
src/libsystemd-network/test-ndisc-ra.c
src/network/networkd-radv.c
src/systemd/sd-radv.h

index 441939b71758917b17ab2f1402142b042fd612a9..837e7f260344daba7d9f6c15372881a834091942 100644 (file)
@@ -93,6 +93,9 @@ struct sd_radv_prefix {
         } _packed_ opt;
 
         LIST_FIELDS(struct sd_radv_prefix, prefix);
+
+        usec_t valid_until;
+        usec_t preferred_until;
 };
 
 #define log_radv_full(level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "RADV: " fmt, ##__VA_ARGS__)
index 46704acdefecda888b45adee09d4da0f61d54a8b..169278d5e3695a174d62fb586117d307c803e1d7 100644 (file)
@@ -169,6 +169,12 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst,
                 .msg_namelen = sizeof(dst_addr),
                 .msg_iov = iov,
         };
+        usec_t time_now;
+        int r;
+
+        r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
+        if (r < 0)
+                return r;
 
         if (dst && !in_addr_is_null(AF_INET6, (union in_addr_union*) dst))
                 dst_addr.sin6_addr = *dst;
@@ -198,6 +204,18 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst,
         }
 
         LIST_FOREACH(prefix, p, ra->prefixes) {
+                if (p->valid_until) {
+
+                        if (time_now > p->valid_until)
+                                p->opt.valid_lifetime = 0;
+                        else
+                                p->opt.valid_lifetime = htobe32((p->valid_until - time_now) / USEC_PER_SEC);
+
+                        if (time_now > p->preferred_until)
+                                p->opt.preferred_lifetime = 0;
+                        else
+                                p->opt.preferred_lifetime = htobe32((p->preferred_until - time_now) / USEC_PER_SEC);
+                }
                 iov[msg.msg_iovlen].iov_base = &p->opt;
                 iov[msg.msg_iovlen].iov_len = sizeof(p->opt);
                 msg.msg_iovlen++;
@@ -518,9 +536,13 @@ _public_ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
         return r;
 }
 
-_public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
+_public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, bool dynamic) {
         sd_radv_prefix *cur;
+        int r;
         _cleanup_free_ char *addr_p = NULL;
+        char time_string_preferred[FORMAT_TIMESPAN_MAX];
+        char time_string_valid[FORMAT_TIMESPAN_MAX];
+        usec_t time_now, valid, preferred, valid_until, preferred_until;
 
         assert_return(ra, -EINVAL);
 
@@ -528,7 +550,6 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
                 return -EINVAL;
 
         LIST_FOREACH(prefix, cur, ra->prefixes) {
-                int r;
 
                 r = in_addr_prefix_intersect(AF_INET6,
                                              (union in_addr_union*) &cur->opt.in6_addr,
@@ -538,13 +559,16 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
                 if (r > 0) {
                         _cleanup_free_ char *addr_cur = NULL;
 
-                        (void) in_addr_to_string(AF_INET6,
-                                                 (union in_addr_union*) &cur->opt.in6_addr,
-                                                 &addr_cur);
                         (void) in_addr_to_string(AF_INET6,
                                                  (union in_addr_union*) &p->opt.in6_addr,
                                                  &addr_p);
 
+                        if (dynamic && cur->opt.prefixlen == p->opt.prefixlen)
+                                goto update;
+
+                        (void) in_addr_to_string(AF_INET6,
+                                                 (union in_addr_union*) &cur->opt.in6_addr,
+                                                 &addr_cur);
                         log_radv("IPv6 prefix %s/%u already configured, ignoring %s/%u",
                                  addr_cur, cur->opt.prefixlen,
                                  addr_p, p->opt.prefixlen);
@@ -560,7 +584,39 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
         ra->n_prefixes++;
 
         (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &p->opt.in6_addr, &addr_p);
-        log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
+
+        if (!dynamic) {
+                log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
+                return 0;
+        }
+
+        cur = p;
+
+ update:
+        r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
+        if (r < 0)
+                return r;
+
+        valid = be32toh(p->opt.valid_lifetime) * USEC_PER_SEC;
+        valid_until = usec_add(valid, time_now);
+        if (valid_until == USEC_INFINITY)
+                return -EOVERFLOW;
+
+        preferred = be32toh(p->opt.preferred_lifetime) * USEC_PER_SEC;
+        preferred_until = usec_add(preferred, time_now);
+        if (preferred_until == USEC_INFINITY)
+                return -EOVERFLOW;
+
+        cur->valid_until = valid_until;
+        cur->preferred_until = preferred_until;
+
+        log_radv("%s prefix %s/%u preferred %s valid %s",
+                 cur? "Updated": "Added",
+                 addr_p, p->opt.prefixlen,
+                 format_timespan(time_string_preferred, FORMAT_TIMESPAN_MAX,
+                                 preferred, USEC_PER_SEC),
+                 format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX,
+                                 valid, USEC_PER_SEC));
 
         return 0;
 }
index c1a8d5a00d05227ee71d296d0506ebaf058652ae..1fc8ca9ebafb908e74e9e45053fffc73682e7dcc 100644 (file)
@@ -342,8 +342,8 @@ static void test_ra(void) {
                 if (prefix[i].preferred)
                         assert_se(sd_radv_prefix_set_preferred_lifetime(p, prefix[i].preferred) >= 0);
 
-                assert_se((sd_radv_add_prefix(ra, p) >= 0) == prefix[i].succesful);
-                assert_se(sd_radv_add_prefix(ra, p) < 0);
+                assert_se((sd_radv_add_prefix(ra, p, false) >= 0) == prefix[i].succesful);
+                assert_se(sd_radv_add_prefix(ra, p, false) < 0);
 
                 p = sd_radv_prefix_unref(p);
                 assert_se(!p);
index a7e66f575b0401ab11cf9f18d543a42159a7267c..5fdab89f2d0c9d0b8949f350d3f239a5d2c4457a 100644 (file)
@@ -502,7 +502,7 @@ int radv_configure(Link *link) {
                    RADV_PREFIX_DELEGATION_STATIC,
                    RADV_PREFIX_DELEGATION_BOTH)) {
                 LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
-                        r = sd_radv_add_prefix(link->radv, p->radv_prefix);
+                        r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
                         if (r != -EEXIST && r < 0)
                                 return r;
                 }
index 94d5e71e8abbf9288b54aa2d3ef32d5653949507..393c977bf10b36e01bc68ca2c9a7a063703bb6fa 100644 (file)
@@ -24,6 +24,7 @@
 #include <inttypes.h>
 #include <net/ethernet.h>
 #include <netinet/in.h>
+#include <stdbool.h>
 #include <sys/types.h>
 
 #include "sd-ndisc.h"
@@ -62,7 +63,7 @@ int sd_radv_set_router_lifetime(sd_radv *ra, uint32_t router_lifetime);
 int sd_radv_set_managed_information(sd_radv *ra, int managed);
 int sd_radv_set_other_information(sd_radv *ra, int other);
 int sd_radv_set_preference(sd_radv *ra, unsigned preference);
-int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p);
+int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, bool dynamic);
 int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
                       const struct in6_addr *dns, size_t n_dns);
 int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime, char **search_list);