From: Yu Watanabe Date: Tue, 12 Mar 2024 08:35:51 +0000 (+0900) Subject: network/address: acquire address in address_process_request() X-Git-Tag: v256-rc1~510 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dbf66cd1ab09109cb0fccfd5ff49dd179ecefc34;p=thirdparty%2Fsystemd.git network/address: acquire address in address_process_request() Previously, if an [Address] section is configured with a null address, e.g. Address=0.0.0.0/24, then we acquired a free address in link_request_address(). With this commit, we queue a request with the null address as is, and acquire a free address later in address_process_request(). Similary, now IPv4ACD daemon is configured in address_process_request(). With this change, we can make the address acquisition depend on other conditions, e.g. if the persistent storage is ready or not. --- diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 49a43753c5e..d9c3dae85c5 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -1415,43 +1415,6 @@ void link_foreignize_addresses(Link *link) { address->source = NETWORK_CONFIG_SOURCE_FOREIGN; } -static int address_acquire(Link *link, const Address *original, Address **ret) { - _cleanup_(address_unrefp) Address *na = NULL; - union in_addr_union in_addr; - int r; - - assert(link); - assert(original); - assert(ret); - - /* Something useful was configured? just use it */ - if (in_addr_is_set(original->family, &original->in_addr)) - return address_dup(original, ret); - - /* The address is configured to be 0.0.0.0 or [::] by the user? - * Then let's acquire something more useful from the pool. */ - r = address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr); - if (r < 0) - return r; - if (r == 0) - return -EBUSY; - - /* Pick first address in range for ourselves. */ - if (original->family == AF_INET) - in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1); - else if (original->family == AF_INET6) - in_addr.in6.s6_addr[15] |= 1; - - r = address_dup(original, &na); - if (r < 0) - return r; - - na->in_addr = in_addr; - - *ret = TAKE_PTR(na); - return 0; -} - int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg) { int r; @@ -1524,21 +1487,67 @@ static int address_configure(const Address *address, const struct ifa_cacheinfo return request_call_netlink_async(link->manager->rtnl, m, req); } -static bool address_is_ready_to_configure(Link *link, const Address *address) { +static int address_acquire(Link *link, const Address *address, union in_addr_union *ret) { + union in_addr_union a; + int r; + assert(link); assert(address); + assert(ret); - if (!link_is_ready_to_configure(link, false)) - return false; + r = address_pool_acquire(link->manager, address->family, address->prefixlen, &a); + if (r < 0) + return r; + if (r == 0) + return -EBUSY; - if (!ipv4acd_bound(link, address)) - return false; + /* Pick first address in range for ourselves. */ + if (address->family == AF_INET) + a.in.s_addr |= htobe32(1); + else if (address->family == AF_INET6) + a.in6.s6_addr[15] |= 1; + else + assert_not_reached(); - /* Refuse adding more than the limit */ - if (set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX) - return false; + *ret = a; + return 0; +} - return true; +static int address_requeue_request(Request *req, Link *link, const Address *address) { + int r; + + assert(req); + assert(link); + assert(link->manager); + assert(link->network); + assert(address); + + /* Something useful was configured? just use it */ + if (in_addr_is_set(address->family, &address->in_addr)) + return 0; + + /* The address is configured to be 0.0.0.0 or [::] by the user? + * Then let's acquire something more useful. */ + union in_addr_union a; + r = address_acquire(link, address, &a); + if (r < 0) + return r; + + _cleanup_(address_unrefp) Address *tmp = NULL; + r = address_dup(address, &tmp); + if (r < 0) + return r; + + tmp->in_addr = a; + + r = link_requeue_request(link, req, tmp, NULL); + if (r < 0) + return r; + if (r == 0) + return -EEXIST; /* Already queued?? Strange... */ + + TAKE_PTR(tmp); + return 1; /* A new request is queued. it is not necessary to process this request anymore. */ } static int address_process_request(Request *req, Link *link, Address *address) { @@ -1550,7 +1559,26 @@ static int address_process_request(Request *req, Link *link, Address *address) { assert(link); assert(address); - if (!address_is_ready_to_configure(link, address)) + if (!link_is_ready_to_configure(link, false)) + return 0; + + /* Refuse adding more than the limit */ + if (set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX) + return 0; + + r = address_requeue_request(req, link, address); + if (r == -EBUSY) + return 0; + if (r != 0) + return r; + + address_set_broadcast(address, link); + + r = ipv4acd_configure(link, address); + if (r < 0) + return r; + + if (!ipv4acd_bound(link, address)) return 0; address_set_cinfo(link->manager, address, &c); @@ -1595,19 +1623,14 @@ int link_request_address( /* The requested address is outdated. Let's ignore the request. */ return 0; - if (address_get(link, address, &existing) < 0) { - if (address_get_request(link, address, NULL) >= 0) - return 0; /* already requested, skipping. */ + if (address_get_request(link, address, NULL) >= 0) + return 0; /* already requested, skipping. */ - r = address_acquire(link, address, &tmp); - if (r < 0) - return log_link_warning_errno(link, r, "Failed to acquire an address from pool: %m"); - - } else { - r = address_dup(address, &tmp); - if (r < 0) - return log_oom(); + r = address_dup(address, &tmp); + if (r < 0) + return log_oom(); + if (address_get(link, address, &existing) >= 0) { /* Copy already assigned address when it is requested as a null address. */ if (address_is_static_null(address)) tmp->in_addr = existing->in_addr; @@ -1616,12 +1639,6 @@ int link_request_address( tmp->state = existing->state; } - address_set_broadcast(tmp, link); - - r = ipv4acd_configure(link, tmp); - if (r < 0) - return r; - log_address_debug(tmp, "Requesting", link); r = link_queue_request_safe(link, REQUEST_TYPE_ADDRESS, tmp,