From 5385e5f9406c007e53bbbea8f522217571666201 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 30 Jul 2023 23:16:41 +0900 Subject: [PATCH] network/ipv4acd: split out sd_ipv4acd management from Address to Link Then, we can start IPv4ACD without adding corresponding Address object to Link. Hopefully, no functional change, just refactoring and preparation for later commits. --- src/network/networkd-address.c | 12 +-- src/network/networkd-address.h | 4 - src/network/networkd-ipv4acd.c | 163 ++++++++++++++++++--------------- src/network/networkd-ipv4acd.h | 5 +- src/network/networkd-link.c | 2 + src/network/networkd-link.h | 2 + 6 files changed, 101 insertions(+), 87 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index c33ffa95766..2c062565c05 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -133,9 +133,9 @@ Address *address_free(Address *address) { if (address->family == AF_INET6 && in6_addr_equal(&address->in_addr.in6, &address->link->ipv6ll_address)) memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr)); - } - sd_ipv4acd_unref(address->acd); + ipv4acd_detach(address->link, address); + } config_section_free(address->section); free(address->label); @@ -153,8 +153,9 @@ static bool address_lifetime_is_valid(const Address *a) { bool address_is_ready(const Address *a) { assert(a); + assert(a->link); - if (!ipv4acd_bound(a)) + if (!ipv4acd_bound(a->link, a)) return false; if (FLAGS_SET(a->flags, IFA_F_TENTATIVE)) @@ -462,7 +463,6 @@ int address_dup(const Address *src, Address **ret) { dest->section = NULL; dest->link = NULL; dest->label = NULL; - dest->acd = NULL; dest->netlabel = NULL; if (src->family == AF_INET) { @@ -1206,7 +1206,7 @@ static bool address_is_ready_to_configure(Link *link, const Address *address) { if (!link_is_ready_to_configure(link, false)) return false; - if (!ipv4acd_bound(address)) + if (!ipv4acd_bound(link, address)) return false; /* Refuse adding more than the limit */ @@ -1302,7 +1302,7 @@ int link_request_address( existing->lifetime_preferred_usec = address->lifetime_preferred_usec; } - r = ipv4acd_configure(existing); + r = ipv4acd_configure(link, existing); if (r < 0) return r; diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 766da8ee754..1391178e4e0 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -5,8 +5,6 @@ #include #include -#include "sd-ipv4acd.h" - #include "conf-parser.h" #include "in-addr-util.h" #include "networkd-link.h" @@ -58,8 +56,6 @@ struct Address { /* duplicate_address_detection is only used by static or IPv4 dynamic addresses. * To control DAD for IPv6 dynamic addresses, set IFA_F_NODAD to flags. */ AddressFamily duplicate_address_detection; - sd_ipv4acd *acd; - bool acd_bound; /* Called when address become ready */ address_ready_callback_t callback; diff --git a/src/network/networkd-ipv4acd.c b/src/network/networkd-ipv4acd.c index fb4bf47fd47..3d5e2036aa7 100644 --- a/src/network/networkd-ipv4acd.c +++ b/src/network/networkd-ipv4acd.c @@ -13,6 +13,11 @@ #include "networkd-link.h" #include "networkd-manager.h" +DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR( + ipv4acd_hash_ops, + void, trivial_hash_func, trivial_compare_func, + sd_ipv4acd, sd_ipv4acd_unref); + bool link_ipv4acd_supported(Link *link) { assert(link); @@ -40,9 +45,9 @@ bool link_ipv4acd_supported(Link *link) { return true; } -static bool address_ipv4acd_enabled(Address *address) { +static bool address_ipv4acd_enabled(Link *link, const Address *address) { + assert(link); assert(address); - assert(address->link); if (address->family != AF_INET) return false; @@ -54,19 +59,23 @@ static bool address_ipv4acd_enabled(Address *address) { if (!IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4)) return false; - if (!link_ipv4acd_supported(address->link)) - return false; - - return true; + return link_ipv4acd_supported(link); } -bool ipv4acd_bound(const Address *address) { +bool ipv4acd_bound(Link *link, const Address *address) { + sd_ipv4acd *acd; + + assert(link); assert(address); - if (!address->acd) + if (address->family != AF_INET) + return true; + + acd = hashmap_get(link->ipv4acd_by_address, IN4_ADDR_TO_PTR(&address->in_addr.in)); + if (!acd) return true; - return address->acd_bound; + return sd_ipv4acd_is_bound(acd) > 0; } static int static_ipv4acd_address_remove(Link *link, Address *address, bool on_conflict) { @@ -114,23 +123,25 @@ static int dhcp4_address_on_conflict(Link *link) { } static void on_acd(sd_ipv4acd *acd, int event, void *userdata) { - Address *address = ASSERT_PTR(userdata); + Link *link = ASSERT_PTR(userdata); + Address *address = NULL; struct in_addr a; - Link *link; int r; assert(acd); - assert(address->acd == acd); - assert(address->link); - assert(address->family == AF_INET); - assert(IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4)); - link = address->link; - a = address->in_addr.in; + r = sd_ipv4acd_get_address(acd, &a); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get address from IPv4ACD: %m"); + link_enter_failed(link); + } + + (void) link_get_ipv4_address(link, &a, 0, &address); switch (event) { case SD_IPV4ACD_EVENT_STOP: - address->acd_bound = false; + if (!address) + break; if (address->source == NETWORK_CONFIG_SOURCE_STATIC) { r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ false); @@ -143,13 +154,12 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) { break; case SD_IPV4ACD_EVENT_BIND: - address->acd_bound = true; - log_link_debug(link, "Successfully claimed address %s", IN4_ADDR_TO_STRING(&a)); break; case SD_IPV4ACD_EVENT_CONFLICT: - address->acd_bound = false; + if (!address) + break; log_link_warning(link, "Dropping address %s, as an address conflict was detected.", IN4_ADDR_TO_STRING(&a)); @@ -180,75 +190,89 @@ static int ipv4acd_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0; } -static int address_ipv4acd_start(Address *address) { - assert(address); - assert(address->link); - - if (!address->acd) - return 0; +static int ipv4acd_start_one(Link *link, sd_ipv4acd *acd) { + assert(link); + assert(acd); - if (sd_ipv4acd_is_running(address->acd)) + if (sd_ipv4acd_is_running(acd)) return 0; - if (!link_has_carrier(address->link)) + if (!link_has_carrier(link)) return 0; - return sd_ipv4acd_start(address->acd, true); + return sd_ipv4acd_start(acd, /* reset_conflicts = */ true); } -int ipv4acd_configure(Address *address) { - Link *link; +int ipv4acd_configure(Link *link, const Address *address) { + _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *acd = NULL; + sd_ipv4acd *existing; int r; + assert(link); + assert(link->manager); assert(address); - link = ASSERT_PTR(address->link); - - if (!address_ipv4acd_enabled(address)) { - address->acd = sd_ipv4acd_unref(address->acd); - address->acd_bound = false; + if (address->family != AF_INET) return 0; - } - if (address->acd) - return address_ipv4acd_start(address); + existing = hashmap_get(link->ipv4acd_by_address, IN4_ADDR_TO_PTR(&address->in_addr.in)); + + if (!address_ipv4acd_enabled(link, address)) + return sd_ipv4acd_stop(existing); + + if (existing) + return ipv4acd_start_one(link, existing); log_link_debug(link, "Configuring IPv4ACD for address %s.", IN4_ADDR_TO_STRING(&address->in_addr.in)); - r = sd_ipv4acd_new(&address->acd); + r = sd_ipv4acd_new(&acd); + if (r < 0) + return r; + + r = sd_ipv4acd_attach_event(acd, link->manager->event, 0); if (r < 0) return r; - r = sd_ipv4acd_attach_event(address->acd, link->manager->event, 0); + r = sd_ipv4acd_set_ifindex(acd, link->ifindex); if (r < 0) return r; - r = sd_ipv4acd_set_ifindex(address->acd, link->ifindex); + r = sd_ipv4acd_set_mac(acd, &link->hw_addr.ether); if (r < 0) return r; - r = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether); + r = sd_ipv4acd_set_address(acd, &address->in_addr.in); if (r < 0) return r; - r = sd_ipv4acd_set_address(address->acd, &address->in_addr.in); + r = sd_ipv4acd_set_callback(acd, on_acd, link); if (r < 0) return r; - r = sd_ipv4acd_set_callback(address->acd, on_acd, address); + r = sd_ipv4acd_set_check_mac_callback(acd, ipv4acd_check_mac, link->manager); if (r < 0) return r; - r = sd_ipv4acd_set_check_mac_callback(address->acd, ipv4acd_check_mac, link->manager); + r = hashmap_ensure_put(&link->ipv4acd_by_address, &ipv4acd_hash_ops, IN4_ADDR_TO_PTR(&address->in_addr.in), acd); if (r < 0) return r; - return address_ipv4acd_start(address); + return ipv4acd_start_one(link, TAKE_PTR(acd)); +} + +void ipv4acd_detach(Link *link, const Address *address) { + assert(link); + assert(address); + + if (address->family != AF_INET) + return; + + sd_ipv4acd_unref(hashmap_remove(link->ipv4acd_by_address, IN4_ADDR_TO_PTR(&address->in_addr.in))); } int ipv4acd_update_mac(Link *link) { - Address *address; - int k, r = 0; + sd_ipv4acd *acd; + int r; assert(link); @@ -257,28 +281,23 @@ int ipv4acd_update_mac(Link *link) { if (ether_addr_is_null(&link->hw_addr.ether)) return 0; - SET_FOREACH(address, link->addresses) { - if (!address->acd) - continue; - - k = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether); - if (k < 0) - r = k; + HASHMAP_FOREACH(acd, link->ipv4acd_by_address) { + r = sd_ipv4acd_set_mac(acd, &link->hw_addr.ether); + if (r < 0) + return r; } - if (r < 0) - link_enter_failed(link); - return r; + return 0; } int ipv4acd_start(Link *link) { - Address *address; + sd_ipv4acd *acd; int r; assert(link); - SET_FOREACH(address, link->addresses) { - r = address_ipv4acd_start(address); + HASHMAP_FOREACH(acd, link->ipv4acd_by_address) { + r = ipv4acd_start_one(link, acd); if (r < 0) return r; } @@ -287,16 +306,13 @@ int ipv4acd_start(Link *link) { } int ipv4acd_stop(Link *link) { - Address *address; + sd_ipv4acd *acd; int k, r = 0; assert(link); - SET_FOREACH(address, link->addresses) { - if (!address->acd) - continue; - - k = sd_ipv4acd_stop(address->acd); + HASHMAP_FOREACH(acd, link->ipv4acd_by_address) { + k = sd_ipv4acd_stop(acd); if (k < 0) r = k; } @@ -305,16 +321,13 @@ int ipv4acd_stop(Link *link) { } int ipv4acd_set_ifname(Link *link) { - Address *address; + sd_ipv4acd *acd; int r; assert(link); - SET_FOREACH(address, link->addresses) { - if (!address->acd) - continue; - - r = sd_ipv4acd_set_ifname(address->acd, link->ifname); + HASHMAP_FOREACH(acd, link->ipv4acd_by_address) { + r = sd_ipv4acd_set_ifname(acd, link->ifname); if (r < 0) return r; } diff --git a/src/network/networkd-ipv4acd.h b/src/network/networkd-ipv4acd.h index 1ec9481b99e..54da4356796 100644 --- a/src/network/networkd-ipv4acd.h +++ b/src/network/networkd-ipv4acd.h @@ -5,8 +5,9 @@ typedef struct Address Address; typedef struct Link Link; bool link_ipv4acd_supported(Link *link); -bool ipv4acd_bound(const Address *address); -int ipv4acd_configure(Address *address); +bool ipv4acd_bound(Link *link, const Address *address); +int ipv4acd_configure(Link *link, const Address *address); +void ipv4acd_detach(Link *link, const Address *address); int ipv4acd_update_mac(Link *link); int ipv4acd_start(Link *link); int ipv4acd_stop(Link *link); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index c237295606c..d4a72e2ec5e 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -160,6 +160,8 @@ static void link_free_engines(Link *link) { link->lldp_rx = sd_lldp_rx_unref(link->lldp_rx); link->lldp_tx = sd_lldp_tx_unref(link->lldp_tx); + link->ipv4acd_by_address = hashmap_free(link->ipv4acd_by_address); + link->ipv4ll = sd_ipv4ll_unref(link->ipv4ll); link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index b91259c4870..e46e5f0c617 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -130,6 +130,8 @@ typedef struct Link { bool dhcp4_configured:1; char *dhcp4_6rd_tunnel_name; + Hashmap *ipv4acd_by_address; + sd_ipv4ll *ipv4ll; bool ipv4ll_address_configured:1; -- 2.47.3