]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: warn when NDISC and DHCPv6 provide the same address 17851/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 8 Dec 2020 04:35:48 +0000 (13:35 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 8 Dec 2020 04:36:19 +0000 (13:36 +0900)
With some router, the address in NDISC generated with EUI-64 conflicts
with an address provided by DHCPv6.

Prompted by #17831.

src/network/networkd-dhcp6.c

index 6592cdbfe09e6eb84f1a6b0a10674b0321e27923..51a34693c2d316835393f3c6ca72c64338d8c660 100644 (file)
@@ -969,6 +969,70 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
         return 1;
 }
 
+static void log_dhcp6_address(Link *link, const Address *address, char **ret) {
+        char valid_buf[FORMAT_TIMESPAN_MAX], preferred_buf[FORMAT_TIMESPAN_MAX];
+        const char *valid_str = NULL, *preferred_str = NULL;
+        _cleanup_free_ char *buffer = NULL;
+        bool by_ndisc = false;
+        Address *existing;
+        NDiscAddress *na;
+        int log_level, r;
+
+        assert(link);
+        assert(address);
+
+        (void) in_addr_to_string(address->family, &address->in_addr, &buffer);
+        if (address->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
+                valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
+                                            address->cinfo.ifa_valid * USEC_PER_SEC,
+                                            USEC_PER_SEC);
+        if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
+                preferred_str = format_timespan(preferred_buf, FORMAT_TIMESPAN_MAX,
+                                                address->cinfo.ifa_prefered * USEC_PER_SEC,
+                                                USEC_PER_SEC);
+
+        r = address_get(link, address, &existing);
+        if (r < 0) {
+                /* New address. */
+                log_level = LOG_INFO;
+                goto simple_log;
+        } else
+                log_level = LOG_DEBUG;
+
+        if (set_contains(link->dhcp6_addresses, address))
+                /* Already warned. */
+                goto simple_log;
+
+        if (address->prefixlen == existing->prefixlen)
+                /* Currently, only conflict in prefix length is reported. */
+                goto simple_log;
+
+        SET_FOREACH(na, link->ndisc_addresses)
+                if (address_compare_func(na->address, existing)) {
+                        by_ndisc = true;
+                        break;
+                }
+
+        log_link_warning(link, "DHCPv6 address %s/%u (valid %s%s, preferred %s%s) conflicts the existing address %s/%u%s.",
+                         strnull(buffer), address->prefixlen,
+                         valid_str ? "for " : "forever", strempty(valid_str),
+                         preferred_str ? "for " : "forever", strempty(preferred_str),
+                         strnull(buffer), existing->prefixlen,
+                         by_ndisc ? "assigned by NDISC. Please try to use or update IPv6Token= setting "
+                         "to change the address generated by NDISC, or disable UseAutonomousPrefix=" : "");
+        goto finalize;
+
+simple_log:
+        log_link_full(link, log_level, "DHCPv6 address %s/%u (valid %s%s, preferred %s%s)",
+                      strnull(buffer), address->prefixlen,
+                      valid_str ? "for " : "forever", strempty(valid_str),
+                      preferred_str ? "for " : "forever", strempty(preferred_str));
+
+finalize:
+        if (ret)
+                *ret = TAKE_PTR(buffer);
+}
+
 static int dhcp6_update_address(
                 Link *link,
                 const struct in6_addr *ip6_addr,
@@ -991,22 +1055,19 @@ static int dhcp6_update_address(
         addr->cinfo.ifa_prefered = lifetime_preferred;
         addr->cinfo.ifa_valid = lifetime_valid;
 
-        (void) in_addr_to_string(addr->family, &addr->in_addr, &buffer);
-        log_link_full(link, set_contains(link->dhcp6_addresses, addr) ? LOG_DEBUG : LOG_INFO,
-                      "DHCPv6 address %s/%u timeout preferred %d valid %d",
-                      strna(buffer), addr->prefixlen, lifetime_preferred, lifetime_valid);
+        log_dhcp6_address(link, addr, &buffer);
 
         r = address_configure(addr, link, dhcp6_address_handler, true, &ret);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to set DHCPv6 address %s/%u: %m",
-                                            strna(buffer), addr->prefixlen);
+                                            strnull(buffer), addr->prefixlen);
 
         link->dhcp6_address_messages++;
 
         r = set_ensure_put(&link->dhcp6_addresses, &address_hash_ops, ret);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to store DHCPv6 address %s/%u: %m",
-                                            strna(buffer), addr->prefixlen);
+                                            strnull(buffer), addr->prefixlen);
 
         (void) set_remove(link->dhcp6_addresses_old, ret);