]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/ipv4acd: split out sd_ipv4acd management from Address to Link 28572/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 30 Jul 2023 14:16:41 +0000 (23:16 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 30 Jul 2023 14:16:41 +0000 (23:16 +0900)
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
src/network/networkd-address.h
src/network/networkd-ipv4acd.c
src/network/networkd-ipv4acd.h
src/network/networkd-link.c
src/network/networkd-link.h

index c33ffa95766c1297a76c642bbcfac3ff0acb4b97..2c062565c05036855cfeb4c07eda785f622702d2 100644 (file)
@@ -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;
 
index 766da8ee7545098e60c77063a4ddcfbf7a641d56..1391178e4e0999c9c0fdf4b83c55ea54d57286da 100644 (file)
@@ -5,8 +5,6 @@
 #include <stdbool.h>
 #include <stdio.h>
 
-#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;
index fb4bf47fd474b7db63e38a6c19766ac60701fc6d..3d5e2036aa764b66325e6ffd31ddaaf3ed831761 100644 (file)
 #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;
         }
index 1ec9481b99e0256c124ece1a2f2166f78e24f457..54da435679631a8a971d1404794a67a7a9d2eee7 100644 (file)
@@ -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);
index c237295606cdb80d77333bb827d9788f28396453..d4a72e2ec5e18a92d805541340de37d0d07fd6eb 100644 (file)
@@ -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);
index b91259c487062700031adb2d88eca0eafa5f46bc..e46e5f0c617cfa8f1e441fa383fc2cde8c7aa622 100644 (file)
@@ -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;