networkd: preserve exact host-prefix pool addresses

Address pool allocation checks a selected prefix before address_acquire()
forces its lowest bit to one. For /32 and /128, this changes the
checked address and can return an address that is already in use.

Keep exact host-prefix addresses unchanged and only select the first
host address when the prefix leaves host bits available.

(cherry picked from commit a0a493a038)
(cherry picked from commit 27e2f6b49d)
This commit is contained in:
zouge666 authored and Luca Boccassi committed 2026-11-05 14:48:10 +00:00
1 parent 950525d9fa
commit b79761ddc3
3 files changed
+23 -7

No files matched your search

+7 -7
View File
@@ -1641,13 +1641,13 @@ static int address_acquire(Link *link, const Address *address, union in_addr_uni
if (r == 0)
return -EBUSY;
/* Pick first address in range for ourselves. */
if (address->family == AF_INET)
a.in.s_addr |= htobe32(1);
else if (address->family == AF_INET6)
a.in6.s6_addr[15] |= 1;
else
assert_not_reached();
/* Pick first address in range for ourselves. A host prefix already identifies the exact address. */
if (address->prefixlen < FAMILY_ADDRESS_SIZE(address->family) * 8) {
if (address->family == AF_INET)
a.in.s_addr |= htobe32(1);
else
a.in6.s6_addr[15] |= 1;
}
*ret = a;
return 0;
@@ -170,12 +170,19 @@ Label=subnet16
Address=0.0.0.0/24
Label=subnet24
[Address]
Address=0.0.0.0/32
Label=host32
[Address]
Address=::/73
[Address]
Address=::/74
[Address]
Address=::/128
[Address]
Address=10.10.1.1/24
# just a random label which should exist
@@ -4191,25 +4191,34 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
ip4_null_16 = None
ip4_null_24 = None
ip4_null_32 = None
output = check_output('ip -4 --json address show dev dummy98')
for i in json.loads(output)[0]['addr_info']:
if i['label'] == 'subnet16':
ip4_null_16 = i['local']
elif i['label'] == 'subnet24':
ip4_null_24 = i['local']
elif i['label'] == 'host32':
ip4_null_32 = i
self.assertTrue(ip4_null_16.endswith('.0.1'))
self.assertTrue(ip4_null_24.endswith('.1'))
self.assertIsNotNone(ip4_null_32)
self.assertEqual(ip4_null_32['prefixlen'], 32)
ip6_null_73 = None
ip6_null_74 = None
ip6_null_128 = None
output = check_output('ip -6 --json address show dev dummy98')
for i in json.loads(output)[0]['addr_info']:
if i['prefixlen'] == 73:
ip6_null_73 = i['local']
elif i['prefixlen'] == 74:
ip6_null_74 = i['local']
elif i['prefixlen'] == 128 and i['local'].startswith('fd'):
ip6_null_128 = i
self.assertTrue(ip6_null_73.endswith(':1'))
self.assertTrue(ip6_null_74.endswith(':1'))
self.assertIsNotNone(ip6_null_128)
self.verify_address_static(
label1='label1',