Skip to content

Commit b78524f

Browse files
authored
Merge pull request systemd#21055 from yuwata/network-dhcp6-pd-route-lifetime-metric
network: dhcp6pd: set lifetime and route metric
2 parents 6417e89 + d0619f2 commit b78524f

File tree

9 files changed

+84
-16
lines changed

9 files changed

+84
-16
lines changed

man/systemd.network.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2162,7 +2162,8 @@ Table=1234</programlisting></para>
21622162
<term><varname>RouteMetric=</varname></term>
21632163
<listitem>
21642164
<para>The metric of the route to the delegated prefix subnet. Takes an unsigned integer in
2165-
the range 0…4294967295. When unset or set to 0, the kernel's default value is used.</para>
2165+
the range 0…4294967295. When set to 0, the kernel's default value is used. Defaults to 256.
2166+
</para>
21662167
</listitem>
21672168
</varlistentry>
21682169
</variablelist>

src/libsystemd-network/dhcp6-lease-internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ struct sd_dhcp6_lease {
1818
size_t serverid_len;
1919
uint8_t preference;
2020
bool rapid_commit;
21+
triple_timestamp timestamp;
2122

2223
DHCP6IA ia;
2324
DHCP6IA pd;

src/libsystemd-network/dhcp6-network.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) {
4747
if (r < 0)
4848
return r;
4949

50+
r = setsockopt_int(s, SOL_SOCKET, SO_TIMESTAMP, true);
51+
if (r < 0)
52+
return r;
53+
5054
r = bind(s, &src.sa, sizeof(src.in6));
5155
if (r < 0)
5256
return -errno;

src/libsystemd-network/sd-dhcp6-client.c

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "hexdecoct.h"
2222
#include "hostname-util.h"
2323
#include "in-addr-util.h"
24+
#include "io-util.h"
2425
#include "network-common.h"
2526
#include "random-util.h"
2627
#include "socket-util.h"
@@ -1341,13 +1342,14 @@ static int client_parse_message(
13411342
return 0;
13421343
}
13431344

1344-
static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) {
1345+
static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len, const triple_timestamp *t) {
13451346
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
13461347
bool rapid_commit;
13471348
int r;
13481349

13491350
assert(client);
13501351
assert(reply);
1352+
assert(t);
13511353

13521354
if (reply->type != DHCP6_MESSAGE_REPLY)
13531355
return 0;
@@ -1356,6 +1358,8 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si
13561358
if (r < 0)
13571359
return -ENOMEM;
13581360

1361+
lease->timestamp = *t;
1362+
13591363
r = client_parse_message(client, reply, len, lease);
13601364
if (r < 0)
13611365
return r;
@@ -1375,18 +1379,24 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si
13751379
return DHCP6_STATE_BOUND;
13761380
}
13771381

1378-
static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) {
1382+
static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len, const triple_timestamp *t) {
13791383
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
13801384
uint8_t pref_advertise = 0, pref_lease = 0;
13811385
int r;
13821386

1387+
assert(client);
1388+
assert(advertise);
1389+
assert(t);
1390+
13831391
if (advertise->type != DHCP6_MESSAGE_ADVERTISE)
13841392
return 0;
13851393

13861394
r = dhcp6_lease_new(&lease);
13871395
if (r < 0)
13881396
return r;
13891397

1398+
lease->timestamp = *t;
1399+
13901400
r = client_parse_message(client, advertise, len, lease);
13911401
if (r < 0)
13921402
return r;
@@ -1417,6 +1427,17 @@ static int client_receive_message(
14171427

14181428
sd_dhcp6_client *client = userdata;
14191429
DHCP6_CLIENT_DONT_DESTROY(client);
1430+
/* This needs to be initialized with zero. See #20741. */
1431+
CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL) control = {};
1432+
struct iovec iov;
1433+
struct msghdr msg = {
1434+
.msg_iov = &iov,
1435+
.msg_iovlen = 1,
1436+
.msg_control = &control,
1437+
.msg_controllen = sizeof(control),
1438+
};
1439+
struct cmsghdr *cmsg;
1440+
triple_timestamp t = {};
14201441
_cleanup_free_ DHCP6Message *message = NULL;
14211442
ssize_t buflen, len;
14221443
int r = 0;
@@ -1427,9 +1448,8 @@ static int client_receive_message(
14271448

14281449
buflen = next_datagram_size_fd(fd);
14291450
if (buflen == -ENETDOWN)
1430-
/* the link is down. Don't return an error or the I/O event
1431-
source will be disconnected and we won't be able to receive
1432-
packets again when the link comes back. */
1451+
/* the link is down. Don't return an error or the I/O event source will be disconnected
1452+
* and we won't be able to receive packets again when the link comes back. */
14331453
return 0;
14341454
if (buflen < 0)
14351455
return buflen;
@@ -1438,7 +1458,9 @@ static int client_receive_message(
14381458
if (!message)
14391459
return -ENOMEM;
14401460

1441-
len = recv(fd, message, buflen, 0);
1461+
iov = IOVEC_MAKE(message, buflen);
1462+
1463+
len = recvmsg_safe(fd, &msg, MSG_DONTWAIT);
14421464
if (len < 0) {
14431465
/* see comment above for why we shouldn't error out on ENETDOWN. */
14441466
if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
@@ -1452,6 +1474,16 @@ static int client_receive_message(
14521474
return 0;
14531475
}
14541476

1477+
CMSG_FOREACH(cmsg, &msg) {
1478+
if (cmsg->cmsg_level == SOL_SOCKET &&
1479+
cmsg->cmsg_type == SO_TIMESTAMP &&
1480+
cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
1481+
triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) CMSG_DATA(cmsg)));
1482+
}
1483+
1484+
if (!triple_timestamp_is_set(&t))
1485+
triple_timestamp_get(&t);
1486+
14551487
if (!IN_SET(message->type, DHCP6_MESSAGE_ADVERTISE, DHCP6_MESSAGE_REPLY, DHCP6_MESSAGE_RECONFIGURE)) {
14561488
const char *type_str = dhcp6_message_type_to_string(message->type);
14571489
if (type_str)
@@ -1466,7 +1498,7 @@ static int client_receive_message(
14661498

14671499
switch (client->state) {
14681500
case DHCP6_STATE_INFORMATION_REQUEST:
1469-
r = client_receive_reply(client, message, len);
1501+
r = client_receive_reply(client, message, len, &t);
14701502
if (r < 0) {
14711503
log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
14721504
return 0;
@@ -1479,7 +1511,7 @@ static int client_receive_message(
14791511
break;
14801512

14811513
case DHCP6_STATE_SOLICITATION:
1482-
r = client_receive_advertise(client, message, len);
1514+
r = client_receive_advertise(client, message, len, &t);
14831515
if (r < 0) {
14841516
log_dhcp6_client_errno(client, r, "Failed to process received advertise message, ignoring: %m");
14851517
return 0;
@@ -1495,7 +1527,7 @@ static int client_receive_message(
14951527
case DHCP6_STATE_RENEW:
14961528
case DHCP6_STATE_REBIND:
14971529

1498-
r = client_receive_reply(client, message, len);
1530+
r = client_receive_reply(client, message, len, &t);
14991531
if (r < 0) {
15001532
log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
15011533
return 0;

src/libsystemd-network/sd-dhcp6-lease.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@
1111
#include "strv.h"
1212
#include "util.h"
1313

14+
int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret) {
15+
assert_return(lease, -EINVAL);
16+
assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
17+
assert_return(clock_supported(clock), -EOPNOTSUPP);
18+
assert_return(ret, -EINVAL);
19+
20+
if (!triple_timestamp_is_set(&lease->timestamp))
21+
return -ENODATA;
22+
23+
*ret = triple_timestamp_by_clock(&lease->timestamp, clock);
24+
return 0;
25+
}
26+
1427
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
1528
DHCP6Address *addr;
1629
uint32_t valid = 0, t;

src/network/networkd-dhcp-common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "time-util.h"
1111

1212
#define DHCP_ROUTE_METRIC 1024
13+
#define DHCP6PD_ROUTE_METRIC 256
1314

1415
typedef struct Link Link;
1516
typedef struct Manager Manager;

src/network/networkd-dhcp6.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ static int dhcp6_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
288288
return 1;
289289
}
290290

291-
static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix) {
291+
static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix, usec_t timestamp_usec, uint32_t lifetime_sec) {
292292
_cleanup_(route_freep) Route *route = NULL;
293293
Route *existing;
294294
int r;
@@ -310,6 +310,7 @@ static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix) {
310310
route->dst_prefixlen = 64;
311311
route->protocol = RTPROT_DHCP;
312312
route->priority = link->network->dhcp6_pd_route_metric;
313+
route->lifetime = usec_add(timestamp_usec, lifetime_sec * USEC_PER_SEC);
313314

314315
if (route_get(NULL, link, route, &existing) < 0)
315316
link->dhcp6_pd_configured = false;
@@ -420,6 +421,7 @@ static int dhcp6_pd_request_address(
420421
static int dhcp6_pd_assign_prefix(
421422
Link *link,
422423
const struct in6_addr *prefix,
424+
usec_t timestamp_usec,
423425
uint32_t lifetime_preferred,
424426
uint32_t lifetime_valid) {
425427

@@ -435,7 +437,7 @@ static int dhcp6_pd_assign_prefix(
435437
return r;
436438
}
437439

438-
r = dhcp6_pd_request_route(link, prefix);
440+
r = dhcp6_pd_request_route(link, prefix, timestamp_usec, lifetime_valid);
439441
if (r < 0)
440442
return r;
441443

@@ -527,6 +529,7 @@ static int dhcp6_pd_prefix_distribute(
527529
Link *dhcp6_link,
528530
const struct in6_addr *pd_prefix,
529531
uint8_t pd_prefix_len,
532+
usec_t timestamp_usec,
530533
uint32_t lifetime_preferred,
531534
uint32_t lifetime_valid,
532535
bool assign_preferred_subnet_id) {
@@ -560,7 +563,7 @@ static int dhcp6_pd_prefix_distribute(
560563
continue;
561564

562565
(void) in6_addr_prefix_to_string(&assigned_prefix, 64, &buf);
563-
r = dhcp6_pd_assign_prefix(link, &assigned_prefix, lifetime_preferred, lifetime_valid);
566+
r = dhcp6_pd_assign_prefix(link, &assigned_prefix, timestamp_usec, lifetime_preferred, lifetime_valid);
564567
if (r < 0) {
565568
log_link_warning_errno(link, r, "Failed to assign/update prefix %s: %m", strna(buf));
566569
if (link == dhcp6_link)
@@ -746,7 +749,7 @@ static int dhcp6_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
746749
return 1;
747750
}
748751

749-
static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *addr, uint8_t prefixlen) {
752+
static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *addr, uint8_t prefixlen, usec_t timestamp_usec, uint32_t lifetime_sec) {
750753
_cleanup_(route_freep) Route *route = NULL;
751754
_cleanup_free_ char *buf = NULL;
752755
Route *existing;
@@ -774,6 +777,8 @@ static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *ad
774777
route->table = link_get_dhcp6_route_table(link);
775778
route->type = RTN_UNREACHABLE;
776779
route->protocol = RTPROT_DHCP;
780+
route->priority = DHCP_ROUTE_METRIC;
781+
route->lifetime = usec_add(timestamp_usec, lifetime_sec * USEC_PER_SEC);
777782

778783
if (route_get(link->manager, NULL, route, &existing) < 0)
779784
link->dhcp6_configured = false;
@@ -826,12 +831,17 @@ static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_
826831
}
827832

828833
static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
834+
usec_t timestamp_usec;
829835
Link *link;
830836
int r;
831837

832838
assert(dhcp6_link);
833839
assert(dhcp6_link->dhcp6_lease);
834840

841+
r = sd_dhcp6_lease_get_timestamp(dhcp6_link->dhcp6_lease, clock_boottime_or_monotonic(), &timestamp_usec);
842+
if (r < 0)
843+
return log_link_warning_errno(dhcp6_link, r, "Failed to get timestamp of DHCPv6 lease: %m");
844+
835845
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
836846
if (link == dhcp6_link)
837847
continue;
@@ -857,7 +867,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
857867
if (r == 0)
858868
continue;
859869

860-
r = dhcp6_request_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len);
870+
r = dhcp6_request_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len, timestamp_usec, lifetime_valid);
861871
if (r < 0)
862872
return r;
863873

@@ -889,6 +899,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
889899
r = dhcp6_pd_prefix_distribute(dhcp6_link,
890900
&pd_prefix,
891901
pd_prefix_len,
902+
timestamp_usec,
892903
lifetime_preferred,
893904
lifetime_valid,
894905
true);
@@ -898,6 +909,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
898909
r = dhcp6_pd_prefix_distribute(dhcp6_link,
899910
&pd_prefix,
900911
pd_prefix_len,
912+
timestamp_usec,
901913
lifetime_preferred,
902914
lifetime_valid,
903915
false);

src/network/networkd-network.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
409409
.dhcp6_pd_announce = true,
410410
.dhcp6_pd_assign = true,
411411
.dhcp6_pd_manage_temporary_address = true,
412-
.dhcp6_pd_subnet_id = -1,
412+
.dhcp6_pd_subnet_id = UINT64_MAX,
413+
.dhcp6_pd_route_metric = DHCP6PD_ROUTE_METRIC,
413414

414415
.dhcp_server_bind_to_interface = true,
415416
.dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,

src/systemd/sd-dhcp6-lease.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@
2121

2222
#include <inttypes.h>
2323
#include <netinet/in.h>
24+
#include <sys/types.h>
2425

2526
#include "_sd-common.h"
2627

2728
_SD_BEGIN_DECLARATIONS;
2829

2930
typedef struct sd_dhcp6_lease sd_dhcp6_lease;
3031

32+
int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret);
33+
3134
void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease);
3235
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease,
3336
struct in6_addr *addr,

0 commit comments

Comments
 (0)