1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-28 02:50:16 +03:00

Merge pull request #21119 from yuwata/network-dhcp6-pd-cleanups

network: dhcp6pd: several cleanups
This commit is contained in:
Yu Watanabe 2021-10-26 08:10:56 +09:00 committed by GitHub
commit e817f5b0f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 110 additions and 87 deletions

View File

@ -421,35 +421,6 @@ static int dhcp6_pd_request_address(
return 0;
}
static int dhcp6_pd_assign_prefix(
Link *link,
const struct in6_addr *prefix,
usec_t lifetime_preferred_usec,
usec_t lifetime_valid_usec) {
int r;
assert(link);
assert(link->network);
assert(prefix);
if (link->network->dhcp6_pd_announce) {
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, lifetime_valid_usec);
if (r < 0)
return r;
r = dhcp6_pd_request_address(link, prefix, lifetime_preferred_usec, lifetime_valid_usec);
if (r < 0)
return r;
return link_add_dhcp6_pd_prefix(link, prefix);
}
static bool link_has_preferred_subnet_id(Link *link) {
if (!link->network)
return false;
@ -457,77 +428,137 @@ 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);
link->network->dhcp6_pd_subnet_id, UINT64_C(1) << (64 - pd_prefix_len));
/* 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);
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(
static int dhcp6_pd_assign_prefix(
Link *link,
const struct in6_addr *pd_prefix,
uint8_t pd_prefix_len,
usec_t lifetime_preferred_usec,
usec_t lifetime_valid_usec) {
_cleanup_free_ char *buf = NULL;
struct in6_addr prefix;
int r;
assert(link);
assert(link->network);
assert(pd_prefix);
if (dhcp6_pd_get_assigned_prefix(link, pd_prefix, pd_prefix_len, &prefix) < 0 &&
dhcp6_pd_get_preferred_prefix(link, pd_prefix, pd_prefix_len, &prefix) < 0)
return 0;
(void) in6_addr_prefix_to_string(&prefix, 64, &buf);
if (link->network->dhcp6_pd_announce) {
r = radv_add_prefix(link, &prefix, 64, lifetime_preferred_usec, lifetime_valid_usec);
if (r < 0)
return log_link_warning_errno(link, r,
"Failed to assign/update prefix %s to IPv6 Router Advertisement: %m",
strna(buf));
}
r = dhcp6_pd_request_route(link, &prefix, lifetime_valid_usec);
if (r < 0)
return log_link_warning_errno(link, r,
"Failed to assign/update route for prefix %s: %m",
strna(buf));
r = dhcp6_pd_request_address(link, &prefix, lifetime_preferred_usec, lifetime_valid_usec);
if (r < 0)
return log_link_warning_errno(link, r,
"Failed to assign/update address for prefix %s: %m",
strna(buf));
r = link_add_dhcp6_pd_prefix(link, &prefix);
if (r < 0)
return log_link_warning_errno(link, r,
"Failed to save assigned prefix %s: %m",
strna(buf));
log_link_debug(link, "Assigned prefix %s", strna(buf));
return 1;
}
static int dhcp6_pd_distribute_prefix(
Link *dhcp6_link,
const struct in6_addr *pd_prefix,
uint8_t pd_prefix_len,
@ -544,8 +575,6 @@ static int dhcp6_pd_prefix_distribute(
assert(pd_prefix_len <= 64);
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
_cleanup_free_ char *buf = NULL;
struct in6_addr assigned_prefix;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
continue;
@ -559,22 +588,14 @@ static int dhcp6_pd_prefix_distribute(
if (assign_preferred_subnet_id != link_has_preferred_subnet_id(link))
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)
continue;
(void) in6_addr_prefix_to_string(&assigned_prefix, 64, &buf);
r = dhcp6_pd_assign_prefix(link, &assigned_prefix, lifetime_preferred_usec, lifetime_valid_usec);
r = dhcp6_pd_assign_prefix(link, pd_prefix, pd_prefix_len, 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)
return r;
link_enter_failed(link);
continue;
}
log_link_debug(link, "Assigned prefix %s", strna(buf));
}
return 0;
@ -906,7 +927,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
n_prefixes, strna(buf));
}
r = dhcp6_pd_prefix_distribute(dhcp6_link,
r = dhcp6_pd_distribute_prefix(dhcp6_link,
&pd_prefix,
pd_prefix_len,
lifetime_preferred_usec,
@ -915,7 +936,7 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) {
if (r < 0)
return r;
r = dhcp6_pd_prefix_distribute(dhcp6_link,
r = dhcp6_pd_distribute_prefix(dhcp6_link,
&pd_prefix,
pd_prefix_len,
lifetime_preferred_usec,
@ -1535,10 +1556,12 @@ static int dhcp6_configure(Link *link) {
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix delegation: %m");
}
if (link->network->dhcp6_pd_length > 0) {
r = sd_dhcp6_client_set_prefix_delegation_hint(client, link->network->dhcp6_pd_length, &link->network->dhcp6_pd_address);
if (link->network->dhcp6_pd_prefix_length > 0) {
r = sd_dhcp6_client_set_prefix_delegation_hint(client,
link->network->dhcp6_pd_prefix_length,
&link->network->dhcp6_pd_prefix_hint);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix hint: %m");
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix delegation hint: %m");
}
link->dhcp6_client = TAKE_PTR(client);
@ -1651,7 +1674,7 @@ int link_serialize_dhcp6_client(Link *link, FILE *f) {
return 0;
}
int config_parse_dhcp6_pd_hint(
int config_parse_dhcp6_pd_prefix_hint(
const char* unit,
const char *filename,
unsigned line,
@ -1663,7 +1686,7 @@ int config_parse_dhcp6_pd_hint(
void *data,
void *userdata) {
Network *network = data;
Network *network = userdata;
union in_addr_union u;
unsigned char prefixlen;
int r;
@ -1671,7 +1694,7 @@ int config_parse_dhcp6_pd_hint(
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
assert(userdata);
r = in_addr_prefix_from_string(rvalue, AF_INET6, &u, &prefixlen);
if (r < 0) {
@ -1686,8 +1709,8 @@ int config_parse_dhcp6_pd_hint(
return 0;
}
network->dhcp6_pd_address = u.in6;
network->dhcp6_pd_length = prefixlen;
network->dhcp6_pd_prefix_hint = u.in6;
network->dhcp6_pd_prefix_length = prefixlen;
return 0;
}

View File

@ -29,7 +29,7 @@ int link_request_dhcp6_client(Link *link);
int link_serialize_dhcp6_client(Link *link, FILE *f);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_prefix_hint);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_client_start_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_subnet_id);

View File

@ -248,7 +248,7 @@ DHCPv6.UserClass, config_parse_dhcp_user_or_vendor_cl
DHCPv6.VendorClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_vendor_class)
DHCPv6.SendVendorOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_vendor_options)
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_prefix_hint, 0, 0
DHCPv6.WithoutRA, config_parse_dhcp6_client_start_mode, 0, offsetof(Network, dhcp6_without_ra)
DHCPv6.SendOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_options)
DHCPv6.IAID, config_parse_iaid, AF_INET6, 0

View File

@ -183,11 +183,11 @@ struct Network {
bool dhcp6_iaid_set;
bool dhcp6_iaid_set_explicitly;
DUID dhcp6_duid;
uint8_t dhcp6_pd_length;
uint8_t dhcp6_pd_prefix_length;
struct in6_addr dhcp6_pd_prefix_hint;
char *dhcp6_mudurl;
char **dhcp6_user_class;
char **dhcp6_vendor_class;
struct in6_addr dhcp6_pd_address;
DHCP6ClientStartMode dhcp6_without_ra;
OrderedHashmap *dhcp6_client_send_options;
OrderedHashmap *dhcp6_client_send_vendor_options;