From: Yu Watanabe Date: Tue, 30 Jul 2024 15:25:43 +0000 (+0900) Subject: network/ipv4acd: manage ACD engines with Address object X-Git-Tag: v257-rc1~799^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d9ef1cc40757ff6d6875812510cb4c03e7e488b5;p=thirdparty%2Fsystemd.git network/ipv4acd: manage ACD engines with Address object IPv4 addresses are managed with local and peer addresses and prefix length. So, potentially, the same address with different prefix length can be assigned on a link, e.g. 192.168.0.1/24 and 192.168.0.1/26. If one of the address is configured with ACD but the other is not, then previously ACD might be unexpectedly disabled or enabled on them, as we managed ACD engines with only local addresses. This makes ACD engines managed with the corresponding Address objects. --- diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index b4ac0bc41b6..6e55c4f0224 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -135,8 +135,6 @@ void link_get_address_states( *ret_all = address_state_from_scope(MIN(ipv4_scope, ipv6_scope)); } -static void address_hash_func(const Address *a, struct siphash *state); -static int address_compare_func(const Address *a1, const Address *a2); static void address_detach(Address *address); DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( @@ -446,7 +444,7 @@ static int address_ipv4_prefix(const Address *a, struct in_addr *ret) { return 0; } -static void address_hash_func(const Address *a, struct siphash *state) { +void address_hash_func(const Address *a, struct siphash *state) { assert(a); siphash24_compress_typesafe(a->family, state); @@ -476,7 +474,7 @@ static void address_hash_func(const Address *a, struct siphash *state) { } } -static int address_compare_func(const Address *a1, const Address *a2) { +int address_compare_func(const Address *a1, const Address *a2) { int r; r = CMP(a1->family, a2->family); diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index e09551ecda4..8e8d04f8173 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -88,6 +88,8 @@ void link_get_address_states( LinkAddressState *ret_ipv6, LinkAddressState *ret_all); +void address_hash_func(const Address *a, struct siphash *state); +int address_compare_func(const Address *a1, const Address *a2); extern const struct hash_ops address_hash_ops; bool address_can_update(const Address *existing, const Address *requesting); @@ -118,10 +120,6 @@ static inline int link_get_ipv6_address(Link *link, const struct in6_addr *addre assert(address); return link_get_address(link, AF_INET6, &(union in_addr_union) { .in6 = *address }, prefixlen, ret); } -static inline int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret) { - assert(address); - return link_get_address(link, AF_INET, &(union in_addr_union) { .in = *address }, prefixlen, ret); -} int manager_get_address(Manager *manager, int family, const union in_addr_union *address, unsigned char prefixlen, Address **ret); bool manager_has_address(Manager *manager, int family, const union in_addr_union *address); diff --git a/src/network/networkd-ipv4acd.c b/src/network/networkd-ipv4acd.c index de03293fff3..6b1abc42e8d 100644 --- a/src/network/networkd-ipv4acd.c +++ b/src/network/networkd-ipv4acd.c @@ -13,10 +13,14 @@ #include "networkd-link.h" #include "networkd-manager.h" -DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR( +DEFINE_PRIVATE_HASH_OPS_FULL( ipv4acd_hash_ops, - void, trivial_hash_func, trivial_compare_func, - sd_ipv4acd, sd_ipv4acd_unref); + Address, + address_hash_func, + address_compare_func, + address_unref, + sd_ipv4acd, + sd_ipv4acd_unref); bool link_ipv4acd_supported(Link *link) { assert(link); @@ -71,7 +75,7 @@ bool ipv4acd_bound(Link *link, const Address *address) { if (address->family != AF_INET) return true; - acd = hashmap_get(link->ipv4acd_by_address, IN4_ADDR_TO_PTR(&address->in_addr.in)); + acd = hashmap_get(link->ipv4acd_by_address, address); if (!acd) return true; @@ -127,24 +131,22 @@ static int dhcp4_address_on_conflict(Link *link) { static void on_acd(sd_ipv4acd *acd, int event, void *userdata) { Link *link = ASSERT_PTR(userdata); Address *address = NULL; - struct in_addr a; int r; assert(acd); - 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 *val, *key; + HASHMAP_FOREACH_KEY(val, key, link->ipv4acd_by_address) + if (val == acd) { + (void) address_get(link, key, &address); + break; + } - (void) link_get_ipv4_address(link, &a, 0, &address); + if (!address) + return; switch (event) { case SD_IPV4ACD_EVENT_STOP: - if (!address) - break; - if (address->source == NETWORK_CONFIG_SOURCE_STATIC) { r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ false); if (r < 0) @@ -156,14 +158,11 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) { break; case SD_IPV4ACD_EVENT_BIND: - log_link_debug(link, "Successfully claimed address %s", IN4_ADDR_TO_STRING(&a)); + log_link_debug(link, "Successfully claimed address %s", IN4_ADDR_TO_STRING(&address->in_addr.in)); break; case SD_IPV4ACD_EVENT_CONFLICT: - if (!address) - break; - - log_link_warning(link, "Dropping address %s, as an address conflict was detected.", IN4_ADDR_TO_STRING(&a)); + log_link_warning(link, "Dropping address %s, as an address conflict was detected.", IN4_ADDR_TO_STRING(&address->in_addr.in)); if (address->source == NETWORK_CONFIG_SOURCE_STATIC) r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ true); @@ -207,6 +206,7 @@ static int ipv4acd_start_one(Link *link, sd_ipv4acd *acd) { int ipv4acd_configure(Link *link, const Address *address) { _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *acd = NULL; + _cleanup_(address_unrefp) Address *a = NULL; sd_ipv4acd *existing; int r; @@ -217,7 +217,7 @@ int ipv4acd_configure(Link *link, const Address *address) { if (address->family != AF_INET) return 0; - existing = hashmap_get(link->ipv4acd_by_address, IN4_ADDR_TO_PTR(&address->in_addr.in)); + existing = hashmap_get(link->ipv4acd_by_address, address); if (!address_ipv4acd_enabled(link, address)) return sd_ipv4acd_stop(existing); @@ -227,6 +227,15 @@ int ipv4acd_configure(Link *link, const Address *address) { log_link_debug(link, "Configuring IPv4ACD for address %s.", IN4_ADDR_TO_STRING(&address->in_addr.in)); + r = address_new(&a); + if (r < 0) + return r; + + a->family = AF_INET; + a->in_addr = address->in_addr; + a->in_addr_peer = address->in_addr_peer; + a->prefixlen = address->prefixlen; + r = sd_ipv4acd_new(&acd); if (r < 0) return r; @@ -255,11 +264,17 @@ int ipv4acd_configure(Link *link, const Address *address) { if (r < 0) return r; - r = hashmap_ensure_put(&link->ipv4acd_by_address, &ipv4acd_hash_ops, IN4_ADDR_TO_PTR(&address->in_addr.in), acd); + r = ipv4acd_start_one(link, acd); if (r < 0) return r; - return ipv4acd_start_one(link, TAKE_PTR(acd)); + r = hashmap_ensure_put(&link->ipv4acd_by_address, &ipv4acd_hash_ops, a, acd); + if (r < 0) + return r; + + TAKE_PTR(a); + TAKE_PTR(acd); + return 0; } void ipv4acd_detach(Link *link, const Address *address) { @@ -269,7 +284,9 @@ void ipv4acd_detach(Link *link, const Address *address) { if (address->family != AF_INET) return; - sd_ipv4acd_unref(hashmap_remove(link->ipv4acd_by_address, IN4_ADDR_TO_PTR(&address->in_addr.in))); + Address *a; + sd_ipv4acd_unref(hashmap_remove2(link->ipv4acd_by_address, address, (void**) &a)); + address_unref(a); } int ipv4acd_update_mac(Link *link) {