From: Yu Watanabe Date: Sun, 20 Feb 2022 02:46:16 +0000 (+0900) Subject: network: dhcp-pd: allow to assign the same subnet prefix to multiple interfaces X-Git-Tag: v251-rc1~243^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F22574%2Fhead;p=thirdparty%2Fsystemd.git network: dhcp-pd: allow to assign the same subnet prefix to multiple interfaces There is no reason networkd refuses that. Especially, when multiple downstream interfaces are connected to the same network, it is natural to assign the same subnet prefix to them. Prompted by #22571. --- diff --git a/src/network/networkd-dhcp-prefix-delegation.c b/src/network/networkd-dhcp-prefix-delegation.c index 7be9713d46b..bba66f71ed5 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 31090682fe9..f7e3cbfee47 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 35c9efd77d7..39f5e58bef9 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')