]> 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 12:36:10 +0000 (13:36 +0100)
Replaces #37891.

(cherry picked from commit 4c4fe8cd71da64506705736fda0ab7f7154f28d2)

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

index 4e4e13915e77c4c041b1647fc8b581872aff14de..a658bda4335429f3d948d587b88800a9a5c145d9 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 f8d6b6c3a1ec97cf0ef926b448502eace3c7705c..1a0eedc32900e2b0f721996f24e09e929f744fed 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 b4650b140a4a4b187382ebe14af7685d4720e49e..be9780821762fa55ff3c007332874263bd2ddf95 100644 (file)
@@ -168,7 +168,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),
@@ -177,6 +178,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;
 }