From 6174dc7d9612405b853511b277269ba5951e618f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 11 Sep 2023 00:30:14 +0900 Subject: [PATCH] network: allow to configure multiple IPv6 null addresses with different prefix length Previously, even if a .network file contains multiple IPv6 null addresses with different prefix length, only the first setting is applied, as the remainings are deduped in network_drop_invalid_addresses(). Even though the kernel allows us to change the prefix length of an existing IPv6 address, we cannot safely change the prefix length of an address that is originally requested as a null address, as the prefix of the address may conflict with other addresses if we change it. We already prohibit to change the prefix length of an existing IPv6 address that is originally requested as a null address. So, we can safely allow to configure multiple IPv6 addresses from null addresses by relaxing the dedup logic. The dedup is govern by the hash_ops. This adds a special handling for IPv6 null addresses. --- src/network/networkd-address.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 8e6d913cd5..b94e0d3af0 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -373,6 +373,9 @@ static void address_hash_func(const Address *a, struct siphash *state) { } case AF_INET6: siphash24_compress(&a->in_addr.in6, sizeof(a->in_addr.in6), state); + + if (in6_addr_is_null(&a->in_addr.in6)) + siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state); break; default: @@ -407,7 +410,16 @@ static int address_compare_func(const Address *a1, const Address *a2) { } case AF_INET6: /* See kernel's ipv6_get_ifaddr() in net/ipv6/addrconf.c */ - return memcmp(&a1->in_addr.in6, &a2->in_addr.in6, sizeof(a1->in_addr.in6)); + r = memcmp(&a1->in_addr.in6, &a2->in_addr.in6, sizeof(a1->in_addr.in6)); + if (r != 0) + return r; + + /* To distinguish IPv6 null addresses with different prefixlen, e.g. ::48 vs ::64, let's + * compare the prefix length. */ + if (in6_addr_is_null(&a1->in_addr.in6)) + r = CMP(a1->prefixlen, a2->prefixlen); + + return r; default: /* treat any other address family as AF_UNSPEC */ -- 2.25.1