summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Boccassi <luca.boccassi@microsoft.com>2021-10-20 14:38:03 +0100
committerGitHub <noreply@github.com>2021-10-20 14:38:03 +0100
commitb78524f48daef840c02b8e75f87f65094c4edd2a (patch)
tree68779b0a16346be41ba16d1b4e857941c2fd989c
parent6417e8925cb55fdd41fa7c03521407160c40a9f5 (diff)
parentd0619f2c2b3865e930da9832a246c97d35f63b85 (diff)
downloadsystemd-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.xml3
-rw-r--r--src/libsystemd-network/dhcp6-lease-internal.h1
-rw-r--r--src/libsystemd-network/dhcp6-network.c4
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c50
-rw-r--r--src/libsystemd-network/sd-dhcp6-lease.c13
-rw-r--r--src/network/networkd-dhcp-common.h1
-rw-r--r--src/network/networkd-dhcp6.c22
-rw-r--r--src/network/networkd-network.c3
-rw-r--r--src/systemd/sd-dhcp6-lease.h3
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(), &timestamp_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,