summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-10-21 05:16:52 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2021-10-26 00:35:22 +0900
commit56bbe0ef02bc783875c12dd238740a846b775399 (patch)
tree602f5bf0413de4ce71c582f16f4ed92e8c0cd872
parentf595b2e9b438460e993c7eeae419c7c16133e19d (diff)
downloadsystemd-56bbe0ef02bc783875c12dd238740a846b775399.tar.gz
network: dhcp6pd: introduce a simplified and unified method to calculate subnet prefix
-rw-r--r--src/network/networkd-dhcp6.c75
1 files changed, 42 insertions, 33 deletions
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index a92394554a..837368b829 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -457,74 +457,83 @@ static bool link_has_preferred_subnet_id(Link *link) {
return link->network->dhcp6_pd_subnet_id >= 0;
}
-static int dhcp6_get_preferred_delegated_prefix(
+static int dhcp6_pd_calculate_prefix(
+ const struct in6_addr *pd_prefix,
+ uint8_t pd_prefix_len,
+ uint64_t subnet_id,
+ struct in6_addr *ret) {
+
+ struct in6_addr prefix;
+
+ assert(pd_prefix);
+ assert(pd_prefix_len <= 64);
+ assert(ret);
+
+ if (subnet_id >= UINT64_C(1) << (64 - pd_prefix_len))
+ return -ERANGE;
+
+ prefix = *pd_prefix;
+
+ if (pd_prefix_len < 32)
+ prefix.s6_addr32[0] |= htobe32(subnet_id >> 32);
+
+ prefix.s6_addr32[1] |= htobe32(subnet_id & 0xffffffff);
+
+ *ret = prefix;
+ return 0;
+}
+
+static int dhcp6_pd_get_preferred_prefix(
Link *link,
const struct in6_addr *pd_prefix,
uint8_t pd_prefix_len,
struct in6_addr *ret) {
- /* We start off with the original PD prefix we have been assigned and iterate from there */
- union in_addr_union prefix;
- uint64_t n_prefixes;
+ struct in6_addr prefix;
Link *assigned_link;
int r;
assert(link);
assert(link->manager);
assert(pd_prefix);
- assert(pd_prefix_len <= 64);
-
- n_prefixes = UINT64_C(1) << (64 - pd_prefix_len);
- prefix.in6 = *pd_prefix;
if (link_has_preferred_subnet_id(link)) {
- uint64_t subnet_id = link->network->dhcp6_pd_subnet_id;
-
/* If the link has a preference for a particular subnet id try to allocate that */
- if (subnet_id >= n_prefixes)
- return log_link_warning_errno(link, SYNTHETIC_ERRNO(ERANGE),
- "subnet id %" PRIu64 " is out of range. Only have %" PRIu64 " subnets.",
- subnet_id, n_prefixes);
- r = in_addr_prefix_nth(AF_INET6, &prefix, 64, subnet_id);
+ r = dhcp6_pd_calculate_prefix(pd_prefix, pd_prefix_len, link->network->dhcp6_pd_subnet_id, &prefix);
if (r < 0)
return log_link_warning_errno(link, r,
"subnet id %" PRIu64 " is out of range. Only have %" PRIu64 " subnets.",
- subnet_id, n_prefixes);
-
- /* Verify that the prefix we did calculate fits in the pd prefix.
- * This should not fail as we checked the prefix size beforehand */
- assert_se(in6_addr_prefix_covers(pd_prefix, pd_prefix_len, &prefix.in6) > 0);
+ link->network->dhcp6_pd_subnet_id, UINT64_C(1) << (64 - pd_prefix_len));
- if (link_get_by_dhcp6_pd_prefix(link->manager, &prefix.in6, &assigned_link) >= 0 &&
+ if (link_get_by_dhcp6_pd_prefix(link->manager, &prefix, &assigned_link) >= 0 &&
assigned_link != link) {
_cleanup_free_ char *assigned_buf = NULL;
- (void) in6_addr_to_string(&prefix.in6, &assigned_buf);
+ (void) in6_addr_to_string(&prefix, &assigned_buf);
return log_link_warning_errno(link, SYNTHETIC_ERRNO(EAGAIN),
"The requested prefix %s is already assigned to another link.",
strna(assigned_buf));
}
- *ret = prefix.in6;
+ *ret = prefix;
return 0;
}
- for (uint64_t n = 0; n < n_prefixes; n++) {
+ for (uint64_t n = 0; ; n++) {
+ r = dhcp6_pd_calculate_prefix(pd_prefix, pd_prefix_len, n, &prefix);
+ if (r < 0)
+ return log_link_warning_errno(link, r,
+ "Couldn't find a suitable prefix. Ran out of address space.");
+
/* If we do not have an allocation preference just iterate
* through the address space and return the first free prefix. */
- if (link_get_by_dhcp6_pd_prefix(link->manager, &prefix.in6, &assigned_link) < 0 ||
+ if (link_get_by_dhcp6_pd_prefix(link->manager, &prefix, &assigned_link) < 0 ||
assigned_link == link) {
- *ret = prefix.in6;
+ *ret = prefix;
return 0;
}
-
- r = in_addr_prefix_next(AF_INET6, &prefix, 64);
- if (r < 0)
- return log_link_warning_errno(link, r, "Can't allocate another prefix. Out of address space?: %m");
}
-
- return log_link_warning_errno(link, SYNTHETIC_ERRNO(ERANGE), "Couldn't find a suitable prefix. Ran out of address space.");
}
static int dhcp6_pd_prefix_distribute(
@@ -560,7 +569,7 @@ static int dhcp6_pd_prefix_distribute(
continue;
if (dhcp6_pd_get_assigned_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix) < 0 &&
- dhcp6_get_preferred_delegated_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix) < 0)
+ dhcp6_pd_get_preferred_prefix(link, pd_prefix, pd_prefix_len, &assigned_prefix) < 0)
continue;
(void) in6_addr_prefix_to_string(&assigned_prefix, 64, &buf);