]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/ipv4acd: manage ACD engines with Address object
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 30 Jul 2024 15:25:43 +0000 (00:25 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 30 Jul 2024 20:35:20 +0000 (05:35 +0900)
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.

src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-ipv4acd.c

index b4ac0bc41b6e3e576ba44de824488a6917432e4d..6e55c4f0224385ef1f51385d93148415f8faf6d2 100644 (file)
@@ -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);
index e09551ecda4c2bf4f120e16d224c3eb35d5fd4fc..8e8d04f81731e489b7798234a07d1521fa45b38c 100644 (file)
@@ -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);
 
index de03293fff330fdfae5c8e8ef282382c0eb12ac2..6b1abc42e8d3d0ca74a7499d7b57329e09e79137 100644 (file)
 #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) {