diff --git a/src/network/networkd-dhcp-prefix-delegation.c b/src/network/networkd-dhcp-prefix-delegation.c index 24bafb8b4a..0bc922d400 100644 --- a/src/network/networkd-dhcp-prefix-delegation.c +++ b/src/network/networkd-dhcp-prefix-delegation.c @@ -570,47 +570,6 @@ static int dhcp6_pd_assign_prefix( return 1; } -static int dhcp6_pd_distribute_prefix( - Link *dhcp6_link, - const struct in6_addr *pd_prefix, - uint8_t pd_prefix_len, - usec_t lifetime_preferred_usec, - usec_t lifetime_valid_usec) { - - Link *link; - int r; - - assert(dhcp6_link); - assert(dhcp6_link->manager); - assert(pd_prefix); - assert(pd_prefix_len <= 64); - - HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) { - if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) - continue; - - if (!dhcp6_pd_is_uplink(link, dhcp6_link, /* accept_auto = */ true)) - continue; - - if (link->network->dhcp6_pd_announce && !link->radv) - continue; - - if (link == dhcp6_link && !link->network->dhcp6_pd_assign) - continue; - - r = dhcp6_pd_assign_prefix(link, pd_prefix, pd_prefix_len, lifetime_preferred_usec, lifetime_valid_usec); - if (r < 0) { - if (link == dhcp6_link) - return r; - - link_enter_failed(link); - continue; - } - } - - return 0; -} - static int dhcp6_pd_prepare(Link *link) { if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) return 0; @@ -624,7 +583,7 @@ static int dhcp6_pd_prepare(Link *link) { link_mark_addresses(link, NETWORK_CONFIG_SOURCE_DHCP6PD, NULL); link_mark_routes(link, NETWORK_CONFIG_SOURCE_DHCP6PD, NULL); - return 0; + return 1; } static int dhcp6_pd_finalize(Link *link) { @@ -633,12 +592,6 @@ static int dhcp6_pd_finalize(Link *link) { if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) return 0; - if (!link_dhcp6_pd_is_enabled(link)) - return 0; - - if (link->network->dhcp6_pd_announce && !link->radv) - return 0; - if (link->dhcp6_pd_messages == 0) { link->dhcp6_pd_configured = false; @@ -793,103 +746,6 @@ static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_ return prefixlen <= 64; } -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(), ×tamp_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) { - r = dhcp6_pd_prepare(link); - if (r < 0) { - /* When failed on the upstream interface (i.e., the case link == dhcp6_link), - * immediately abort the assignment of the prefixes. As, the all assigned - * prefixes will be dropped soon in link_enter_failed(), and it is meaningless - * to continue the assignment. */ - if (link == dhcp6_link) - return r; - - link_enter_failed(link); - } - } - - for (sd_dhcp6_lease_reset_pd_prefix_iter(dhcp6_link->dhcp6_lease);;) { - uint32_t lifetime_preferred_sec, lifetime_valid_sec; - usec_t lifetime_preferred_usec, lifetime_valid_usec; - struct in6_addr pd_prefix; - uint8_t pd_prefix_len; - - r = sd_dhcp6_lease_get_pd(dhcp6_link->dhcp6_lease, &pd_prefix, &pd_prefix_len, - &lifetime_preferred_sec, &lifetime_valid_sec); - if (r < 0) - break; - - lifetime_preferred_usec = usec_add(lifetime_preferred_sec * USEC_PER_SEC, timestamp_usec); - lifetime_valid_usec = usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec); - - r = dhcp6_pd_prefix_add(dhcp6_link, &pd_prefix, pd_prefix_len); - if (r < 0) - return r; - if (r == 0) - continue; - - r = dhcp6_request_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len, lifetime_valid_usec); - if (r < 0) - return r; - - /* We are doing prefix allocation in two steps: - * 1. all those links that have a preferred subnet id will be assigned their subnet - * 2. all those links that remain will receive prefixes in sequential order. Prefixes - * that were previously already allocated to another link will be skipped. - * The assignment has to be split in two phases since subnet id - * preferences should be honored. Meaning that any subnet id should be - * handed out to the requesting link and not to some link that didn't - * specify any preference. */ - - assert(pd_prefix_len <= 64); - - /* Mask prefix for safety. */ - r = in6_addr_mask(&pd_prefix, pd_prefix_len); - if (r < 0) - return log_link_error_errno(dhcp6_link, r, "Failed to mask DHCPv6 PD prefix: %m"); - - if (DEBUG_LOGGING) { - uint64_t n_prefixes = UINT64_C(1) << (64 - pd_prefix_len); - _cleanup_free_ char *buf = NULL; - - (void) in6_addr_prefix_to_string(&pd_prefix, pd_prefix_len, &buf); - log_link_debug(dhcp6_link, "Assigning up to %" PRIu64 " prefixes from %s", - n_prefixes, strna(buf)); - } - - r = dhcp6_pd_distribute_prefix(dhcp6_link, - &pd_prefix, - pd_prefix_len, - lifetime_preferred_usec, - lifetime_valid_usec); - if (r < 0) - return r; - } - - HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) { - r = dhcp6_pd_finalize(link); - if (r < 0) { - if (link == dhcp6_link) - return r; - - link_enter_failed(link); - } - } - - return 0; -} - static int dhcp6_pd_assign_prefixes(Link *link, Link *uplink) { usec_t timestamp_usec; int r; @@ -898,14 +754,11 @@ static int dhcp6_pd_assign_prefixes(Link *link, Link *uplink) { assert(uplink); assert(uplink->dhcp6_lease); - /* This is similar to dhcp6_pd_prefix_acquired(), but called when a downstream interface - * appears later or reconfiguring the interface. */ - - r = sd_dhcp6_lease_get_timestamp(uplink->dhcp6_lease, clock_boottime_or_monotonic(), ×tamp_usec); - if (r < 0) + r = dhcp6_pd_prepare(link); + if (r <= 0) return r; - r = dhcp6_pd_prepare(link); + r = sd_dhcp6_lease_get_timestamp(uplink->dhcp6_lease, clock_boottime_or_monotonic(), ×tamp_usec); if (r < 0) return r; @@ -920,9 +773,6 @@ static int dhcp6_pd_assign_prefixes(Link *link, Link *uplink) { if (r < 0) break; - lifetime_preferred_usec = usec_add(lifetime_preferred_sec * USEC_PER_SEC, timestamp_usec); - lifetime_valid_usec = usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec); - if (pd_prefix_len > 64) continue; @@ -931,14 +781,76 @@ static int dhcp6_pd_assign_prefixes(Link *link, Link *uplink) { if (r < 0) return r; + lifetime_preferred_usec = usec_add(lifetime_preferred_sec * USEC_PER_SEC, timestamp_usec); + lifetime_valid_usec = usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec); + r = dhcp6_pd_assign_prefix(link, &pd_prefix, pd_prefix_len, lifetime_preferred_usec, lifetime_valid_usec); if (r < 0) return r; } - r = dhcp6_pd_finalize(link); + return dhcp6_pd_finalize(link); +} + +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(), ×tamp_usec); if (r < 0) - return r; + return log_link_warning_errno(dhcp6_link, r, "Failed to get timestamp of DHCPv6 lease: %m"); + + /* First, logs acquired prefixes and request unreachable routes. */ + for (sd_dhcp6_lease_reset_pd_prefix_iter(dhcp6_link->dhcp6_lease);;) { + uint32_t lifetime_preferred_sec, lifetime_valid_sec; + usec_t lifetime_valid_usec; + struct in6_addr pd_prefix; + uint8_t pd_prefix_len; + + r = sd_dhcp6_lease_get_pd(dhcp6_link->dhcp6_lease, &pd_prefix, &pd_prefix_len, + &lifetime_preferred_sec, &lifetime_valid_sec); + if (r < 0) + break; + + /* Mask prefix for safety. */ + r = in6_addr_mask(&pd_prefix, pd_prefix_len); + if (r < 0) + return log_link_error_errno(dhcp6_link, r, "Failed to mask DHCPv6 PD prefix: %m"); + + lifetime_valid_usec = usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec); + + r = dhcp6_pd_prefix_add(dhcp6_link, &pd_prefix, pd_prefix_len); + if (r < 0) + return r; + if (r == 0) + continue; + + r = dhcp6_request_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len, lifetime_valid_usec); + if (r < 0) + return r; + } + + /* Then, assign subnet prefixes. */ + HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) { + if (!dhcp6_pd_is_uplink(link, dhcp6_link, /* accept_auto = */ true)) + continue; + + r = dhcp6_pd_assign_prefixes(link, dhcp6_link); + if (r < 0) { + /* When failed on the upstream interface (i.e., the case link == dhcp6_link), + * immediately abort the assignment of the prefixes. As, the all assigned + * prefixes will be dropped soon in link_enter_failed(), and it is meaningless + * to continue the assignment. */ + if (link == dhcp6_link) + return r; + + link_enter_failed(link); + } + } return 0; }