]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: address: use usec_t for handling lifetime 21072/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 20 Oct 2021 17:21:59 +0000 (02:21 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 21 Oct 2021 11:58:15 +0000 (20:58 +0900)
This drops stuct ifa_cacheinfo from Address, and store lifetime with
usec_t.

Why? Now, all requests of address configurations are once stored in
the request queue, and will be processed when it is ready. So, the
timestamp value passed to the kernel must be evaluated on configure.

This also fixes the following two issues.
- Time values in struct ifa_cacheinfo are stored in uint32_t.
  So, the validity check of the address configured by NDisc may fail on
  long running systems.
- If a system uses DHCPv6PD, when an interface may appear or be
  reconfigured later, then the lifetime value may be inappropriate.
  We need to adjust the lifetime with the current time and the timestamp
  of the lease.

src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-dhcp4.c
src/network/networkd-dhcp6.c
src/network/networkd-ndisc.c
src/network/networkd-radv.c
src/network/networkd-radv.h
src/network/test-networkd-address.c

index 33afdb0335de4dc3aa45ada18b3692469d962fd4..78e011a85541d444a4c7667d0b9f70d67a34064a 100644 (file)
@@ -67,8 +67,8 @@ int address_new(Address **ret) {
         *address = (Address) {
                 .family = AF_UNSPEC,
                 .scope = RT_SCOPE_UNIVERSE,
-                .cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME,
-                .cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME,
+                .lifetime_valid_usec = USEC_INFINITY,
+                .lifetime_preferred_usec = USEC_INFINITY,
                 .set_broadcast = -1,
                 .duplicate_address_detection = ADDRESS_FAMILY_IPV6,
         };
@@ -224,6 +224,41 @@ static bool address_may_set_broadcast(const Address *a, const Link *link) {
         return !streq_ptr(link->kind, "wireguard");
 }
 
+static struct ifa_cacheinfo *address_set_cinfo(const Address *a, struct ifa_cacheinfo *cinfo) {
+        usec_t now_usec;
+
+        assert(a);
+        assert(cinfo);
+
+        now_usec = now(clock_boottime_or_monotonic());
+
+        *cinfo = (struct ifa_cacheinfo) {
+                .ifa_valid = MIN(usec_sub_unsigned(a->lifetime_valid_usec, now_usec) / USEC_PER_SEC, UINT32_MAX),
+                .ifa_prefered = MIN(usec_sub_unsigned(a->lifetime_preferred_usec, now_usec) / USEC_PER_SEC, UINT32_MAX),
+        };
+
+        return cinfo;
+}
+
+static void address_set_lifetime(Address *a, const struct ifa_cacheinfo *cinfo) {
+        usec_t now_usec;
+
+        assert(a);
+        assert(cinfo);
+
+        now_usec = now(clock_boottime_or_monotonic());
+
+        if (cinfo->ifa_valid == UINT32_MAX)
+                a->lifetime_valid_usec = USEC_INFINITY;
+        else
+                a->lifetime_valid_usec = usec_add(cinfo->ifa_valid * USEC_PER_SEC, now_usec);
+
+        if (cinfo->ifa_prefered == UINT32_MAX)
+                a->lifetime_preferred_usec = USEC_INFINITY;
+        else
+                a->lifetime_preferred_usec = usec_add(cinfo->ifa_prefered * USEC_PER_SEC, now_usec);
+}
+
 static uint32_t address_prefix(const Address *a) {
         assert(a);
 
@@ -553,16 +588,16 @@ int manager_has_address(Manager *manager, int family, const union in_addr_union
         return false;
 }
 
-const char* format_lifetime(char *buf, size_t l, uint32_t lifetime) {
+const char* format_lifetime(char *buf, size_t l, usec_t lifetime_usec) {
         assert(buf);
         assert(l > 4);
 
-        if (lifetime == CACHE_INFO_INFINITY_LIFE_TIME)
+        if (lifetime_usec == USEC_INFINITY)
                 return "forever";
 
         sprintf(buf, "for ");
         /* format_timespan() never fails */
-        assert_se(format_timespan(buf + 4, l - 4, lifetime * USEC_PER_SEC, USEC_PER_SEC));
+        assert_se(format_timespan(buf + 4, l - 4, usec_sub_unsigned(lifetime_usec, now(clock_boottime_or_monotonic())), USEC_PER_SEC));
         return buf;
 }
 
@@ -586,8 +621,8 @@ static void log_address_debug(const Address *address, const char *str, const Lin
         log_link_debug(link, "%s %s address (%s): %s%s%s/%u (valid %s, preferred %s), flags: %s",
                        str, strna(network_config_source_to_string(address->source)), strna(state),
                        strnull(addr), peer ? " peer " : "", strempty(peer), address->prefixlen,
-                       FORMAT_LIFETIME(address->cinfo.ifa_valid),
-                       FORMAT_LIFETIME(address->cinfo.ifa_prefered),
+                       FORMAT_LIFETIME(address->lifetime_valid_usec),
+                       FORMAT_LIFETIME(address->lifetime_preferred_usec),
                        strna(flags_str));
 }
 
@@ -684,7 +719,7 @@ bool link_address_is_dynamic(const Link *link, const Address *address) {
         assert(link);
         assert(address);
 
-        if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
+        if (address->lifetime_preferred_usec != USEC_INFINITY)
                 return true;
 
         /* Even when the address is leased from a DHCP server, networkd assign the address
@@ -983,7 +1018,8 @@ static int address_configure(
                         return log_link_error_errno(link, r, "Could not append IFA_LABEL attribute: %m");
         }
 
-        r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
+        r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO,
+                                                 address_set_cinfo(address, &(struct ifa_cacheinfo) {}));
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append IFA_CACHEINFO attribute: %m");
 
@@ -1192,6 +1228,7 @@ int request_process_address(Request *req) {
 
 int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
         _cleanup_(address_freep) Address *tmp = NULL;
+        struct ifa_cacheinfo cinfo;
         Link *link = NULL;
         uint16_t type;
         Address *address = NULL;
@@ -1326,7 +1363,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
                 assert_not_reached();
         }
 
-        r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &tmp->cinfo);
+        r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
         if (r < 0 && r != -ENODATA) {
                 log_link_warning_errno(link, r, "rtnl: cannot get IFA_CACHEINFO attribute, ignoring: %m");
                 return 0;
@@ -1340,10 +1377,11 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
                         /* update flags and etc. */
                         address->flags = tmp->flags;
                         address->scope = tmp->scope;
-                        address->cinfo = tmp->cinfo;
+                        address_set_lifetime(address, &cinfo);
                         address_enter_configured(address);
                         log_address_debug(address, "Received updated", link);
                 } else {
+                        address_set_lifetime(tmp, &cinfo);
                         address_enter_configured(tmp);
                         log_address_debug(tmp, "Received new", link);
 
@@ -1602,7 +1640,7 @@ int config_parse_lifetime(
 
         Network *network = userdata;
         _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
-        uint32_t k;
+        usec_t k;
         int r;
 
         assert(filename);
@@ -1622,7 +1660,7 @@ int config_parse_lifetime(
 
         /* We accept only "forever", "infinity", empty, or "0". */
         if (STR_IN_SET(rvalue, "forever", "infinity", ""))
-                k = CACHE_INFO_INFINITY_LIFE_TIME;
+                k = USEC_INFINITY;
         else if (streq(rvalue, "0"))
                 k = 0;
         else {
@@ -1631,7 +1669,7 @@ int config_parse_lifetime(
                 return 0;
         }
 
-        n->cinfo.ifa_prefered = k;
+        n->lifetime_preferred_usec = k;
         TAKE_PTR(n);
 
         return 0;
index 20e957ccafb7ff2cc794b976a398edf04b2e4143..75edfd70dc1ce5bf691f8e8c1b9f6ffd37a2fd1e 100644 (file)
@@ -11,8 +11,7 @@
 #include "in-addr-util.h"
 #include "networkd-link.h"
 #include "networkd-util.h"
-
-#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
+#include "time-util.h"
 
 typedef struct Address Address;
 typedef struct Manager Manager;
@@ -37,11 +36,15 @@ struct Address {
 
         int set_broadcast;
         struct in_addr broadcast;
-        struct ifa_cacheinfo cinfo;
 
         union in_addr_union in_addr;
         union in_addr_union in_addr_peer;
 
+        /* These are absolute points in time, and NOT timespans/durations.
+         * Must be specified with clock_boottime_or_monotonic(). */
+        usec_t lifetime_valid_usec;
+        usec_t lifetime_preferred_usec;
+
         bool scope_set:1;
         bool ip_masquerade_done:1;
         AddressFamily duplicate_address_detection;
@@ -51,7 +54,7 @@ struct Address {
         address_ready_callback_t callback;
 };
 
-const char* format_lifetime(char *buf, size_t l, uint32_t lifetime) _warn_unused_result_;
+const char* format_lifetime(char *buf, size_t l, usec_t lifetime_usec) _warn_unused_result_;
 /* Note: the lifetime of the compound literal is the immediately surrounding block,
  * see C11 §6.5.2.5, and
  * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
index a8d649842307ea117d39c3e70e2008f8d30f5e13..1ee0052a751c759e5c41a5f5bc93599b03d2ed8e 100644 (file)
@@ -841,10 +841,10 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
 
 static int dhcp4_request_address(Link *link, bool announce) {
         _cleanup_(address_freep) Address *addr = NULL;
-        uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
         struct in_addr address, netmask, server;
         unsigned prefixlen;
         Address *existing;
+        usec_t lifetime_usec;
         int r;
 
         assert(link);
@@ -864,10 +864,15 @@ static int dhcp4_request_address(Link *link, bool announce) {
                 return log_link_debug_errno(link, r, "DHCP error: failed to get DHCP server IP address: %m");
 
         if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
-                r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
+                uint32_t lifetime_sec;
+
+                r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime_sec);
                 if (r < 0)
                         return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
-        }
+
+                lifetime_usec = usec_add(lifetime_sec * USEC_PER_SEC, now(clock_boottime_or_monotonic()));
+        } else
+                lifetime_usec = USEC_INFINITY;
 
         prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
 
@@ -908,8 +913,8 @@ static int dhcp4_request_address(Link *link, bool announce) {
         addr->provider.in = server;
         addr->family = AF_INET;
         addr->in_addr.in.s_addr = address.s_addr;
-        addr->cinfo.ifa_prefered = lifetime;
-        addr->cinfo.ifa_valid = lifetime;
+        addr->lifetime_preferred_usec = lifetime_usec;
+        addr->lifetime_valid_usec = lifetime_usec;
         addr->prefixlen = prefixlen;
         if (prefixlen <= 30)
                 addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
@@ -1698,7 +1703,6 @@ int config_parse_dhcp_fallback_lease_lifetime(
                 void *userdata) {
 
         Network *network = userdata;
-        uint32_t k;
 
         assert(filename);
         assert(section);
@@ -1712,15 +1716,13 @@ int config_parse_dhcp_fallback_lease_lifetime(
         }
 
         /* We accept only "forever" or "infinity". */
-        if (STR_IN_SET(rvalue, "forever", "infinity"))
-                k = CACHE_INFO_INFINITY_LIFE_TIME;
-        else {
+        if (!STR_IN_SET(rvalue, "forever", "infinity")) {
                 log_syntax(unit, LOG_WARNING, filename, line, 0,
                            "Invalid LeaseLifetime= value, ignoring: %s", rvalue);
                 return 0;
         }
 
-        network->dhcp_fallback_lease_lifetime = k;
+        network->dhcp_fallback_lease_lifetime = UINT32_MAX;
 
         return 0;
 }
index be3238337ce523dc3fd838f56eeedb7b2ea98468..1cd779fe37767923fb7b15c59733a431d3ca52ae 100644 (file)
@@ -44,7 +44,7 @@ bool link_dhcp6_pd_is_enabled(Link *link) {
 }
 
 static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
-        uint32_t lifetime_preferred, lifetime_valid;
+        uint32_t lifetime_preferred_sec, lifetime_valid_sec;
         struct in6_addr pd_prefix;
         uint8_t pd_prefix_len;
 
@@ -53,7 +53,7 @@ static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
 
         sd_dhcp6_lease_reset_pd_prefix_iter(lease);
 
-        return sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len, &lifetime_preferred, &lifetime_valid) >= 0;
+        return sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len, &lifetime_preferred_sec, &lifetime_valid_sec) >= 0;
 }
 
 static void link_remove_dhcp6_pd_prefix(Link *link, const struct in6_addr *prefix) {
@@ -288,7 +288,7 @@ static int dhcp6_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
         return 1;
 }
 
-static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix, usec_t timestamp_usec, uint32_t lifetime_sec) {
+static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix, usec_t lifetime_usec) {
         _cleanup_(route_freep) Route *route = NULL;
         Route *existing;
         int r;
@@ -310,7 +310,7 @@ static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix, use
         route->dst_prefixlen = 64;
         route->protocol = RTPROT_DHCP;
         route->priority = link->network->dhcp6_pd_route_metric;
-        route->lifetime_usec = usec_add(timestamp_usec, lifetime_sec * USEC_PER_SEC);
+        route->lifetime_usec = lifetime_usec;
 
         if (route_get(NULL, link, route, &existing) < 0)
                 link->dhcp6_pd_configured = false;
@@ -360,15 +360,15 @@ static void log_dhcp6_pd_address(Link *link, const Address *address) {
 
         log_link_full(link, log_level, "DHCPv6-PD address %s (valid %s, preferred %s)",
                       strna(buffer),
-                      FORMAT_LIFETIME(address->cinfo.ifa_valid),
-                      FORMAT_LIFETIME(address->cinfo.ifa_prefered));
+                      FORMAT_LIFETIME(address->lifetime_valid_usec),
+                      FORMAT_LIFETIME(address->lifetime_preferred_usec));
 }
 
 static int dhcp6_pd_request_address(
                 Link *link,
                 const struct in6_addr *prefix,
-                uint32_t lifetime_preferred,
-                uint32_t lifetime_valid) {
+                usec_t lifetime_preferred_usec,
+                usec_t lifetime_valid_usec) {
 
         _cleanup_set_free_ Set *addresses = NULL;
         struct in6_addr *a;
@@ -397,8 +397,8 @@ static int dhcp6_pd_request_address(
                 address->family = AF_INET6;
                 address->in_addr.in6 = *a;
                 address->prefixlen = 64;
-                address->cinfo.ifa_prefered = lifetime_preferred;
-                address->cinfo.ifa_valid = lifetime_valid;
+                address->lifetime_preferred_usec = lifetime_preferred_usec;
+                address->lifetime_valid_usec = lifetime_valid_usec;
                 SET_FLAG(address->flags, IFA_F_MANAGETEMPADDR, link->network->dhcp6_pd_manage_temporary_address);
                 address->route_metric = link->network->dhcp6_pd_route_metric;
 
@@ -421,9 +421,8 @@ static int dhcp6_pd_request_address(
 static int dhcp6_pd_assign_prefix(
                 Link *link,
                 const struct in6_addr *prefix,
-                usec_t timestamp_usec,
-                uint32_t lifetime_preferred,
-                uint32_t lifetime_valid) {
+                usec_t lifetime_preferred_usec,
+                usec_t lifetime_valid_usec) {
 
         int r;
 
@@ -432,16 +431,16 @@ static int dhcp6_pd_assign_prefix(
         assert(prefix);
 
         if (link->network->dhcp6_pd_announce) {
-                r = radv_add_prefix(link, prefix, 64, lifetime_preferred, lifetime_valid);
+                r = radv_add_prefix(link, prefix, 64, lifetime_preferred_usec, lifetime_valid_usec);
                 if (r < 0)
                         return r;
         }
 
-        r = dhcp6_pd_request_route(link, prefix, timestamp_usec, lifetime_valid);
+        r = dhcp6_pd_request_route(link, prefix, lifetime_valid_usec);
         if (r < 0)
                 return r;
 
-        r = dhcp6_pd_request_address(link, prefix, lifetime_preferred, lifetime_valid);
+        r = dhcp6_pd_request_address(link, prefix, lifetime_preferred_usec, lifetime_valid_usec);
         if (r < 0)
                 return r;
 
@@ -529,9 +528,8 @@ static int dhcp6_pd_prefix_distribute(
                 Link *dhcp6_link,
                 const struct in6_addr *pd_prefix,
                 uint8_t pd_prefix_len,
-                usec_t timestamp_usec,
-                uint32_t lifetime_preferred,
-                uint32_t lifetime_valid,
+                usec_t lifetime_preferred_usec,
+                usec_t lifetime_valid_usec,
                 bool assign_preferred_subnet_id) {
 
         Link *link;
@@ -563,7 +561,7 @@ static int dhcp6_pd_prefix_distribute(
                         continue;
 
                 (void) in6_addr_prefix_to_string(&assigned_prefix, 64, &buf);
-                r = dhcp6_pd_assign_prefix(link, &assigned_prefix, timestamp_usec, lifetime_preferred, lifetime_valid);
+                r = dhcp6_pd_assign_prefix(link, &assigned_prefix, lifetime_preferred_usec, lifetime_valid_usec);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "Failed to assign/update prefix %s: %m", strna(buf));
                         if (link == dhcp6_link)
@@ -749,7 +747,7 @@ static int dhcp6_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
         return 1;
 }
 
-static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *addr, uint8_t prefixlen, usec_t timestamp_usec, uint32_t lifetime_sec) {
+static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *addr, uint8_t prefixlen, usec_t lifetime_usec) {
         _cleanup_(route_freep) Route *route = NULL;
         _cleanup_free_ char *buf = NULL;
         Route *existing;
@@ -778,7 +776,7 @@ static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *ad
         route->type = RTN_UNREACHABLE;
         route->protocol = RTPROT_DHCP;
         route->priority = DHCP_ROUTE_METRIC;
-        route->lifetime_usec = usec_add(timestamp_usec, lifetime_sec * USEC_PER_SEC);
+        route->lifetime_usec = lifetime_usec;
 
         if (route_get(link->manager, NULL, route, &existing) < 0)
                 link->dhcp6_configured = false;
@@ -852,22 +850,26 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
         }
 
         for (sd_dhcp6_lease_reset_pd_prefix_iter(dhcp6_link->dhcp6_lease);;) {
-                uint32_t lifetime_preferred, lifetime_valid;
+                uint32_t lifetime_preferred_sec, lifetime_valid_sec;
+                usec_t lifetime_preferred_usec, lifetime_valid_usec;
                 struct in6_addr pd_prefix;
                 uint8_t pd_prefix_len;
 
                 r = sd_dhcp6_lease_get_pd(dhcp6_link->dhcp6_lease, &pd_prefix, &pd_prefix_len,
-                                          &lifetime_preferred, &lifetime_valid);
+                                          &lifetime_preferred_sec, &lifetime_valid_sec);
                 if (r < 0)
                         break;
 
+                lifetime_preferred_usec = usec_add(lifetime_preferred_sec * USEC_PER_SEC, timestamp_usec);
+                lifetime_valid_usec = usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec);
+
                 r = dhcp6_pd_prefix_add(dhcp6_link, &pd_prefix, pd_prefix_len);
                 if (r < 0)
                         return r;
                 if (r == 0)
                         continue;
 
-                r = dhcp6_request_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len, timestamp_usec, lifetime_valid);
+                r = dhcp6_request_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len, lifetime_valid_usec);
                 if (r < 0)
                         return r;
 
@@ -899,9 +901,8 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
                 r = dhcp6_pd_prefix_distribute(dhcp6_link,
                                                &pd_prefix,
                                                pd_prefix_len,
-                                               timestamp_usec,
-                                               lifetime_preferred,
-                                               lifetime_valid,
+                                               lifetime_preferred_usec,
+                                               lifetime_valid_usec,
                                                true);
                 if (r < 0)
                         return r;
@@ -909,9 +910,8 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
                 r = dhcp6_pd_prefix_distribute(dhcp6_link,
                                                &pd_prefix,
                                                pd_prefix_len,
-                                               timestamp_usec,
-                                               lifetime_preferred,
-                                               lifetime_valid,
+                                               lifetime_preferred_usec,
+                                               lifetime_valid_usec,
                                                false);
                 if (r < 0)
                         return r;
@@ -976,8 +976,8 @@ static void log_dhcp6_address(Link *link, const Address *address) {
 
         log_link_warning(link, "DHCPv6 address %s/%u (valid %s, preferred %s) conflicts the address %s/%u%s.",
                          strna(buffer), address->prefixlen,
-                         FORMAT_LIFETIME(address->cinfo.ifa_valid),
-                         FORMAT_LIFETIME(address->cinfo.ifa_prefered),
+                         FORMAT_LIFETIME(address->lifetime_valid_usec),
+                         FORMAT_LIFETIME(address->lifetime_preferred_usec),
                          strna(buffer), existing->prefixlen,
                          by_ndisc ? " assigned by NDisc. Please try to use or update IPv6Token= setting "
                          "to change the address generated by NDISC, or disable UseAutonomousPrefix=" : "");
@@ -986,15 +986,15 @@ static void log_dhcp6_address(Link *link, const Address *address) {
 simple_log:
         log_link_full(link, log_level, "DHCPv6 address %s/%u (valid %s, preferred %s)",
                       strna(buffer), address->prefixlen,
-                      FORMAT_LIFETIME(address->cinfo.ifa_valid),
-                      FORMAT_LIFETIME(address->cinfo.ifa_prefered));
+                      FORMAT_LIFETIME(address->lifetime_valid_usec),
+                      FORMAT_LIFETIME(address->lifetime_preferred_usec));
 }
 
 static int dhcp6_request_address(
                 Link *link,
                 const struct in6_addr *ip6_addr,
-                uint32_t lifetime_preferred,
-                uint32_t lifetime_valid) {
+                usec_t lifetime_preferred_usec,
+                usec_t lifetime_valid_usec) {
 
         _cleanup_(address_freep) Address *addr = NULL;
         Address *existing;
@@ -1009,8 +1009,8 @@ static int dhcp6_request_address(
         addr->in_addr.in6 = *ip6_addr;
         addr->flags = IFA_F_NOPREFIXROUTE;
         addr->prefixlen = 128;
-        addr->cinfo.ifa_prefered = lifetime_preferred;
-        addr->cinfo.ifa_valid = lifetime_valid;
+        addr->lifetime_preferred_usec = lifetime_preferred_usec;
+        addr->lifetime_valid_usec = lifetime_valid_usec;
 
         log_dhcp6_address(link, addr);
 
@@ -1032,6 +1032,7 @@ static int dhcp6_request_address(
 }
 
 static int dhcp6_address_acquired(Link *link) {
+        usec_t timestamp_usec;
         int r;
 
         assert(link);
@@ -1041,15 +1042,21 @@ static int dhcp6_address_acquired(Link *link) {
         if (!link->network->dhcp6_use_address)
                 return 0;
 
+        r = sd_dhcp6_lease_get_timestamp(link->dhcp6_lease, clock_boottime_or_monotonic(), &timestamp_usec);
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to get timestamp of DHCPv6 lease: %m");
+
         for (sd_dhcp6_lease_reset_address_iter(link->dhcp6_lease);;) {
-                uint32_t lifetime_preferred, lifetime_valid;
+                uint32_t lifetime_preferred_sec, lifetime_valid_sec;
                 struct in6_addr ip6_addr;
 
-                r = sd_dhcp6_lease_get_address(link->dhcp6_lease, &ip6_addr, &lifetime_preferred, &lifetime_valid);
+                r = sd_dhcp6_lease_get_address(link->dhcp6_lease, &ip6_addr, &lifetime_preferred_sec, &lifetime_valid_sec);
                 if (r < 0)
                         break;
 
-                r = dhcp6_request_address(link, &ip6_addr, lifetime_preferred, lifetime_valid);
+                r = dhcp6_request_address(link, &ip6_addr,
+                                          usec_add(lifetime_preferred_sec * USEC_PER_SEC, timestamp_usec),
+                                          usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec));
                 if (r < 0)
                         return r;
         }
index 9e3da746e3662db13bcac81572b30343c85aed6f..2bcb25daad00968e654136c9b4cba3aff2782907 100644 (file)
@@ -382,19 +382,17 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
 }
 
 static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
-        uint32_t lifetime_valid, lifetime_preferred;
+        uint32_t lifetime_valid_sec, lifetime_preferred_sec;
+        usec_t lifetime_valid_usec, lifetime_preferred_usec, timestamp_usec;
         _cleanup_set_free_ Set *addresses = NULL;
         struct in6_addr prefix, *a;
         unsigned prefixlen;
-        usec_t time_now;
         int r;
 
         assert(link);
         assert(rt);
 
-        /* Do not use clock_boottime_or_monotonic() here, as the kernel internally manages cstamp and
-         * tstamp with jiffies, and it is not increased while the system is suspended. */
-        r = sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &time_now);
+        r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &timestamp_usec);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
 
@@ -415,23 +413,26 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
                 return 0;
         }
 
-        r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid);
+        r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid_sec);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
 
-        if (lifetime_valid == 0) {
+        if (lifetime_valid_sec == 0) {
                 log_link_debug(link, "Ignoring prefix as its valid lifetime is zero.");
                 return 0;
         }
 
-        r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred);
+        r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred_sec);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
 
         /* The preferred lifetime is never greater than the valid lifetime */
-        if (lifetime_preferred > lifetime_valid)
+        if (lifetime_preferred_sec > lifetime_valid_sec)
                 return 0;
 
+        lifetime_valid_usec = usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec);
+        lifetime_preferred_usec = usec_add(lifetime_preferred_sec * USEC_PER_SEC, timestamp_usec);
+
         r = ndisc_generate_addresses(link, &prefix, prefixlen, &addresses);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to generate SLAAC addresses: %m");
@@ -448,8 +449,8 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
                 address->in_addr.in6 = *a;
                 address->prefixlen = prefixlen;
                 address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
-                address->cinfo.ifa_valid = lifetime_valid;
-                address->cinfo.ifa_prefered = lifetime_preferred;
+                address->lifetime_valid_usec = lifetime_valid_usec;
+                address->lifetime_preferred_usec = lifetime_preferred_usec;
 
                 /* See RFC4862, section 5.5.3.e. But the following logic is deviated from RFC4862 by
                  * honoring all valid lifetimes to improve the reaction of SLAAC to renumbering events.
@@ -458,9 +459,7 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
                 if (r > 0) {
                         /* If the address is already assigned, but not valid anymore, then refuse to
                          * update the address, and it will be removed. */
-                        if (e->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME &&
-                            usec_add(e->cinfo.tstamp / 100 * USEC_PER_SEC,
-                                     e->cinfo.ifa_valid * USEC_PER_SEC) < time_now)
+                        if (e->lifetime_valid_usec < timestamp_usec)
                                 continue;
                 }
 
index 73e9bce52a02f1e4222ad4c18322289723fbbc84..c3a4ca6a3ad15a867fcb49b62fc240d866514f91 100644 (file)
@@ -629,10 +629,11 @@ int radv_add_prefix(
                 Link *link,
                 const struct in6_addr *prefix,
                 uint8_t prefix_len,
-                uint32_t lifetime_preferred,
-                uint32_t lifetime_valid) {
+                usec_t lifetime_preferred_usec,
+                usec_t lifetime_valid_usec) {
 
         _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
+        usec_t now_usec;
         int r;
 
         assert(link);
@@ -640,6 +641,8 @@ int radv_add_prefix(
         if (!link->radv)
                 return 0;
 
+        now_usec = now(clock_boottime_or_monotonic());
+
         r = sd_radv_prefix_new(&p);
         if (r < 0)
                 return r;
@@ -648,11 +651,11 @@ int radv_add_prefix(
         if (r < 0)
                 return r;
 
-        r = sd_radv_prefix_set_preferred_lifetime(p, lifetime_preferred);
+        r = sd_radv_prefix_set_preferred_lifetime(p, usec_sub_unsigned(lifetime_preferred_usec, now_usec) / USEC_PER_SEC);
         if (r < 0)
                 return r;
 
-        r = sd_radv_prefix_set_valid_lifetime(p, lifetime_valid);
+        r = sd_radv_prefix_set_valid_lifetime(p, usec_sub_unsigned(lifetime_valid_usec, now_usec) / USEC_PER_SEC);
         if (r < 0)
                 return r;
 
index d51fe323dcec8216eed1efee25bad58f64749aee..6fd27ef39ec99a53cbe0851dff63bd64307dcf9d 100644 (file)
@@ -64,7 +64,7 @@ int link_request_radv_addresses(Link *link);
 
 int radv_update_mac(Link *link);
 int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
-                    uint32_t lifetime_preferred, uint32_t lifetime_valid);
+                    usec_t lifetime_preferred_usec, usec_t lifetime_valid_usec);
 
 int request_process_radv(Request *req);
 int link_request_radv(Link *link);
index 7c1d65a433c7e26cdab7338f56e09eee31a8b4fe..564c76f8483aff8881401087b844ddf621c50817 100644 (file)
@@ -2,21 +2,26 @@
 
 #include "networkd-address.h"
 #include "tests.h"
+#include "time-util.h"
 
-static void test_FORMAT_LIFETIME_one(uint32_t lifetime, const char *expected) {
+static void test_FORMAT_LIFETIME_one(usec_t lifetime, const char *expected) {
         const char *t = FORMAT_LIFETIME(lifetime);
 
-        log_debug("%"PRIu32 " → \"%s\" (expected \"%s\")", lifetime, t, expected);
+        log_debug(USEC_FMT " → \"%s\" (expected \"%s\")", lifetime, t, expected);
         assert_se(streq(t, expected));
 }
 
 static void test_FORMAT_LIFETIME(void) {
+        usec_t now_usec;
+
         log_info("/* %s */", __func__);
 
-        test_FORMAT_LIFETIME_one(0, "for 0");
-        test_FORMAT_LIFETIME_one(1, "for 1s");
-        test_FORMAT_LIFETIME_one(3 * (USEC_PER_WEEK/USEC_PER_SEC), "for 3w");
-        test_FORMAT_LIFETIME_one(CACHE_INFO_INFINITY_LIFE_TIME, "forever");
+        now_usec = now(CLOCK_MONOTONIC);
+
+        test_FORMAT_LIFETIME_one(now_usec, "for 0");
+        test_FORMAT_LIFETIME_one(usec_add(now_usec, 2 * USEC_PER_SEC - 1), "for 1s");
+        test_FORMAT_LIFETIME_one(usec_add(now_usec, 3 * USEC_PER_WEEK + USEC_PER_SEC - 1), "for 3w");
+        test_FORMAT_LIFETIME_one(USEC_INFINITY, "forever");
 }
 
 int main(int argc, char *argv[]) {