]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/dhcp6: consider the DHCPv6 protocol as finished when conflict addresses exist
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 20 Jun 2025 18:51:30 +0000 (03:51 +0900)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 25 Jun 2025 17:17:42 +0000 (18:17 +0100)
Replaces #37891.

(cherry picked from commit 4c4fe8cd71da64506705736fda0ab7f7154f28d2)
(cherry picked from commit b53f734a65c7d6183bf8fad6cef465d2d1c11db5)

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

index 00fdb51128ec74a3ae450e2a8e641f1f2d46fbe2..1940827025b3d38016459dfcff84d4c8e37bf128 100644 (file)
@@ -316,6 +316,27 @@ bool link_check_addresses_ready(Link *link, NetworkConfigSource source) {
                 has = true;
         }
 
+        if (has || source != NETWORK_CONFIG_SOURCE_DHCP6)
+                return has;
+
+        /* If there is no DHCPv6 addresses, but all conflicting addresses are successfully configured, then
+         * let's handle the DHCPv6 client successfully configured addresses. Otherwise, if the conflicted
+         * addresses are static or foreign, and there is no other dynamic addressing protocol enabled, then
+         * the link will never enter the configured state. See also link_check_ready(). */
+        SET_FOREACH(a, link->addresses) {
+                if (source >= 0 && a->source == NETWORK_CONFIG_SOURCE_DHCP6)
+                        continue;
+                if (!a->also_requested_by_dhcp6)
+                        continue;
+                if (address_is_marked(a))
+                        continue;
+                if (!address_exists(a))
+                        continue;
+                if (!address_is_ready(a))
+                        return false;
+                has = true;
+        }
+
         return has;
 }
 
@@ -1940,6 +1961,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
                 nft_set_context_clear(&address->nft_set_context);
                 (void) nft_set_context_dup(&a->nft_set_context, &address->nft_set_context);
                 address->requested_as_null = a->requested_as_null;
+                address->also_requested_by_dhcp6 = a->also_requested_by_dhcp6;
                 address->callback = a->callback;
 
                 ipv6_token_ref(a->token);
index e09551ecda4c2bf4f120e16d224c3eb35d5fd4fc..f5ad95d382f3103779228b512c72daeb9216a204 100644 (file)
@@ -59,6 +59,10 @@ struct Address {
         bool ip_masquerade_done:1;
         bool requested_as_null:1;
         bool used_by_dhcp_server:1;
+        /* If this address is configured by non-DHCPv6 protocol (i.e. statically, NDISC, or any foreign
+         * methods), and the DHCPv6 client requests the same address, set this flag.
+         * See link_check_addresses_ready() and verify_dhcp6_address(). */
+        bool also_requested_by_dhcp6:1;
 
         /* 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. */
index 19deb103c63bf5b71cf3fabcf342716bed985540..9d06a2a8d3193f1ae7d75936541b9d6b561f5437 100644 (file)
@@ -164,7 +164,8 @@ static int verify_dhcp6_address(Link *link, const Address *address) {
         bool by_ndisc = existing->source == NETWORK_CONFIG_SOURCE_NDISC;
 
         log_link_full(link,
-                      LOG_WARNING,
+                      /* Downgrade the log level if we have logged about the conflict previously. */
+                      existing->also_requested_by_dhcp6 ? LOG_DEBUG : LOG_WARNING,
                       "Ignoring DHCPv6 address %s (valid %s, preferred %s) which conflicts with %s%s.%s",
                       IN6_ADDR_PREFIX_TO_STRING(&address->in_addr.in6, address->prefixlen),
                       FORMAT_LIFETIME(address->lifetime_valid_usec),
@@ -173,6 +174,7 @@ static int verify_dhcp6_address(Link *link, const Address *address) {
                       by_ndisc ? " assigned by NDisc" : "",
                       by_ndisc ? "\nHint: use IPv6Token= setting to change the address generated by NDisc or set UseAutonomousPrefix=no." : "");
 
+        existing->also_requested_by_dhcp6 = true;
         return -EEXIST;
 }