]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: dhcp-pd: allow to assign the same subnet prefix to multiple interfaces 22574/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 20 Feb 2022 02:46:16 +0000 (11:46 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 22 Feb 2022 11:39:32 +0000 (20:39 +0900)
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.

src/network/networkd-dhcp-prefix-delegation.c
test/test-network/conf/25-dhcp-pd-downstream-dummy98.network
test/test-network/systemd-networkd-tests.py

index 7be9713d46b0d00d76dc7baec02df4bb874f1a03..bba66f71ed5d93170720dd4d47692a1cfe8737b5 100644 (file)
@@ -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;
 }
index 31090682fe910bd746c322abacc8958de30ac5f7..f7e3cbfee47f780711d9f85645c77041fb8f6c0a 100644 (file)
@@ -10,7 +10,7 @@ DHCPPrefixDelegation=yes
 
 [DHCPPrefixDelegation]
 UplinkInterface=veth99
-SubnetId=2
+SubnetId=0
 Announce=no
 Token=eui64
 Token=::1a:2b:3c:4d
index 35c9efd77d750b65b750eafae9af3027dcb1935c..39f5e58bef988711eabaa53ded5963781337394c 100755 (executable)
@@ -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')