]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: dhcp6: introduce UplinkInterface= for DHCP6 prefix delegation
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 13 Oct 2021 09:00:52 +0000 (18:00 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 26 Oct 2021 11:43:10 +0000 (20:43 +0900)
man/systemd.network.xml
src/network/networkd-dhcp-common.c
src/network/networkd-dhcp-common.h
src/network/networkd-dhcp6.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.h
test/fuzz/fuzz-network-parser/directives.network

index cdb6f4eb87b45d3ccdd740db1ffd4e3e100d8ede..b6bf993adc00796913fcb3a7516bdbb2a2b3e021 100644 (file)
@@ -2123,6 +2123,17 @@ Table=1234</programlisting></para>
     is enabled.</para>
 
     <variablelist class='network-directives'>
+      <varlistentry>
+        <term><varname>UplinkInterface=</varname></term>
+        <listitem>
+          <para>Specifies the name or the index of the uplink interface, or one of the special values
+          <literal>:self</literal> and <literal>:auto</literal>. When <literal>:self</literal>, the
+          interface itself is considered the uplink interface. When <literal>:auto</literal>, the first
+          link which acquired prefixes to be delegated from the DHCPv6 server is selected. Defaults to
+          <literal>:auto</literal>.</para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>SubnetId=</varname></term>
         <listitem>
index 3a77a457802db174416162639aeb6a249c559041..0c0a76d362df45aa456eca5fc0cfaccec7a7df89 100644 (file)
@@ -1281,6 +1281,7 @@ int config_parse_uplink(
                 void *userdata) {
 
         Network *network = userdata;
+        bool accept_none = true;
         int *index, r;
         char **name;
 
@@ -1288,6 +1289,7 @@ int config_parse_uplink(
         assert(section);
         assert(lvalue);
         assert(rvalue);
+        assert(userdata);
 
         if (streq(section, "DHCPServer")) {
                 index = &network->dhcp_server_uplink_index;
@@ -1295,6 +1297,10 @@ int config_parse_uplink(
         } else if (streq(section, "IPv6SendRA")) {
                 index = &network->router_uplink_index;
                 name = &network->router_uplink_name;
+        } else if (streq(section, "DHCPv6PrefixDelegation")) {
+                index = &network->dhcp6_pd_uplink_index;
+                name = &network->dhcp_server_uplink_name;
+                accept_none = false;
         } else
                 assert_not_reached();
 
@@ -1304,12 +1310,18 @@ int config_parse_uplink(
                 return 0;
         }
 
-        if (streq(rvalue, ":none")) {
+        if (accept_none && streq(rvalue, ":none")) {
                 *index = UPLINK_INDEX_NONE;
                 *name = mfree(*name);
                 return 0;
         }
 
+        if (!accept_none && streq(rvalue, ":self")) {
+                *index = UPLINK_INDEX_SELF;
+                *name = mfree(*name);
+                return 0;
+        }
+
         r = parse_ifindex(rvalue);
         if (r > 0) {
                 *index = r;
index 176f6c04fe0c7eee687dbe5241e3fe3c60df34bd..d45b92e1a9869ae6a15ef931a83278e7f5054aa5 100644 (file)
@@ -12,6 +12,7 @@
 /* Special values for *_uplink_index. */
 #define UPLINK_INDEX_AUTO  0 /* uplink will be selected automatically */
 #define UPLINK_INDEX_NONE -1 /* uplink will not be selected automatically */
+#define UPLINK_INDEX_SELF -2 /* the interface itself is uplink */
 
 #define DHCP_ROUTE_METRIC 1024
 #define DHCP6PD_ROUTE_METRIC 256
index 01850d49c52ff5ca72cbce36013375d93a0df619..52ff5eb3aab5db15a3cf3c5a6e8c24ade18097d8 100644 (file)
@@ -42,6 +42,22 @@ bool link_dhcp6_pd_is_enabled(Link *link) {
         return link->network->dhcp6_pd;
 }
 
+static int dhcp6_pd_resolve_uplink(Link *link, Link **ret) {
+        if (link->network->dhcp6_pd_uplink_name)
+                return link_get_by_name(link->manager, link->network->dhcp6_pd_uplink_name, ret);
+
+        if (link->network->dhcp6_pd_uplink_index > 0)
+                return link_get_by_index(link->manager, link->network->dhcp6_pd_uplink_index, ret);
+
+        if (link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_SELF) {
+                *ret = link;
+                return 0;
+        }
+
+        assert(link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_AUTO);
+        return -ENOENT;
+}
+
 static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
         uint32_t lifetime_preferred_sec, lifetime_valid_sec;
         struct in6_addr pd_prefix;
@@ -575,6 +591,7 @@ static int dhcp6_pd_distribute_prefix(
         assert(pd_prefix_len <= 64);
 
         HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
+                Link *uplink;
 
                 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
                         continue;
@@ -591,6 +608,15 @@ static int dhcp6_pd_distribute_prefix(
                 if (assign_preferred_subnet_id != link_has_preferred_subnet_id(link))
                         continue;
 
+                r = dhcp6_pd_resolve_uplink(link, &uplink);
+                if (r != -ENOENT) {
+                        if (r < 0) /* The uplink interface does not exist yet. */
+                                continue;
+
+                        if (uplink != dhcp6_link)
+                                continue;
+                }
+
                 r = dhcp6_pd_assign_prefix(link, pd_prefix, pd_prefix_len, lifetime_preferred_usec, lifetime_valid_usec);
                 if (r < 0) {
                         if (link == dhcp6_link)
@@ -1402,8 +1428,17 @@ static int dhcp6_pd_find_uplink(Link *link, Link **ret) {
 
         assert(link);
         assert(link->manager);
+        assert(link->network);
         assert(ret);
 
+        if (dhcp6_pd_resolve_uplink(link, &l) >= 0) {
+                if (!dhcp6_pd_uplink_is_ready(l))
+                        return -EBUSY;
+
+                *ret = l;
+                return 0;
+        }
+
         HASHMAP_FOREACH(l, link->manager->links_by_index) {
                 if (!dhcp6_pd_uplink_is_ready(l))
                         continue;
index 758aa8ee19e7304a5c9b892f96854549db8f510e..ccbf02b99d9472619434ea5dcc5cd13ece4ff758 100644 (file)
@@ -325,6 +325,7 @@ BridgeMDB.VLANId,                            config_parse_mdb_vlan_id,
 BridgeVLAN.PVID,                             config_parse_brvlan_pvid,                                 0,                             0
 BridgeVLAN.VLAN,                             config_parse_brvlan_vlan,                                 0,                             0
 BridgeVLAN.EgressUntagged,                   config_parse_brvlan_untagged,                             0,                             0
+DHCPv6PrefixDelegation.UplinkInterface,      config_parse_uplink,                                      0,                             0
 DHCPv6PrefixDelegation.SubnetId,             config_parse_dhcp6_pd_subnet_id,                          0,                             offsetof(Network, dhcp6_pd_subnet_id)
 DHCPv6PrefixDelegation.Announce,             config_parse_bool,                                        0,                             offsetof(Network, dhcp6_pd_announce)
 DHCPv6PrefixDelegation.Assign,               config_parse_bool,                                        0,                             offsetof(Network, dhcp6_pd_assign)
index 3972fc5c89265e27f02401573e2643b99d62759e..bd9758c899a7f6848d18516b94e3a4a7bbfe980a 100644 (file)
@@ -241,6 +241,8 @@ struct Network {
         int64_t dhcp6_pd_subnet_id;
         uint32_t dhcp6_pd_route_metric;
         Set *dhcp6_pd_tokens;
+        int dhcp6_pd_uplink_index;
+        char *dhcp6_pd_uplink_name;
 
         /* Bridge Support */
         int use_bpdu;
index dae13a243cd9623238c9e67eb03f3f7525434486..985c2fc0d3fc3e6032d7e79d622325f33e10be5b 100644 (file)
@@ -151,6 +151,7 @@ DUIDType=
 DUIDRawData=
 RouteTable=
 [DHCPv6PrefixDelegation]
+UplinkInterface=
 SubnetId=
 Announce=
 Assign=