diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 6592cdbfe0..51a34693c2 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -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);