diff --git a/src/network/networkd-dhcp-prefix-delegation.c b/src/network/networkd-dhcp-prefix-delegation.c index 7be9713d46..bba66f71ed 100644 --- a/src/network/networkd-dhcp-prefix-delegation.c +++ b/src/network/networkd-dhcp-prefix-delegation.c @@ -487,20 +487,13 @@ static int dhcp_pd_get_preferred_subnet_prefix( "subnet id %" PRIu64 " is out of range. Only have %" PRIu64 " subnets.", link->network->dhcp_pd_subnet_id, UINT64_C(1) << (64 - pd_prefix_len)); - if (link_get_by_dhcp_pd_subnet_prefix(link->manager, &prefix, &assigned_link) >= 0 && - assigned_link != link) { - _cleanup_free_ char *assigned_buf = NULL; - - (void) in6_addr_to_string(&prefix, &assigned_buf); - return log_link_warning_errno(link, SYNTHETIC_ERRNO(EAGAIN), - "The requested prefix %s is already assigned to another link.", - strna(assigned_buf)); - } - *ret = prefix; return 0; } + if (dhcp_pd_get_assigned_subnet_prefix(link, pd_prefix, pd_prefix_len, ret) >= 0) + return 0; + for (uint64_t n = 0; ; n++) { /* If we do not have an allocation preference just iterate * through the address space and return the first free prefix. */ @@ -517,11 +510,16 @@ static int dhcp_pd_get_preferred_subnet_prefix( /* Check that the prefix is not assigned to another link. */ if (link_get_by_dhcp_pd_subnet_prefix(link->manager, &prefix, &assigned_link) < 0 || - assigned_link == link) { - *ret = prefix; - return 0; - } + assigned_link == link) + break; } + + r = link_add_dhcp_pd_subnet_prefix(link, &prefix); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to save acquired free subnet prefix: %m"); + + *ret = prefix; + return 0; } static int dhcp_pd_assign_subnet_prefix( @@ -540,9 +538,9 @@ static int dhcp_pd_assign_subnet_prefix( assert(link->network); assert(pd_prefix); - if (dhcp_pd_get_assigned_subnet_prefix(link, pd_prefix, pd_prefix_len, &prefix) < 0 && - dhcp_pd_get_preferred_subnet_prefix(link, pd_prefix, pd_prefix_len, &prefix) < 0) - return 0; + r = dhcp_pd_get_preferred_subnet_prefix(link, pd_prefix, pd_prefix_len, &prefix); + if (r < 0) + return r == -ERANGE ? 0 : r; (void) in6_addr_prefix_to_string(&prefix, 64, &buf); @@ -570,12 +568,6 @@ static int dhcp_pd_assign_subnet_prefix( "Failed to assign/update address for prefix %s: %m", strna(buf)); - r = link_add_dhcp_pd_subnet_prefix(link, &prefix); - if (r < 0) - return log_link_warning_errno(link, r, - "Failed to save assigned prefix %s: %m", - strna(buf)); - log_link_debug(link, "Assigned prefix %s", strna(buf)); return 1; } diff --git a/test/test-network/conf/25-dhcp-pd-downstream-dummy98.network b/test/test-network/conf/25-dhcp-pd-downstream-dummy98.network index 31090682fe..f7e3cbfee4 100644 --- a/test/test-network/conf/25-dhcp-pd-downstream-dummy98.network +++ b/test/test-network/conf/25-dhcp-pd-downstream-dummy98.network @@ -10,7 +10,7 @@ DHCPPrefixDelegation=yes [DHCPPrefixDelegation] UplinkInterface=veth99 -SubnetId=2 +SubnetId=0 Announce=no Token=eui64 Token=::1a:2b:3c:4d diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 35c9efd77d..39f5e58bef 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -5269,8 +5269,8 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): # Link Subnet IDs # test1: 0x00 # dummy97: 0x01 (The link will appear later) - # dummy98: 0x02 - # dummy99: auto -> 0x03 (No address assignment) + # dummy98: 0x00 + # dummy99: auto -> 0x02 (No address assignment) # veth97: 0x08 # veth98: 0x09 # veth99: 0x10 @@ -5300,15 +5300,15 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): output = check_output('ip -6 address show dev dummy98 scope global') print(output) # address in IA_PD (Token=static) - self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr') + self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr') # address in IA_PD (temporary) - self.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]02:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6') + self.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6') print('### ip -6 address show dev dummy99 scope global') output = check_output('ip -6 address show dev dummy99 scope global') print(output) # Assign=no - self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]03') + self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02') print('### ip -6 address show dev veth97 scope global') output = check_output('ip -6 address show dev veth97 scope global') @@ -5368,12 +5368,12 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): print('### ip -6 route show dev dummy98') output = check_output('ip -6 route show dev dummy98') print(output) - self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto kernel metric [0-9]* expires') + self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires') print('### ip -6 route show dev dummy99') output = check_output('ip -6 route show dev dummy99') print(output) - self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]03::/64 proto dhcp metric [0-9]* expires') + self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires') print('### ip -6 route show dev veth97') output = check_output('ip -6 route show dev veth97') @@ -5420,25 +5420,25 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): output = check_output('ip -6 address show dev dummy98 scope global') print(output) # address in IA_PD (Token=static) - self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr') + self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr') # address in IA_PD (temporary) - self.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]02:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6') + self.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6') print('### ip -6 address show dev dummy99 scope global') output = check_output('ip -6 address show dev dummy99 scope global') print(output) # Assign=no - self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]03') + self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02') print('### ip -6 route show dev dummy98') output = check_output('ip -6 route show dev dummy98') print(output) - self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto kernel metric [0-9]* expires') + self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires') print('### ip -6 route show dev dummy99') output = check_output('ip -6 route show dev dummy99') print(output) - self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]03::/64 proto dhcp metric [0-9]* expires') + self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires') def verify_dhcp4_6rd(self, tunnel_name): print('### ip -4 address show dev veth-peer scope global') @@ -5449,9 +5449,9 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): # Link Subnet IDs # test1: 0x00 # dummy97: 0x01 (The link will appear later) - # dummy98: 0x02 - # dummy99: auto -> 0x0[34] (No address assignment) - # 6rd-XXX: auto -> 0x0[34] + # dummy98: 0x00 + # dummy99: auto -> 0x0[23] (No address assignment) + # 6rd-XXX: auto -> 0x0[23] # veth97: 0x08 # veth98: 0x09 # veth99: 0x10 @@ -5484,15 +5484,15 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): output = check_output('ip -6 address show dev dummy98 scope global') print(output) # address in IA_PD (Token=static) - self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+02:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr') + self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr') # address in IA_PD (temporary) - self.wait_address('dummy98', 'inet6 2001:db8:6464:[0-9a-f]+02:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6') + self.wait_address('dummy98', 'inet6 2001:db8:6464:[0-9a-f]+00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6') print('### ip -6 address show dev dummy99 scope global') output = check_output('ip -6 address show dev dummy99 scope global') print(output) # Assign=no - self.assertNotRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+0[34]') + self.assertNotRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+0[23]') print('### ip -6 address show dev veth97 scope global') output = check_output('ip -6 address show dev veth97 scope global') @@ -5552,12 +5552,12 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): print('### ip -6 route show dev dummy98') output = check_output('ip -6 route show dev dummy98') print(output) - self.assertRegex(output, '2001:db8:6464:[0-9a-f]+02::/64 proto kernel metric [0-9]* expires') + self.assertRegex(output, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires') print('### ip -6 route show dev dummy99') output = check_output('ip -6 route show dev dummy99') print(output) - self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[34]::/64 proto dhcp metric [0-9]* expires') + self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires') print('### ip -6 route show dev veth97') output = check_output('ip -6 route show dev veth97') @@ -5604,13 +5604,13 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): print('### ip -6 address show dev {}'.format(tunnel_name)) output = check_output('ip -6 address show dev {}'.format(tunnel_name)) print(output) - self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+0[34]:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global dynamic') + self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+0[23]:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global dynamic') self.assertRegex(output, 'inet6 ::10.100.100.[0-9]+/96 scope global') print('### ip -6 route show dev {}'.format(tunnel_name)) output = check_output('ip -6 route show dev {}'.format(tunnel_name)) print(output) - self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[34]::/64 proto kernel metric [0-9]* expires') + self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires') self.assertRegex(output, '::/96 proto kernel metric [0-9]*') print('### ip -6 route show default')