summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/meson.build2
-rw-r--r--src/network/networkd-address.c168
-rw-r--r--src/network/networkd-address.h9
-rw-r--r--src/network/networkd-dhcp4.c181
-rw-r--r--src/network/networkd-ipv4acd.c271
-rw-r--r--src/network/networkd-ipv4acd.h10
-rw-r--r--src/network/networkd-link.c24
-rw-r--r--src/network/networkd-link.h3
8 files changed, 326 insertions, 342 deletions
diff --git a/src/network/meson.build b/src/network/meson.build
index 5a3a23101d..4e137d7b9e 100644
--- a/src/network/meson.build
+++ b/src/network/meson.build
@@ -79,6 +79,8 @@ sources = files('''
networkd-dhcp4.h
networkd-dhcp6.c
networkd-dhcp6.h
+ networkd-ipv4acd.c
+ networkd-ipv4acd.h
networkd-ipv4ll.c
networkd-ipv4ll.h
networkd-ipv6-proxy-ndp.c
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index a8f081ec81..35305aff99 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -9,6 +9,7 @@
#include "netlink-util.h"
#include "networkd-address-pool.h"
#include "networkd-address.h"
+#include "networkd-ipv4acd.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-queue.h"
@@ -129,6 +130,7 @@ static int address_new_static(Network *network, const char *filename, unsigned s
address->network = network;
address->section = TAKE_PTR(n);
+ address->is_static = true;
r = ordered_hashmap_ensure_put(&network->addresses_by_section, &network_config_hash_ops, address->section, address);
if (r < 0)
@@ -152,6 +154,7 @@ Address *address_free(Address *address) {
set_remove(address->link->addresses, address);
set_remove(address->link->addresses_foreign, address);
+ set_remove(address->link->addresses_ipv4acd, address);
set_remove(address->link->static_addresses, address);
if (address->link->dhcp_address == address)
address->link->dhcp_address = NULL;
@@ -994,8 +997,6 @@ int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m,
return 1;
}
-static int ipv4_dad_configure(Address *address);
-
static int address_configure(
const Address *address,
Link *link,
@@ -1242,6 +1243,12 @@ static int address_is_ready_to_configure(Link *link, const Address *address) {
return log_link_warning_errno(link, SYNTHETIC_ERRNO(E2BIG),
"Too many addresses are configured, refusing: %m");
+ if (address->family == AF_INET &&
+ address->duplicate_address_detection & ADDRESS_FAMILY_IPV4 &&
+ link->hw_addr.length == ETH_ALEN &&
+ !ether_addr_is_null(&link->hw_addr.ether))
+ return ipv4acd_address_is_ready_to_configure(link, address);
+
r = address_add(link, address, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Could not add address: %m");;
@@ -1286,12 +1293,6 @@ int request_process_address(Request *req) {
if (r < 0)
log_link_warning_errno(link, r, "Could not enable IP masquerading, ignoring: %m");
- if (FLAGS_SET(a->duplicate_address_detection, ADDRESS_FAMILY_IPV4)) {
- r = ipv4_dad_configure(a);
- if (r < 0)
- log_link_warning_errno(link, r, "Failed to start IPv4ACD client, ignoring: %m");
- }
-
return 1;
}
@@ -1475,157 +1476,6 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
return 1;
}
-static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
- Address *address;
- Link *link;
- int r;
-
- assert(acd);
- assert(userdata);
-
- address = (Address *) userdata;
- link = address->link;
-
- assert(address->family == AF_INET);
-
- switch (event) {
- case SD_IPV4ACD_EVENT_STOP:
- log_link_debug(link, "Stopping ACD client...");
- return;
-
- case SD_IPV4ACD_EVENT_BIND:
- log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
- IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
- link_check_ready(link);
- break;
-
- case SD_IPV4ACD_EVENT_CONFLICT:
- log_link_warning(link, "DAD conflict. Dropping address "IPV4_ADDRESS_FMT_STR,
- IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
- r = address_remove(address, link);
- if (r < 0)
- log_link_error_errno(link, r, "Failed to drop DAD conflicted address "IPV4_ADDRESS_FMT_STR,
- IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
-
- link_check_ready(link);
- break;
-
- default:
- assert_not_reached("Invalid IPv4ACD event.");
- }
-
- (void) sd_ipv4acd_stop(acd);
-
- return;
-}
-
-static int ipv4_dad_configure(Address *address) {
- int r;
-
- assert(address);
- assert(address->link);
-
- if (address->family != AF_INET)
- return 0;
-
- log_address_debug(address, "Starting IPv4ACD client. Probing", address->link);
-
- if (!address->acd) {
- r = sd_ipv4acd_new(&address->acd);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_attach_event(address->acd, address->link->manager->event, 0);
- if (r < 0)
- return r;
- }
-
- r = sd_ipv4acd_set_ifindex(address->acd, address->link->ifindex);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_set_mac(address->acd, &address->link->hw_addr.ether);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_set_address(address->acd, &address->in_addr.in);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_set_callback(address->acd, static_address_on_acd, address);
- if (r < 0)
- return r;
-
- return sd_ipv4acd_start(address->acd, true);
-}
-
-static int ipv4_dad_update_mac_one(Address *address) {
- bool running;
- int r;
-
- assert(address);
-
- if (!address->acd)
- return 0;
-
- running = sd_ipv4acd_is_running(address->acd);
-
- r = sd_ipv4acd_stop(address->acd);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_set_mac(address->acd, &address->link->hw_addr.ether);
- if (r < 0)
- return r;
-
- if (running) {
- r = sd_ipv4acd_start(address->acd, true);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int ipv4_dad_update_mac(Link *link) {
- Address *address;
- int k, r = 0;
-
- assert(link);
-
- SET_FOREACH(address, link->addresses) {
- k = ipv4_dad_update_mac_one(address);
- if (k < 0 && r >= 0)
- r = k;
- }
-
- return r;
-}
-
-int ipv4_dad_stop(Link *link) {
- Address *address;
- int k, r = 0;
-
- assert(link);
-
- SET_FOREACH(address, link->addresses) {
- k = sd_ipv4acd_stop(address->acd);
- if (k < 0 && r >= 0)
- r = k;
- }
-
- return r;
-}
-
-void ipv4_dad_unref(Link *link) {
- Address *address;
-
- assert(link);
-
- SET_FOREACH(address, link->addresses)
- address->acd = sd_ipv4acd_unref(address->acd);
-}
-
int config_parse_broadcast(
const char *unit,
const char *filename,
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index a24320fca2..ff3d46abdd 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -41,12 +41,13 @@ typedef struct Address {
bool scope_set:1;
bool ip_masquerade_done:1;
+ bool is_static:1; /* currently only used by IPv4ACD */
+ bool acd_announced:1;
AddressFamily duplicate_address_detection;
+ sd_ipv4acd *acd;
/* Called when address become ready */
address_ready_callback_t callback;
-
- sd_ipv4acd *acd;
} Address;
int address_new(Address **ret);
@@ -71,10 +72,6 @@ int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **
int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret);
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready);
-void ipv4_dad_unref(Link *link);
-int ipv4_dad_stop(Link *link);
-int ipv4_dad_update_mac(Link *link);
-
int link_request_address(
Link *link,
Address *address,
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 1aaeda98e2..f80adcdbcf 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -14,6 +14,7 @@
#include "network-internal.h"
#include "networkd-address.h"
#include "networkd-dhcp4.h"
+#include "networkd-ipv4acd.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
@@ -84,9 +85,6 @@ static int dhcp4_release_old_lease(Link *link) {
static void dhcp4_check_ready(Link *link) {
int r;
- if (link->network->dhcp_send_decline && !link->dhcp4_address_bind)
- return;
-
if (link->dhcp4_messages > 0) {
log_link_debug(link, "%s(): DHCPv4 address and routes are not set.", __func__);
return;
@@ -768,159 +766,32 @@ int dhcp4_lease_lost(Link *link) {
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
link_dirty(link);
- (void) sd_ipv4acd_stop(link->dhcp_acd);
-
- if (r < 0)
- return r;
-
- r = link_request_static_nexthops(link, true);
- if (r < 0)
- return r;
-
- return link_request_static_routes(link, true);
-}
-
-static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
- struct in_addr address;
- Link *link;
- int r;
-
- assert(acd);
- assert(userdata);
-
- link = userdata;
-
- switch (event) {
- case SD_IPV4ACD_EVENT_STOP:
- log_link_debug(link, "Stopping ACD client for DHCPv4 address.");
- return;
-
- case SD_IPV4ACD_EVENT_BIND:
- if (DEBUG_LOGGING) {
- (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
- log_link_debug(link, "Successfully claimed DHCPv4 address "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(address));
- }
- link->dhcp4_address_bind = true;
- dhcp4_check_ready(link);
- break;
-
- case SD_IPV4ACD_EVENT_CONFLICT:
- (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
- log_link_warning(link, "DAD conflict. Dropping DHCPv4 address "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(address));
-
- r = sd_dhcp_client_send_decline(link->dhcp_client);
- if (r < 0)
- log_link_warning_errno(link, r, "Failed to send DHCP DECLINE, ignoring: %m");
-
- if (link->dhcp_lease) {
- r = dhcp4_lease_lost(link);
- if (r < 0)
- link_enter_failed(link);
- }
- break;
-
- default:
- assert_not_reached("Invalid IPv4ACD event.");
- }
-
- (void) sd_ipv4acd_stop(acd);
-
- return;
-}
-
-static int dhcp4_configure_dad(Link *link) {
- int r;
-
- assert(link);
- assert(link->manager);
- assert(link->network);
-
- if (!link->network->dhcp_send_decline)
- return 0;
-
- if (!link->dhcp_acd) {
- r = sd_ipv4acd_new(&link->dhcp_acd);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_attach_event(link->dhcp_acd, link->manager->event, 0);
- if (r < 0)
- return r;
- }
-
- r = sd_ipv4acd_set_ifindex(link->dhcp_acd, link->ifindex);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->hw_addr.ether);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int dhcp4_dad_update_mac(Link *link) {
- bool running;
- int r;
-
- assert(link);
-
- if (!link->dhcp_acd)
- return 0;
-
- running = sd_ipv4acd_is_running(link->dhcp_acd);
+ if (link->network->dhcp_send_decline) {
+ Address *a;
- r = sd_ipv4acd_stop(link->dhcp_acd);
- if (r < 0)
- return r;
+ /* The acquired address may be still ARP probing and not configured. */
- r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->hw_addr.ether);
- if (r < 0)
- return r;
+ SET_FOREACH(a, link->addresses_ipv4acd)
+ if (!a->is_static && address_get(link, a, NULL) < 0) {
+ Request req = {
+ .link = link,
+ .address = a,
+ };
- if (running) {
- r = sd_ipv4acd_start(link->dhcp_acd, true);
- if (r < 0)
- return r;
+ log_link_debug(link, "Canceling the request to configure DHCPv4 address "IPV4_ADDRESS_FMT_STR,
+ IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
+ request_drop(ordered_set_get(link->manager->request_queue, &req));
+ }
}
- return 0;
-}
-
-static int dhcp4_start_acd(Link *link) {
- struct in_addr addr, old;
- int r;
-
- if (!link->network->dhcp_send_decline)
- return 0;
-
- if (!link->dhcp_lease)
- return 0;
-
- (void) sd_ipv4acd_stop(link->dhcp_acd);
-
- link->dhcp4_address_bind = false;
-
- r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_get_address(link->dhcp_acd, &old);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_set_address(link->dhcp_acd, &addr);
if (r < 0)
return r;
- r = sd_ipv4acd_set_callback(link->dhcp_acd, dhcp_address_on_acd, link);
+ r = link_request_static_nexthops(link, true);
if (r < 0)
return r;
- log_link_debug(link, "Starting IPv4ACD client. Probing DHCPv4 address "IPV4_ADDRESS_FMT_STR,
- IPV4_ADDRESS_FMT_VAL(addr));
-
- return sd_ipv4acd_start(link->dhcp_acd, !in4_addr_equal(&addr, &old));
+ return link_request_static_routes(link, true);
}
static int dhcp4_address_ready_callback(Address *address) {
@@ -957,11 +828,6 @@ static int dhcp4_after_address_configure(Request *req, void *object) {
}
link->dhcp_address = address;
-
- r = dhcp4_start_acd(link);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to start IPv4ACD for DHCPv4 address: %m");
-
return 0;
}
@@ -1057,6 +923,7 @@ static int dhcp4_request_address(Link *link, bool announce) {
addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
SET_FLAG(addr->flags, IFA_F_NOPREFIXROUTE, !link_prefixroute(link));
addr->route_metric = link->network->dhcp_route_metric;
+ addr->duplicate_address_detection = link->network->dhcp_send_decline ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_NO;
if (address_get(link, addr, NULL) < 0)
link->dhcp4_configured = false;
@@ -1687,10 +1554,6 @@ int dhcp4_configure(Link *link) {
if (r < 0)
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set initial DHCPv4 address: %m");
- r = dhcp4_configure_dad(link);
- if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to configure service type: %m");
-
return dhcp4_set_client_identifier(link);
}
@@ -1708,15 +1571,7 @@ int dhcp4_update_mac(Link *link) {
if (r < 0)
return r;
- r = dhcp4_set_client_identifier(link);
- if (r < 0)
- return r;
-
- r = dhcp4_dad_update_mac(link);
- if (r < 0)
- return r;
-
- return 0;
+ return dhcp4_set_client_identifier(link);
}
int dhcp4_start(Link *link) {
diff --git a/src/network/networkd-ipv4acd.c b/src/network/networkd-ipv4acd.c
new file mode 100644
index 0000000000..06dfa2d540
--- /dev/null
+++ b/src/network/networkd-ipv4acd.c
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "sd-dhcp-client.h"
+#include "sd-ipv4acd.h"
+
+#include "networkd-address.h"
+#include "networkd-dhcp4.h"
+#include "networkd-ipv4acd.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+
+static int static_address_on_stop(Link *link, Address *address) {
+ int r;
+
+ assert(link);
+ assert(address);
+
+ if (address_get(link, address, NULL) < 0)
+ return 0;
+
+ log_link_debug(link, "Removing address "IPV4_ADDRESS_FMT_STR", as the ACD client is stopped.",
+ IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
+
+ r = address_remove(address, link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to remove address "IPV4_ADDRESS_FMT_STR": %m",
+ IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
+
+ return 0;
+}
+
+static int static_address_on_conflict(Link *link, Address *address) {
+ int r;
+
+ assert(link);
+ assert(address);
+
+ if (address_get(link, address, NULL) < 0) {
+ log_link_warning(link, "Cannot configure requested address "IPV4_ADDRESS_FMT_STR", as an address conflict is detected.",
+ IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
+ return 0;
+ }
+
+ log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict is detected.",
+ IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
+
+ r = address_remove(address, link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to remove address "IPV4_ADDRESS_FMT_STR": %m",
+ IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
+
+ return 0;
+}
+
+static int dhcp4_address_on_conflict(Link *link) {
+ int r;
+
+ assert(link);
+ assert(link->dhcp_client);
+
+ r = sd_dhcp_client_send_decline(link->dhcp_client);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Failed to send DHCP DECLINE, ignoring: %m");
+
+ if (!link->dhcp_lease)
+ /* Unlikely, but during probing the address, the lease may be lost. */
+ return 0;
+
+ log_link_warning(link, "Dropping DHCPv4 lease, as an address conflict is detected.");
+ r = dhcp4_lease_lost(link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to drop DHCPv4 lease: %m");
+
+ /* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes it. */
+ return 0;
+}
+
+static void on_acd(sd_ipv4acd *acd, int event, void *userdata, bool is_static) {
+ Address *address = userdata;
+ Link *link;
+ int r;
+
+ assert(acd);
+ assert(address);
+ assert(address->acd == acd);
+ assert(address->link);
+ assert(address->family == AF_INET);
+
+ link = address->link;
+
+ switch (event) {
+ case SD_IPV4ACD_EVENT_STOP:
+ if (is_static) {
+ r = static_address_on_stop(link, address);
+ if (r < 0)
+ link_enter_failed(link);
+ }
+
+ /* We have nothing to do for DHCPv4 lease here, as the dhcp client is already stopped
+ * when stopping the ipv4acd client. See link_stop_engines(). */
+ break;
+
+ case SD_IPV4ACD_EVENT_BIND:
+ log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
+ IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
+
+ address->acd_announced = true;
+ break;
+
+ case SD_IPV4ACD_EVENT_CONFLICT:
+ if (is_static)
+ r = static_address_on_conflict(link, address);
+ else
+ r = dhcp4_address_on_conflict(link);
+ if (r < 0)
+ link_enter_failed(link);
+ break;
+
+ default:
+ assert_not_reached("Invalid IPv4ACD event.");
+ }
+}
+
+static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
+ on_acd(acd, event, userdata, true);
+}
+
+static void dhcp4_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
+ on_acd(acd, event, userdata, false);
+}
+
+static int ipv4acd_configure(Link *link, const Address *a) {
+ _cleanup_(address_freep) Address *address = NULL;
+ int r;
+
+ assert(link);
+ assert(a);
+ assert(a->family == AF_INET);
+
+ log_link_debug(link, "Configuring IPv4ACD for address "IPV4_ADDRESS_FMT_STR,
+ IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
+
+ r = address_dup(a, &address);
+ if (r < 0)
+ return r;
+
+ r = set_ensure_put(&link->addresses_ipv4acd, &address_hash_ops, address);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EEXIST;
+ address->link = link;
+
+ r = sd_ipv4acd_new(&address->acd);
+ if (r < 0)
+ return r;
+
+ r = sd_ipv4acd_attach_event(address->acd, link->manager->event, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_ipv4acd_set_ifindex(address->acd, link->ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether);
+ if (r < 0)
+ return r;
+
+ r = sd_ipv4acd_set_address(address->acd, &address->in_addr.in);
+ if (r < 0)
+ return r;
+
+ r = sd_ipv4acd_set_callback(address->acd,
+ address->is_static ? static_address_on_acd : dhcp4_address_on_acd,
+ address);
+ if (r < 0)
+ return r;
+
+ if (link_has_carrier(link)) {
+ r = sd_ipv4acd_start(address->acd, true);
+ if (r < 0)
+ return r;
+ }
+
+ TAKE_PTR(address);
+ return 0;
+}
+
+int ipv4acd_address_is_ready_to_configure(Link *link, const Address *address) {
+ Address *acd_address;
+ int r;
+
+ acd_address = set_get(link->addresses_ipv4acd, address);
+ if (!acd_address) {
+ r = ipv4acd_configure(link, address);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to configure IPv4ACD client: %m");
+
+ return false;
+ }
+
+ if (!acd_address->acd_announced)
+ return false;
+
+ r = set_ensure_put(&link->addresses, &address_hash_ops, acd_address);
+ if (r < 0)
+ return log_oom();
+ if (r == 0)
+ return log_link_warning_errno(link, SYNTHETIC_ERRNO(EEXIST), "Address already exists.");
+
+ acd_address->flags |= IFA_F_TENTATIVE;
+ return true;
+}
+
+int ipv4acd_update_mac(Link *link) {
+ Address *address;
+ int k, r = 0;
+
+ assert(link);
+
+ if (link->hw_addr.length != ETH_ALEN)
+ return 0;
+ if (ether_addr_is_null(&link->hw_addr.ether))
+ return 0;
+
+ SET_FOREACH(address, link->addresses_ipv4acd) {
+ assert(address->acd);
+
+ k = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether);
+ if (k < 0)
+ r = k;
+ }
+ if (r < 0)
+ link_enter_failed(link);
+
+ return r;
+}
+
+int ipv4acd_start(Link *link) {
+ Address *address;
+ int r;
+
+ assert(link);
+
+ SET_FOREACH(address, link->addresses_ipv4acd) {
+ if (sd_ipv4acd_is_running(address->acd))
+ continue;
+
+ r = sd_ipv4acd_start(address->acd, true);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int ipv4acd_stop(Link *link) {
+ Address *address;
+ int k, r = 0;
+
+ assert(link);
+
+ SET_FOREACH(address, link->addresses_ipv4acd) {
+ k = sd_ipv4acd_stop(address->acd);
+ if (k < 0)
+ r = k;
+ }
+
+ return r;
+}
diff --git a/src/network/networkd-ipv4acd.h b/src/network/networkd-ipv4acd.h
new file mode 100644
index 0000000000..d2b4ff775f
--- /dev/null
+++ b/src/network/networkd-ipv4acd.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+typedef struct Address Address;
+typedef struct Link Link;
+
+int ipv4acd_address_is_ready_to_configure(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 ba1bd283df..4efe74ad41 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -33,6 +33,7 @@
#include "networkd-dhcp-server.h"
#include "networkd-dhcp4.h"
#include "networkd-dhcp6.h"
+#include "networkd-ipv4acd.h"
#include "networkd-ipv4ll.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-link-bus.h"
@@ -204,7 +205,6 @@ static void link_free_engines(Link *link) {
link->dhcp_server = sd_dhcp_server_unref(link->dhcp_server);
link->dhcp_client = sd_dhcp_client_unref(link->dhcp_client);
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
- link->dhcp_acd = sd_ipv4acd_unref(link->dhcp_acd);
link->lldp = sd_lldp_unref(link->lldp);
link_lldp_emit_stop(link);
@@ -216,8 +216,6 @@ static void link_free_engines(Link *link) {
link->dhcp6_lease = sd_dhcp6_lease_unref(link->dhcp6_lease);
link->ndisc = sd_ndisc_unref(link->ndisc);
link->radv = sd_radv_unref(link->radv);
-
- ipv4_dad_unref(link);
}
static Link *link_free(Link *link) {
@@ -244,6 +242,7 @@ static Link *link_free(Link *link) {
link->addresses = set_free(link->addresses);
link->addresses_foreign = set_free(link->addresses_foreign);
+ link->addresses_ipv4acd = set_free(link->addresses_ipv4acd);
link->pool_addresses = set_free(link->pool_addresses);
link->static_addresses = set_free(link->static_addresses);
link->dhcp6_addresses = set_free(link->dhcp6_addresses);
@@ -361,6 +360,7 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
bool keep_dhcp = may_keep_dhcp &&
link->network &&
+ !link->network->dhcp_send_decline && /* IPv4 ACD for the DHCPv4 address is running. */
(link->manager->restarting ||
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP));
@@ -370,10 +370,6 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
}
- k = sd_ipv4acd_stop(link->dhcp_acd);
- if (k < 0)
- r = log_link_warning_errno(link, k, "Could not stop IPv4 ACD client for DHCPv4: %m");
-
k = sd_dhcp_server_stop(link->dhcp_server);
if (k < 0)
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 server: %m");
@@ -386,7 +382,7 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
if (k < 0)
r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m");
- k = ipv4_dad_stop(link);
+ k = ipv4acd_stop(link);
if (k < 0)
r = log_link_warning_errno(link, k, "Could not stop IPv4 ACD client: %m");
@@ -668,6 +664,10 @@ static int link_acquire_dynamic_ipv4_conf(Link *link) {
return log_link_warning_errno(link, r, "Could not start DHCP server: %m");
}
+ r = ipv4acd_start(link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not start IPv4 ACD client: %m");
+
return 0;
}
@@ -2039,6 +2039,10 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message)
r = ipv4ll_update_mac(link);
if (r < 0)
+ return log_link_debug_errno(link, r, "Could not update MAC address in IPv4 ACD client: %m");
+
+ r = ipv4ll_update_mac(link);
+ if (r < 0)
return log_link_debug_errno(link, r, "Could not update MAC address in IPv4LL client: %m");
r = dhcp4_update_mac(link);
@@ -2065,10 +2069,6 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message)
return log_link_debug_errno(link, r, "Could not update MAC address for LLDP: %m");
}
- r = ipv4_dad_update_mac(link);
- if (r < 0)
- return log_link_debug_errno(link, r, "Could not update MAC address in IPv4 ACD client: %m");
-
return 0;
}
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 28c2821ee6..4077ccaf09 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -104,6 +104,7 @@ typedef struct Link {
Set *addresses;
Set *addresses_foreign;
+ Set *addresses_ipv4acd;
Set *pool_addresses;
Set *static_addresses;
Set *neighbors;
@@ -119,11 +120,9 @@ typedef struct Link {
Set *dhcp_routes, *dhcp_routes_old;
char *lease_file;
unsigned dhcp4_messages;
- sd_ipv4acd *dhcp_acd;
bool dhcp4_route_failed:1;
bool dhcp4_route_retrying:1;
bool dhcp4_configured:1;
- bool dhcp4_address_bind:1;
sd_ipv4ll *ipv4ll;
bool ipv4ll_address_configured:1;