summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2020-12-08 13:35:48 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2020-12-08 13:36:19 +0900
commitb432080dc8ad35e9b3b4fd487001e311c6d2776d (patch)
tree79f542a0b5e8a16cfe4c2941bcd6b555a01bf964
parent450fa34bd0315f2ca4728050b37c3a3d9e0f1b78 (diff)
downloadsystemd-b432080dc8ad35e9b3b4fd487001e311c6d2776d.tar.gz
network: warn when NDISC and DHCPv6 provide the same address
With some router, the address in NDISC generated with EUI-64 conflicts with an address provided by DHCPv6. Prompted by #17831.
-rw-r--r--src/network/networkd-dhcp6.c73
1 files changed, 67 insertions, 6 deletions
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);