From: Yu Watanabe Date: Thu, 7 Sep 2023 18:27:07 +0000 (+0900) Subject: network: find DHCP server address only on loading .network file X-Git-Tag: v255-rc1~523^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5459e11d39f8885ec945829df0d8e1ca62e56f75;p=thirdparty%2Fsystemd.git network: find DHCP server address only on loading .network file Previously, we periodically search suitable address for DHCP server, 1. when .network file is loaded, 2. when checking if we can configure sd_dhcp_server object, 3. when configuring sd_dhcp_server. Especially, the step 2 may be triggered several times. This makes, when .network file is loaded, find a corresponding Address object, add a new Address object if not found, then save the found or added Address object. So, it is not necessary to find address again on configuring sd_dhcp_server object. --- diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 990d24e9b1c..c43655f57aa 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -110,7 +110,7 @@ int address_new(Address **ret) { return 0; } -static int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) { +int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) { _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(address_freep) Address *address = NULL; int r; @@ -401,7 +401,7 @@ static int address_compare_func(const Address *a1, const Address *a2) { } } -DEFINE_PRIVATE_HASH_OPS( +DEFINE_HASH_OPS( address_hash_ops, Address, address_hash_func, @@ -1561,10 +1561,6 @@ int link_request_static_addresses(Link *link) { if (r < 0) return r; - r = link_request_dhcp_server_address(link); - if (r < 0) - return r; - if (link->static_address_messages == 0) { link->static_addresses_configured = true; link_check_ready(link); @@ -2334,7 +2330,7 @@ static void address_section_adjust_broadcast(Address *address) { address->broadcast.s_addr = 0; } -static int address_section_verify(Address *address) { +int address_section_verify(Address *address) { if (section_is_invalid(address->section)) return -EINVAL; @@ -2444,7 +2440,9 @@ int network_drop_invalid_addresses(Network *network) { assert(r > 0); } - network_adjust_dhcp_server(network); + r = network_adjust_dhcp_server(network, &addresses); + if (r < 0) + return r; return 0; } diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 87c7d364868..35acb81aa35 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -7,6 +7,7 @@ #include "conf-parser.h" #include "firewall-util.h" +#include "hash-funcs.h" #include "in-addr-util.h" #include "networkd-link.h" #include "networkd-util.h" @@ -73,7 +74,10 @@ const char* format_lifetime(char *buf, size_t l, usec_t lifetime_usec) _warn_unu int address_flags_to_string_alloc(uint32_t flags, int family, char **ret); +extern const struct hash_ops address_hash_ops; + int address_new(Address **ret); +int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret); Address* address_free(Address *address); int address_get(Link *link, const Address *in, Address **ret); int address_get_harder(Link *link, const Address *in, Address **ret); @@ -115,6 +119,7 @@ int link_request_static_addresses(Link *link); int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, Manager *m); +int address_section_verify(Address *address); int network_drop_invalid_addresses(Network *network); DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Address, address); diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index 3663a506f6a..63c520fa89d 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -39,22 +39,28 @@ static bool link_dhcp4_server_enabled(Link *link) { return link->network->dhcp_server; } -void network_adjust_dhcp_server(Network *network) { +int network_adjust_dhcp_server(Network *network, Set **addresses) { + int r; + assert(network); + assert(addresses); if (!network->dhcp_server) - return; + return 0; if (network->bond) { log_warning("%s: DHCPServer= is enabled for bond slave. Disabling DHCP server.", network->filename); network->dhcp_server = false; - return; + return 0; } - if (!in4_addr_is_set(&network->dhcp_server_address)) { + assert(network->dhcp_server_address_prefixlen <= 32); + + if (network->dhcp_server_address_prefixlen == 0) { Address *address; - bool have = false; + + /* If the server address is not specified, then find suitable static address. */ ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section) { assert(!section_is_invalid(address->section)); @@ -71,83 +77,69 @@ void network_adjust_dhcp_server(Network *network) { if (in4_addr_is_set(&address->in_addr_peer.in)) continue; - have = true; + /* TODO: check if the prefix length is small enough for the pool. */ + + network->dhcp_server_address = address; break; } - if (!have) { - log_warning("%s: DHCPServer= is enabled, but no static address configured. " + if (!network->dhcp_server_address) { + log_warning("%s: DHCPServer= is enabled, but no suitable static address configured. " "Disabling DHCP server.", network->filename); network->dhcp_server = false; - return; + return 0; } - } -} - -int link_request_dhcp_server_address(Link *link) { - _cleanup_(address_freep) Address *address = NULL; - Address *existing; - int r; - - assert(link); - assert(link->network); - - if (!link_dhcp4_server_enabled(link)) - return 0; - - if (!in4_addr_is_set(&link->network->dhcp_server_address)) - return 0; - - r = address_new(&address); - if (r < 0) - return r; - - address->source = NETWORK_CONFIG_SOURCE_STATIC; - address->family = AF_INET; - address->in_addr.in = link->network->dhcp_server_address; - address->prefixlen = link->network->dhcp_server_address_prefixlen; - if (address_get_harder(link, address, &existing) >= 0 && - (address_exists(existing) || address_is_requesting(existing)) && - existing->source == NETWORK_CONFIG_SOURCE_STATIC) - /* The same address seems explicitly configured in [Address] or [Network] section. - * Configure the DHCP server address only when it is not. */ - return 0; + } else { + _cleanup_(address_freep) Address *a = NULL; + Address *existing; + unsigned line; + + /* TODO: check if the prefix length is small enough for the pool. */ + + /* If an address is explicitly specified, then check if the corresponding [Address] section + * is configured, and add one if not. */ + + existing = set_get(*addresses, + &(Address) { + .family = AF_INET, + .in_addr.in = network->dhcp_server_address_in_addr, + .prefixlen = network->dhcp_server_address_prefixlen, + }); + if (existing) { + /* Corresponding [Address] section already exists. */ + network->dhcp_server_address = existing; + return 0; + } - return link_request_static_address(link, address); -} + r = ordered_hashmap_by_section_find_unused_line(network->addresses_by_section, network->filename, &line); + if (r < 0) + return log_warning_errno(r, "%s: Failed to find unused line number for DHCP server address: %m", + network->filename); -static int link_find_dhcp_server_address(Link *link, Address **ret) { - Address *address; + r = address_new_static(network, network->filename, line, &a); + if (r < 0) + return log_warning_errno(r, "%s: Failed to add new static address object for DHCP server: %m", + network->filename); - assert(link); - assert(link->network); + a->family = AF_INET; + a->prefixlen = network->dhcp_server_address_prefixlen; + a->in_addr.in = network->dhcp_server_address_in_addr; + a->requested_as_null = !in4_addr_is_set(&network->dhcp_server_address_in_addr); - /* If ServerAddress= is specified, then use the address. */ - if (in4_addr_is_set(&link->network->dhcp_server_address)) - return link_get_ipv4_address(link, &link->network->dhcp_server_address, - link->network->dhcp_server_address_prefixlen, ret); + r = address_section_verify(a); + if (r < 0) + return r; - /* If not, then select one from static addresses. */ - SET_FOREACH(address, link->addresses) { - if (address->source != NETWORK_CONFIG_SOURCE_STATIC) - continue; - if (!address_exists(address)) - continue; - if (address->family != AF_INET) - continue; - if (in4_addr_is_localhost(&address->in_addr.in)) - continue; - if (in4_addr_is_link_local(&address->in_addr.in)) - continue; - if (in4_addr_is_set(&address->in_addr_peer.in)) - continue; + r = set_ensure_put(addresses, &address_hash_ops, a); + if (r < 0) + return log_oom(); + assert(r > 0); - *ret = address; - return 0; + network->dhcp_server_address = TAKE_PTR(a); } - return -ENOENT; + return 0; } static int dhcp_server_find_uplink(Link *link, Link **ret) { @@ -369,6 +361,8 @@ static int dhcp4_server_configure(Link *link) { int r; assert(link); + assert(link->network); + assert(link->network->dhcp_server_address); log_link_debug(link, "Configuring DHCP Server."); @@ -387,7 +381,7 @@ static int dhcp4_server_configure(Link *link) { if (r < 0) return log_link_warning_errno(link, r, "Failed to set callback for DHCPv4 server instance: %m"); - r = link_find_dhcp_server_address(link, &address); + r = address_get(link, link->network->dhcp_server_address, &address); if (r < 0) return log_link_error_errno(link, r, "Failed to find suitable address for DHCPv4 server instance: %m"); @@ -535,6 +529,8 @@ static bool dhcp_server_is_ready_to_configure(Link *link) { Address *a; assert(link); + assert(link->network); + assert(link->network->dhcp_server_address); if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false)) return false; @@ -545,7 +541,7 @@ static bool dhcp_server_is_ready_to_configure(Link *link) { if (!link->static_addresses_configured) return false; - if (link_find_dhcp_server_address(link, &a) < 0) + if (address_get(link, link->network->dhcp_server_address, &a) < 0) return false; if (!address_is_ready(a)) @@ -711,7 +707,7 @@ int config_parse_dhcp_server_address( assert(rvalue); if (isempty(rvalue)) { - network->dhcp_server_address = (struct in_addr) {}; + network->dhcp_server_address_in_addr = (struct in_addr) {}; network->dhcp_server_address_prefixlen = 0; return 0; } @@ -729,7 +725,7 @@ int config_parse_dhcp_server_address( return 0; } - network->dhcp_server_address = a.in; + network->dhcp_server_address_in_addr = a.in; network->dhcp_server_address_prefixlen = prefixlen; return 0; } diff --git a/src/network/networkd-dhcp-server.h b/src/network/networkd-dhcp-server.h index cb2a8b6a34b..4fd4429deb3 100644 --- a/src/network/networkd-dhcp-server.h +++ b/src/network/networkd-dhcp-server.h @@ -2,13 +2,13 @@ #pragma once #include "conf-parser.h" +#include "set.h" typedef struct Link Link; typedef struct Network Network; -void network_adjust_dhcp_server(Network *network); +int network_adjust_dhcp_server(Network *network, Set **addresses); -int link_request_dhcp_server_address(Link *link); int link_request_dhcp_server(Link *link); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_agent_suboption); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 98cc1f5abc9..34bc179d75b 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -15,6 +15,7 @@ #include "ipoib.h" #include "net-condition.h" #include "netdev.h" +#include "networkd-address.h" #include "networkd-bridge-vlan.h" #include "networkd-dhcp-common.h" #include "networkd-dhcp4.h" @@ -199,7 +200,8 @@ struct Network { bool dhcp_server; bool dhcp_server_bind_to_interface; unsigned char dhcp_server_address_prefixlen; - struct in_addr dhcp_server_address; + struct in_addr dhcp_server_address_in_addr; + const Address *dhcp_server_address; int dhcp_server_uplink_index; char *dhcp_server_uplink_name; struct in_addr dhcp_server_relay_target;