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.
This commit is contained in:
Yu Watanabe 2023-09-11 00:30:14 +09:00
parent 381e3cc68b
commit 6174dc7d96

View file

@ -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 */