From 5f950e56211a90b21e8096ebf27c9c2b8afbd231 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 30 May 2023 14:50:17 +0900 Subject: [PATCH 1/3] network: rewrite dynamic addressing protocol checkers in link_check_ready() Notable change is, - UseAddress=no in [DHCPv6], - Assign=no in [DHCPPrefixDelegation], and - UseAutonomousPrefix=no in [IPv6AcceptRA] are gracefully handled now. --- src/network/networkd-address.c | 23 +++++++++++ src/network/networkd-address.h | 1 + src/network/networkd-link.c | 72 +++++++++++++++++----------------- 3 files changed, 59 insertions(+), 37 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index b8b9dc153b..5c87a6c9c7 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -161,6 +161,29 @@ bool address_is_ready(const Address *a) { return true; } +bool link_check_addresses_ready(Link *link, NetworkConfigSource source) { + Address *a; + bool has = false; + + assert(link); + + /* Check if all addresses on the interface are ready. If there is no address, this will return false. */ + + SET_FOREACH(a, link->addresses) { + if (source >= 0 && a->source != source) + continue; + if (address_is_marked(a)) + continue; + if (!address_exists(a)) + continue; + if (!address_is_ready(a)) + return false; + has = true; + } + + return has; +} + void link_mark_addresses(Link *link, NetworkConfigSource source) { Address *a; diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 89b9621791..18eeb6e48e 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -81,6 +81,7 @@ int address_remove(Address *address); int address_remove_and_drop(Address *address); int address_dup(const Address *src, Address **ret); bool address_is_ready(const Address *a); +bool link_check_addresses_ready(Link *link, NetworkConfigSource source); void address_set_broadcast(Address *a, Link *link); DEFINE_SECTION_CLEANUP_FUNCTIONS(Address, address_free); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index f2839ecf88..c0ad17f9f1 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -436,47 +436,45 @@ void link_check_ready(Link *link) { !in6_addr_is_set(&link->ipv6ll_address)) return (void) log_link_debug(link, "%s(): IPv6LL is not configured yet.", __func__); - bool has_dynamic_address = false; - SET_FOREACH(a, link->addresses) { - if (address_is_marked(a)) - continue; - if (!address_exists(a)) - continue; - if (IN_SET(a->source, - NETWORK_CONFIG_SOURCE_IPV4LL, - NETWORK_CONFIG_SOURCE_DHCP4, - NETWORK_CONFIG_SOURCE_DHCP6, - NETWORK_CONFIG_SOURCE_DHCP_PD, - NETWORK_CONFIG_SOURCE_NDISC)) { - has_dynamic_address = true; - break; - } - } + /* If no dynamic addressing protocol enabled, assume the interface is ready. + * Note, ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */ + if (!link_ipv4ll_enabled(link) && !link_dhcp4_enabled(link) && + !link_dhcp6_enabled(link) && !link_dhcp_pd_is_enabled(link) && + (link->network->configure_without_carrier || !link_ipv6_accept_ra_enabled(link))) + goto ready; - if ((link_ipv4ll_enabled(link) || link_dhcp4_enabled(link) || link_dhcp6_with_address_enabled(link) || - (link_dhcp_pd_is_enabled(link) && link->network->dhcp_pd_assign)) && !has_dynamic_address) - /* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */ - return (void) log_link_debug(link, "%s(): DHCPv4, DHCPv6, DHCP-PD or IPv4LL is enabled but no dynamic address is assigned yet.", __func__); + bool ipv4ll_ready = + link_ipv4ll_enabled(link) && link->ipv4ll_address_configured && + link_check_addresses_ready(link, NETWORK_CONFIG_SOURCE_IPV4LL); + bool dhcp4_ready = + link_dhcp4_enabled(link) && link->dhcp4_configured && + link_check_addresses_ready(link, NETWORK_CONFIG_SOURCE_DHCP4); + bool dhcp6_ready = + link_dhcp6_enabled(link) && link->dhcp6_configured && + (!link->network->dhcp6_use_address || + link_check_addresses_ready(link, NETWORK_CONFIG_SOURCE_DHCP6)); + bool dhcp_pd_ready = + link_dhcp_pd_is_enabled(link) && link->dhcp_pd_configured && + (!link->network->dhcp_pd_assign || + link_check_addresses_ready(link, NETWORK_CONFIG_SOURCE_DHCP_PD)); + bool ndisc_ready = + link_ipv6_accept_ra_enabled(link) && link->ndisc_configured && + (!link->network->ipv6_accept_ra_use_autonomous_prefix || + link_check_addresses_ready(link, NETWORK_CONFIG_SOURCE_NDISC)); - /* Ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */ - if (link_ipv4ll_enabled(link) || link_dhcp4_enabled(link) || - link_dhcp6_enabled(link) || link_dhcp_pd_is_enabled(link) || - (!link->network->configure_without_carrier && link_ipv6_accept_ra_enabled(link))) { + /* At least one dynamic addressing protocol is finished. */ + if (!ipv4ll_ready && !dhcp4_ready && !dhcp6_ready && !dhcp_pd_ready && !ndisc_ready) + return (void) log_link_debug(link, "%s(): dynamic addressing protocols are enabled but none of them finished yet.", __func__); - if (!link->ipv4ll_address_configured && !link->dhcp4_configured && - !link->dhcp6_configured && !link->dhcp_pd_configured && !link->ndisc_configured) - /* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */ - return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__); - - log_link_debug(link, "%s(): IPv4LL:%s DHCPv4:%s DHCPv6:%s DHCP-PD:%s NDisc:%s", - __func__, - yes_no(link->ipv4ll_address_configured), - yes_no(link->dhcp4_configured), - yes_no(link->dhcp6_configured), - yes_no(link->dhcp_pd_configured), - yes_no(link->ndisc_configured)); - } + log_link_debug(link, "%s(): IPv4LL:%s DHCPv4:%s DHCPv6:%s DHCP-PD:%s NDisc:%s", + __func__, + yes_no(ipv4ll_ready), + yes_no(dhcp4_ready), + yes_no(dhcp6_ready), + yes_no(dhcp_pd_ready), + yes_no(ndisc_ready)); +ready: link_set_state(link, LINK_STATE_CONFIGURED); } From 195b83edf852f4e40e0d3a3b630cde97c84d77ba Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 30 May 2023 15:29:05 +0900 Subject: [PATCH 2/3] network: require DHCP protocol to be finished when an address of delegated prefix is assigned --- src/network/networkd-link.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index c0ad17f9f1..ec6d03ff02 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -462,6 +462,25 @@ void link_check_ready(Link *link) { (!link->network->ipv6_accept_ra_use_autonomous_prefix || link_check_addresses_ready(link, NETWORK_CONFIG_SOURCE_NDISC)); + /* If the uplink for PD is self, then request the corresponding DHCP protocol is also ready. */ + if (dhcp_pd_is_uplink(link, link, /* accept_auto = */ false)) { + if (link_dhcp4_enabled(link) && link->network->dhcp_use_6rd && + link->dhcp_lease && dhcp4_lease_has_pd_prefix(link->dhcp_lease)) { + if (!dhcp4_ready) + return (void) log_link_debug(link, "%s(): DHCPv4 6rd prefix is assigned, but DHCPv4 protocol is not finished yet.", __func__); + if (!dhcp_pd_ready) + return (void) log_link_debug(link, "%s(): DHCPv4 is finished, but prefix acquired by DHCPv4-6rd is not assigned yet.", __func__); + } + + if (link_dhcp6_enabled(link) && link->network->dhcp6_use_pd_prefix && + link->dhcp6_lease && dhcp6_lease_has_pd_prefix(link->dhcp6_lease)) { + if (!dhcp6_ready) + return (void) log_link_debug(link, "%s(): DHCPv6 IA_PD prefix is assigned, but DHCPv6 protocol is not finished yet.", __func__); + if (!dhcp_pd_ready) + return (void) log_link_debug(link, "%s(): DHCPv6 is finished, but prefix acquired by DHCPv6 IA_PD is not assigned yet.", __func__); + } + } + /* At least one dynamic addressing protocol is finished. */ if (!ipv4ll_ready && !dhcp4_ready && !dhcp6_ready && !dhcp_pd_ready && !ndisc_ready) return (void) log_link_debug(link, "%s(): dynamic addressing protocols are enabled but none of them finished yet.", __func__); From 9e7d91ed97a008a47e347d99b02de376d55d3449 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 29 May 2023 12:56:30 +0900 Subject: [PATCH 3/3] network: do not request dynamic addressing protocols finished when at least one static address is configured The setting IPv6AcceptRA= is defaults to yes, hence, even if a .network file for an interface has static IP address configuration, it may takes few seconds for the interface being configured state, as NDisc for the interface needs to be finished. That makes wait-online.service needlessly slow. Typically, such delay is not necessary for statically configured networks. Let's make the required condition slightly relaxed; if a .network file has static IP address configurations, then let's make the matching interface enter the 'configured' state soon after the static addresses configured on the interface. Note, this does not change the default for IPv6AcceptRA=, hence, NDisc still runs on interfaces by default. So, addresses, routes, DNS servers, and so on based on RA will be assigned on interfaces later. Strictly speaking, this breaks backward compatibility, but the previous behavior is not clearly documented. If a user requested both static IPv4 address and IPv6 SLAAC address configured before an interface being entered to the 'configured' state, then '--ipv6' for wait-online can be used. So, the behavior change should not cause severe regression. Closes #27779. --- src/network/networkd-link.c | 20 +++++++++++++++----- test/test-network/systemd-networkd-tests.py | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ec6d03ff02..d16090dbcd 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -398,11 +398,6 @@ void link_check_ready(Link *link) { if (!link->static_addresses_configured) return (void) log_link_debug(link, "%s(): static addresses are not configured.", __func__); - SET_FOREACH(a, link->addresses) - if (!address_is_ready(a)) - return (void) log_link_debug(link, "%s(): address %s is not ready.", __func__, - IN_ADDR_PREFIX_TO_STRING(a->family, &a->in_addr, a->prefixlen)); - if (!link->static_address_labels_configured) return (void) log_link_debug(link, "%s(): static address labels are not configured.", __func__); @@ -436,6 +431,21 @@ void link_check_ready(Link *link) { !in6_addr_is_set(&link->ipv6ll_address)) return (void) log_link_debug(link, "%s(): IPv6LL is not configured yet.", __func__); + /* All static addresses must be ready. */ + bool has_static_address = false; + SET_FOREACH(a, link->addresses) { + if (a->source != NETWORK_CONFIG_SOURCE_STATIC) + continue; + if (!address_is_ready(a)) + return (void) log_link_debug(link, "%s(): static address %s is not ready.", __func__, + IN_ADDR_PREFIX_TO_STRING(a->family, &a->in_addr, a->prefixlen)); + has_static_address = true; + } + + /* If at least one static address is requested, do not request that dynamic addressing protocols are finished. */ + if (has_static_address) + goto ready; + /* If no dynamic addressing protocol enabled, assume the interface is ready. * Note, ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */ if (!link_ipv4ll_enabled(link) && !link_dhcp4_enabled(link) && diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 8b01718d55..2fd3f10021 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -4676,6 +4676,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): '--dhcp-alternate-port=67,5555', ipv4_range='192.168.5.110,192.168.5.119') self.wait_online(['veth99:routable', 'veth-peer:routable']) + self.wait_address('veth99', r'inet 192.168.5.11[0-9]*/24', ipv='-4') print('## ip address show dev veth99 scope global') output = check_output('ip address show dev veth99 scope global')