diff options
author | Luca Boccassi <luca.boccassi@microsoft.com> | 2021-10-20 14:38:03 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-20 14:38:03 +0100 |
commit | b78524f48daef840c02b8e75f87f65094c4edd2a (patch) | |
tree | 68779b0a16346be41ba16d1b4e857941c2fd989c | |
parent | 6417e8925cb55fdd41fa7c03521407160c40a9f5 (diff) | |
parent | d0619f2c2b3865e930da9832a246c97d35f63b85 (diff) | |
download | systemd-b78524f48daef840c02b8e75f87f65094c4edd2a.tar.gz |
Merge pull request #21055 from yuwata/network-dhcp6-pd-route-lifetime-metric
network: dhcp6pd: set lifetime and route metric
-rw-r--r-- | man/systemd.network.xml | 3 | ||||
-rw-r--r-- | src/libsystemd-network/dhcp6-lease-internal.h | 1 | ||||
-rw-r--r-- | src/libsystemd-network/dhcp6-network.c | 4 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp6-client.c | 50 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp6-lease.c | 13 | ||||
-rw-r--r-- | src/network/networkd-dhcp-common.h | 1 | ||||
-rw-r--r-- | src/network/networkd-dhcp6.c | 22 | ||||
-rw-r--r-- | src/network/networkd-network.c | 3 | ||||
-rw-r--r-- | src/systemd/sd-dhcp6-lease.h | 3 |
9 files changed, 84 insertions, 16 deletions
diff --git a/man/systemd.network.xml b/man/systemd.network.xml index bcc86417c6..01297c397f 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2162,7 +2162,8 @@ Table=1234</programlisting></para> <term><varname>RouteMetric=</varname></term> <listitem> <para>The metric of the route to the delegated prefix subnet. Takes an unsigned integer in - the range 0…4294967295. When unset or set to 0, the kernel's default value is used.</para> + the range 0…4294967295. When set to 0, the kernel's default value is used. Defaults to 256. + </para> </listitem> </varlistentry> </variablelist> diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h index 8801497b72..66af241df5 100644 --- a/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/libsystemd-network/dhcp6-lease-internal.h @@ -18,6 +18,7 @@ struct sd_dhcp6_lease { size_t serverid_len; uint8_t preference; bool rapid_commit; + triple_timestamp timestamp; DHCP6IA ia; DHCP6IA pd; diff --git a/src/libsystemd-network/dhcp6-network.c b/src/libsystemd-network/dhcp6-network.c index 4f7bd53de4..eedd92d3c2 100644 --- a/src/libsystemd-network/dhcp6-network.c +++ b/src/libsystemd-network/dhcp6-network.c @@ -47,6 +47,10 @@ int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) { if (r < 0) return r; + r = setsockopt_int(s, SOL_SOCKET, SO_TIMESTAMP, true); + if (r < 0) + return r; + r = bind(s, &src.sa, sizeof(src.in6)); if (r < 0) return -errno; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index aacdf06980..9a6be64789 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -21,6 +21,7 @@ #include "hexdecoct.h" #include "hostname-util.h" #include "in-addr-util.h" +#include "io-util.h" #include "network-common.h" #include "random-util.h" #include "socket-util.h" @@ -1341,13 +1342,14 @@ static int client_parse_message( return 0; } -static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) { +static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len, const triple_timestamp *t) { _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; bool rapid_commit; int r; assert(client); assert(reply); + assert(t); if (reply->type != DHCP6_MESSAGE_REPLY) return 0; @@ -1356,6 +1358,8 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si if (r < 0) return -ENOMEM; + lease->timestamp = *t; + r = client_parse_message(client, reply, len, lease); if (r < 0) return r; @@ -1375,11 +1379,15 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si return DHCP6_STATE_BOUND; } -static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) { +static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len, const triple_timestamp *t) { _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; uint8_t pref_advertise = 0, pref_lease = 0; int r; + assert(client); + assert(advertise); + assert(t); + if (advertise->type != DHCP6_MESSAGE_ADVERTISE) return 0; @@ -1387,6 +1395,8 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver if (r < 0) return r; + lease->timestamp = *t; + r = client_parse_message(client, advertise, len, lease); if (r < 0) return r; @@ -1417,6 +1427,17 @@ static int client_receive_message( sd_dhcp6_client *client = userdata; DHCP6_CLIENT_DONT_DESTROY(client); + /* This needs to be initialized with zero. See #20741. */ + CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL) control = {}; + struct iovec iov; + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + triple_timestamp t = {}; _cleanup_free_ DHCP6Message *message = NULL; ssize_t buflen, len; int r = 0; @@ -1427,9 +1448,8 @@ static int client_receive_message( buflen = next_datagram_size_fd(fd); if (buflen == -ENETDOWN) - /* the link is down. Don't return an error or the I/O event - source will be disconnected and we won't be able to receive - packets again when the link comes back. */ + /* the link is down. Don't return an error or the I/O event source will be disconnected + * and we won't be able to receive packets again when the link comes back. */ return 0; if (buflen < 0) return buflen; @@ -1438,7 +1458,9 @@ static int client_receive_message( if (!message) return -ENOMEM; - len = recv(fd, message, buflen, 0); + iov = IOVEC_MAKE(message, buflen); + + len = recvmsg_safe(fd, &msg, MSG_DONTWAIT); if (len < 0) { /* see comment above for why we shouldn't error out on ENETDOWN. */ if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) @@ -1452,6 +1474,16 @@ static int client_receive_message( return 0; } + CMSG_FOREACH(cmsg, &msg) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SO_TIMESTAMP && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) + triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) CMSG_DATA(cmsg))); + } + + if (!triple_timestamp_is_set(&t)) + triple_timestamp_get(&t); + if (!IN_SET(message->type, DHCP6_MESSAGE_ADVERTISE, DHCP6_MESSAGE_REPLY, DHCP6_MESSAGE_RECONFIGURE)) { const char *type_str = dhcp6_message_type_to_string(message->type); if (type_str) @@ -1466,7 +1498,7 @@ static int client_receive_message( switch (client->state) { case DHCP6_STATE_INFORMATION_REQUEST: - r = client_receive_reply(client, message, len); + r = client_receive_reply(client, message, len, &t); if (r < 0) { log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m"); return 0; @@ -1479,7 +1511,7 @@ static int client_receive_message( break; case DHCP6_STATE_SOLICITATION: - r = client_receive_advertise(client, message, len); + r = client_receive_advertise(client, message, len, &t); if (r < 0) { log_dhcp6_client_errno(client, r, "Failed to process received advertise message, ignoring: %m"); return 0; @@ -1495,7 +1527,7 @@ static int client_receive_message( case DHCP6_STATE_RENEW: case DHCP6_STATE_REBIND: - r = client_receive_reply(client, message, len); + r = client_receive_reply(client, message, len, &t); if (r < 0) { log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m"); return 0; diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index c55b06d2f7..6c7ffc7999 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -11,6 +11,19 @@ #include "strv.h" #include "util.h" +int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret) { + assert_return(lease, -EINVAL); + assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP); + assert_return(clock_supported(clock), -EOPNOTSUPP); + assert_return(ret, -EINVAL); + + if (!triple_timestamp_is_set(&lease->timestamp)) + return -ENODATA; + + *ret = triple_timestamp_by_clock(&lease->timestamp, clock); + return 0; +} + int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) { DHCP6Address *addr; uint32_t valid = 0, t; diff --git a/src/network/networkd-dhcp-common.h b/src/network/networkd-dhcp-common.h index 4a98038391..2573247db2 100644 --- a/src/network/networkd-dhcp-common.h +++ b/src/network/networkd-dhcp-common.h @@ -10,6 +10,7 @@ #include "time-util.h" #define DHCP_ROUTE_METRIC 1024 +#define DHCP6PD_ROUTE_METRIC 256 typedef struct Link Link; typedef struct Manager Manager; diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 6ec178f354..2bbad4edbb 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -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) { +static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix, usec_t timestamp_usec, uint32_t lifetime_sec) { _cleanup_(route_freep) Route *route = NULL; Route *existing; int r; @@ -310,6 +310,7 @@ static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix) { route->dst_prefixlen = 64; route->protocol = RTPROT_DHCP; route->priority = link->network->dhcp6_pd_route_metric; + route->lifetime = usec_add(timestamp_usec, lifetime_sec * USEC_PER_SEC); if (route_get(NULL, link, route, &existing) < 0) link->dhcp6_pd_configured = false; @@ -420,6 +421,7 @@ 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) { @@ -435,7 +437,7 @@ static int dhcp6_pd_assign_prefix( return r; } - r = dhcp6_pd_request_route(link, prefix); + r = dhcp6_pd_request_route(link, prefix, timestamp_usec, lifetime_valid); if (r < 0) return r; @@ -527,6 +529,7 @@ 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, bool assign_preferred_subnet_id) { @@ -560,7 +563,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, lifetime_preferred, lifetime_valid); + r = dhcp6_pd_assign_prefix(link, &assigned_prefix, timestamp_usec, lifetime_preferred, lifetime_valid); if (r < 0) { log_link_warning_errno(link, r, "Failed to assign/update prefix %s: %m", strna(buf)); if (link == dhcp6_link) @@ -746,7 +749,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) { +static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *addr, uint8_t prefixlen, usec_t timestamp_usec, uint32_t lifetime_sec) { _cleanup_(route_freep) Route *route = NULL; _cleanup_free_ char *buf = NULL; Route *existing; @@ -774,6 +777,8 @@ static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *ad route->table = link_get_dhcp6_route_table(link); route->type = RTN_UNREACHABLE; route->protocol = RTPROT_DHCP; + route->priority = DHCP_ROUTE_METRIC; + route->lifetime = usec_add(timestamp_usec, lifetime_sec * USEC_PER_SEC); if (route_get(link->manager, NULL, route, &existing) < 0) link->dhcp6_configured = false; @@ -826,12 +831,17 @@ static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_ } static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) { + usec_t timestamp_usec; Link *link; int r; assert(dhcp6_link); assert(dhcp6_link->dhcp6_lease); + r = sd_dhcp6_lease_get_timestamp(dhcp6_link->dhcp6_lease, clock_boottime_or_monotonic(), ×tamp_usec); + if (r < 0) + return log_link_warning_errno(dhcp6_link, r, "Failed to get timestamp of DHCPv6 lease: %m"); + HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) { if (link == dhcp6_link) continue; @@ -857,7 +867,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) { if (r == 0) continue; - r = dhcp6_request_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len); + r = dhcp6_request_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len, timestamp_usec, lifetime_valid); if (r < 0) return r; @@ -889,6 +899,7 @@ 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, true); @@ -898,6 +909,7 @@ 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, false); diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index a367041e99..798f409929 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -409,7 +409,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .dhcp6_pd_announce = true, .dhcp6_pd_assign = true, .dhcp6_pd_manage_temporary_address = true, - .dhcp6_pd_subnet_id = -1, + .dhcp6_pd_subnet_id = UINT64_MAX, + .dhcp6_pd_route_metric = DHCP6PD_ROUTE_METRIC, .dhcp_server_bind_to_interface = true, .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true, diff --git a/src/systemd/sd-dhcp6-lease.h b/src/systemd/sd-dhcp6-lease.h index a10901e5cb..04c6383051 100644 --- a/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/sd-dhcp6-lease.h @@ -21,6 +21,7 @@ #include <inttypes.h> #include <netinet/in.h> +#include <sys/types.h> #include "_sd-common.h" @@ -28,6 +29,8 @@ _SD_BEGIN_DECLARATIONS; typedef struct sd_dhcp6_lease sd_dhcp6_lease; +int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret); + void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease); int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr, |