From: Yu Watanabe Date: Thu, 23 Jul 2020 15:52:32 +0000 (+0900) Subject: network: do not assume static addresses are configured X-Git-Tag: v246~14^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e55265184b305aef166a41d8eb50237e74b0a6fd;p=thirdparty%2Fsystemd.git network: do not assume static addresses are configured link_request_set_routes() is also called when a dynamic address is configured. At that time, static addresses may not be configured yet. Fixes #16546. --- diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index a848151c8b5..747acfe6c5e 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -125,6 +125,7 @@ void address_free(Address *address) { if (address->link && !address->acd) { set_remove(address->link->addresses, address); set_remove(address->link->addresses_foreign, address); + set_remove(address->link->static_addresses, address); if (address->link->dhcp_address == address) address->link->dhcp_address = NULL; if (address->link->dhcp_address_old == address) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 894b55f4c5d..47bdd2a0dc7 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -730,6 +730,7 @@ static Link *link_free(Link *link) { link->addresses = set_free(link->addresses); link->addresses_foreign = set_free(link->addresses_foreign); + link->static_addresses = set_free(link->static_addresses); link->dhcp6_addresses = set_free(link->dhcp6_addresses); link->dhcp6_addresses_old = set_free(link->dhcp6_addresses_old); link->dhcp6_pd_addresses = set_free(link->dhcp6_pd_addresses); @@ -1057,12 +1058,13 @@ int link_request_set_routes(Link *link) { assert(link); assert(link->network); - assert(link->addresses_configured); - assert(link->address_messages == 0); assert(link->state != _LINK_STATE_INVALID); link->static_routes_configured = false; + if (!link->addresses_ready) + return 0; + if (!link_has_carrier(link) && !link->network->configure_without_carrier) /* During configuring addresses, the link lost its carrier. As networkd is dropping * the addresses now, let's not configure the routes either. */ @@ -1102,7 +1104,6 @@ int link_request_set_routes(Link *link) { void link_check_ready(Link *link) { Address *a; Iterator i; - int r; assert(link); @@ -1136,15 +1137,6 @@ void link_check_ready(Link *link) { return; } - if (!link->addresses_ready) { - link->addresses_ready = true; - r = link_request_set_routes(link); - if (r < 0) - link_enter_failed(link); - log_link_debug(link, "%s(): static addresses are configured. Configuring static routes.", __func__); - return; - } - if (!link->static_routes_configured) { log_link_debug(link, "%s(): static routes are not configured.", __func__); return; @@ -1246,6 +1238,50 @@ static int link_request_set_neighbors(Link *link) { return 0; } +static int link_set_bridge_fdb(Link *link) { + FdbEntry *fdb_entry; + int r; + + LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) { + r = fdb_entry_configure(link, fdb_entry); + if (r < 0) + return log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m"); + } + + return 0; +} + +static int static_address_ready_callback(Address *address) { + Address *a; + Iterator i; + Link *link; + + assert(address); + assert(address->link); + + link = address->link; + + if (!link->addresses_configured) + return 0; + + SET_FOREACH(a, link->static_addresses, i) + if (!address_is_ready(a)) { + _cleanup_free_ char *str = NULL; + + (void) in_addr_to_string(a->family, &a->in_addr, &str); + log_link_debug(link, "an address %s/%u is not ready", strnull(str), a->prefixlen); + return 0; + } + + /* This should not be called again */ + SET_FOREACH(a, link->static_addresses, i) + a->callback = NULL; + + link->addresses_ready = true; + + return link_request_set_routes(link); +} + static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; @@ -1271,23 +1307,50 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) (void) manager_rtnl_process_address(rtnl, m, link->manager); if (link->address_messages == 0) { + Address *a; + log_link_debug(link, "Addresses set"); link->addresses_configured = true; - link_check_ready(link); + + /* When all static addresses are already ready, then static_address_ready_callback() + * will not be called automatically. So, call it here. */ + a = set_first(link->static_addresses); + if (!a) { + log_link_warning(link, "No static address is stored."); + link_enter_failed(link); + return 1; + } + if (!a->callback) { + log_link_warning(link, "Address ready callback is not set."); + link_enter_failed(link); + return 1; + } + r = a->callback(a); + if (r < 0) + link_enter_failed(link); } return 1; } -static int link_set_bridge_fdb(Link *link) { - FdbEntry *fdb_entry; +static int static_address_configure(Address *address, Link *link, bool update) { + Address *ret; int r; - LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) { - r = fdb_entry_configure(link, fdb_entry); - if (r < 0) - return log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m"); - } + assert(address); + assert(link); + + r = address_configure(address, link, address_handler, update, &ret); + if (r < 0) + return log_link_warning_errno(link, r, "Could not configure static address: %m"); + + link->address_messages++; + + r = set_ensure_put(&link->static_addresses, &address_hash_ops, ret); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to store static address: %m"); + + ret->callback = static_address_ready_callback; return 0; } @@ -1326,11 +1389,9 @@ static int link_request_set_addresses(Link *link) { else update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0; - r = address_configure(ad, link, address_handler, update, NULL); + r = static_address_configure(ad, link, update); if (r < 0) - return log_link_warning_errno(link, r, "Could not set addresses: %m"); - if (r > 0) - link->address_messages++; + return r; } if (IN_SET(link->network->router_prefix_delegation, @@ -1344,22 +1405,20 @@ static int link_request_set_addresses(Link *link) { r = address_new(&address); if (r < 0) - return log_link_error_errno(link, r, "Could not allocate address: %m"); + return log_oom(); r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen); if (r < 0) - return r; + return log_link_warning_errno(link, r, "Could not get RA prefix: %m"); r = generate_ipv6_eui_64_address(link, &address->in_addr.in6); if (r < 0) - return r; + return log_link_warning_errno(link, r, "Could not generate EUI64 address: %m"); address->family = AF_INET6; - r = address_configure(address, link, address_handler, true, NULL); + r = static_address_configure(address, link, true); if (r < 0) - return log_link_warning_errno(link, r, "Could not set addresses: %m"); - if (r > 0) - link->address_messages++; + return r; } LIST_FOREACH(labels, label, link->network->address_labels) { @@ -1370,8 +1429,7 @@ static int link_request_set_addresses(Link *link) { link->address_label_messages++; } - /* now that we can figure out a default address for the dhcp server, - start it */ + /* now that we can figure out a default address for the dhcp server, start it */ if (link_dhcp4_server_enabled(link) && (link->flags & IFF_UP)) { r = dhcp4_server_configure(link); if (r < 0) @@ -1381,7 +1439,10 @@ static int link_request_set_addresses(Link *link) { if (link->address_messages == 0) { link->addresses_configured = true; - link_check_ready(link); + link->addresses_ready = true; + r = link_request_set_routes(link); + if (r < 0) + return r; } else { log_link_debug(link, "Setting addresses"); link_set_state(link, LINK_STATE_CONFIGURING); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 3cd4a192895..7f99c0f47b2 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -87,6 +87,7 @@ typedef struct Link { Set *addresses; Set *addresses_foreign; + Set *static_addresses; Set *neighbors; Set *neighbors_foreign; Set *routes;