From 56bbe0ef02bc783875c12dd238740a846b775399 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 21 Oct 2021 05:16:52 +0900 Subject: [PATCH 1/3] network: dhcp6pd: introduce a simplified and unified method to calculate subnet prefix --- src/network/networkd-dhcp6.c | 75 ++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index a92394554af..837368b829d 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); + 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( @@ -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); From 78e50edfd48a05b8ccd947a29a25c1833c4239e8 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 21 Oct 2021 16:42:31 +0900 Subject: [PATCH 2/3] network: dhcp6pd: move logic of acquiring subnet prefix into dhcp6_pd_assign_prefix() Preparation for later commits. --- src/network/networkd-dhcp6.c | 98 ++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 837368b829d..352e883a1cc 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -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; @@ -536,7 +507,58 @@ static int dhcp6_pd_get_preferred_prefix( } } -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, @@ -553,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; @@ -568,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_pd_get_preferred_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; @@ -915,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, @@ -924,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, From df8bf726311ba00ef851ea9600f002860c9f713c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 13 Oct 2021 16:12:51 +0900 Subject: [PATCH 3/3] network: dhcp6: rename variables --- src/network/networkd-dhcp6.c | 18 ++++++++++-------- src/network/networkd-dhcp6.h | 2 +- src/network/networkd-network-gperf.gperf | 2 +- src/network/networkd-network.h | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 352e883a1cc..059313d68bc 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -1556,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); @@ -1672,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, @@ -1684,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; @@ -1692,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) { @@ -1707,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; } diff --git a/src/network/networkd-dhcp6.h b/src/network/networkd-dhcp6.h index 72f196ad514..a08d03b6144 100644 --- a/src/network/networkd-dhcp6.h +++ b/src/network/networkd-dhcp6.h @@ -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); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 2a75a98bee8..a6415c23110 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -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 diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index bea882019a4..b23f70b356e 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -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;