]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkd: add RouteTable= to [DHCPv6] section
authorNandakumar Raghavan <naraghavan@microsoft.com>
Tue, 28 Apr 2026 11:14:48 +0000 (11:14 +0000)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 19 May 2026 18:03:33 +0000 (03:03 +0900)
Allow users to allow DHCPv6 unreachable/blackhole routes (installed
for delegated prefixes) into a specific routing table, analogous to
the existing RouteTable= in [DHCPv4] and [IPv6AcceptRA].

The config parser config_parse_dhcp_or_ra_route_table() is extended
with an AF_UNSPEC ltype discriminator for DHCPv6 (AF_INET6 is already
taken by NDISC/RA). link_get_dhcp6_route_table() follows the same
pattern as link_get_dhcp4_route_table() and link_get_ndisc_route_table(),
falling back to the VRF table when not explicitly set.

In dhcp_request_unreachable_route(), the table is applied only for
NETWORK_CONFIG_SOURCE_DHCP6 routes (the uplink unreachable aggregates),
not DHCP_PD routes (per-subnet routes on downstream interfaces), matching
the intent of the feature. The !route->table_set guard avoids overriding
a table already set by the route code.

man/systemd.network.xml
src/network/networkd-dhcp-common.c
src/network/networkd-dhcp-common.h
src/network/networkd-dhcp-prefix-delegation.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h

index 554d8da8ef606e22499d711d0fa1962eff2a6a51..d62e4d62329eda6e9ed452095d601df2df87d5bc 100644 (file)
@@ -3188,6 +3188,23 @@ MultiPathRoute=2001:db8::1@eth0</programlisting>
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>RouteTable=<replaceable>num</replaceable></varname></term>
+        <listitem>
+          <para>The table identifier for routes installed by the DHCPv6 client, e.g. unreachable
+          routes for delegated prefixes. Takes one of the predefined names <literal>default</literal>,
+          <literal>main</literal>, and <literal>local</literal>, names defined in
+          <varname>RouteTable=</varname> in
+          <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+          or a number between 1…4294967295.</para>
+
+          <para>When used in combination with <varname>VRF=</varname>, the VRF's routing table is
+          used when this parameter is not specified.</para>
+
+          <xi:include href="version-info.xml" xpointer="v261"/>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>RapidCommit=</varname></term>
         <listitem>
index d2e51e7e91bc32f7bcf990fbb324ace4a138d3f4..3368145981f9f19958f8cb810dea65ab916e8f50 100644 (file)
@@ -24,6 +24,7 @@
 #include "networkd-manager.h"
 #include "networkd-network.h"
 #include "networkd-route-util.h"
+#include "networkd-util.h"
 #include "parse-util.h"
 #include "set.h"
 #include "socket-util.h"
@@ -60,6 +61,15 @@ uint32_t link_get_ndisc_route_table(Link *link) {
         return link_get_vrf_table(link);
 }
 
+uint32_t link_get_dhcp6_route_table(Link *link) {
+        assert(link);
+        assert(link->network);
+
+        if (link->network->dhcp6_route_table_set)
+                return link->network->dhcp6_route_table;
+        return link_get_vrf_table(link);
+}
+
 bool link_dhcp_enabled(Link *link, int family) {
         assert(link);
         assert(IN_SET(family, AF_INET, AF_INET6));
@@ -565,7 +575,7 @@ int config_parse_dhcp_or_ra_route_table(
 
         assert(filename);
         assert(lvalue);
-        assert(IN_SET(ltype, AF_INET, AF_INET6));
+        assert(IN_SET(ltype, NETWORK_CONFIG_SOURCE_DHCP4, NETWORK_CONFIG_SOURCE_DHCP6, NETWORK_CONFIG_SOURCE_NDISC));
         assert(rvalue);
 
         r = manager_get_route_table_from_string(network->manager, rvalue, &rt);
@@ -576,11 +586,15 @@ int config_parse_dhcp_or_ra_route_table(
         }
 
         switch (ltype) {
-        case AF_INET:
+        case NETWORK_CONFIG_SOURCE_DHCP4:
                 network->dhcp_route_table = rt;
                 network->dhcp_route_table_set = true;
                 break;
-        case AF_INET6:
+        case NETWORK_CONFIG_SOURCE_DHCP6:
+                network->dhcp6_route_table = rt;
+                network->dhcp6_route_table_set = true;
+                break;
+        case NETWORK_CONFIG_SOURCE_NDISC:
                 network->ndisc_route_table = rt;
                 network->ndisc_route_table_set = true;
                 break;
index 6be8bcd6dc3746358e82db944f689eff26b10478..b6385492c38a327dacf930c947c2ae1003cc2ebb 100644 (file)
@@ -41,6 +41,7 @@ typedef struct DUID {
 
 uint32_t link_get_dhcp4_route_table(Link *link);
 uint32_t link_get_ndisc_route_table(Link *link);
+uint32_t link_get_dhcp6_route_table(Link *link);
 
 bool link_dhcp_enabled(Link *link, int family);
 static inline bool link_dhcp4_enabled(Link *link) {
index e734b0171d37ac66b771d221b426c929a7423038..85c52334726be1167fe807d7e81a010c6717a281 100644 (file)
@@ -14,6 +14,7 @@
 #include "in-addr-prefix-util.h"
 #include "networkd-address.h"
 #include "networkd-address-generation.h"
+#include "networkd-dhcp-common.h"
 #include "networkd-dhcp-prefix-delegation.h"
 #include "networkd-dhcp6.h"
 #include "networkd-link.h"
@@ -851,6 +852,8 @@ static int dhcp_request_unreachable_route(
         route->protocol = RTPROT_DHCP;
         route->priority = IP6_RT_PRIO_USER;
         route->lifetime_usec = lifetime_usec;
+        if (source == NETWORK_CONFIG_SOURCE_DHCP6 && !route->table_set)
+                route->table = link_get_dhcp6_route_table(link);
 
         r = route_adjust_nexthops(route, link);
         if (r < 0)
index a5afeed1cb43f5212a5b45c5ce61ff8bdc5ec58b..9e6eb7c799572057631396e8513349d9be1b14fb 100644 (file)
@@ -283,7 +283,7 @@ DHCPv4.IAID,                                     config_parse_iaid,
 DHCPv4.DUIDType,                                 config_parse_network_duid_type,                 0,                                      0
 DHCPv4.DUIDRawData,                              config_parse_network_duid_rawdata,              0,                                      0
 DHCPv4.RouteMetric,                              config_parse_dhcp_route_metric,                 AF_INET,                                0
-DHCPv4.RouteTable,                               config_parse_dhcp_or_ra_route_table,            AF_INET,                                0
+DHCPv4.RouteTable,                               config_parse_dhcp_or_ra_route_table,            NETWORK_CONFIG_SOURCE_DHCP4,            0
 DHCPv4.UseTimezone,                              config_parse_bool,                              0,                                      offsetof(Network, dhcp_use_timezone)
 DHCPv4.ListenPort,                               config_parse_uint16,                            0,                                      offsetof(Network, dhcp_client_port)
 DHCPv4.ServerPort,                               config_parse_uint16,                            0,                                      offsetof(Network, dhcp_port)
@@ -332,6 +332,7 @@ DHCPv6.RapidCommit,                              config_parse_bool,
 DHCPv6.NetLabel,                                 config_parse_string,                            CONFIG_PARSE_STRING_SAFE,               offsetof(Network, dhcp6_netlabel)
 DHCPv6.SendRelease,                              config_parse_bool,                              0,                                      offsetof(Network, dhcp6_send_release)
 DHCPv6.NFTSet,                                   config_parse_nft_set,                           NFT_SET_PARSE_NETWORK,                  offsetof(Network, dhcp6_nft_set_context)
+DHCPv6.RouteTable,                               config_parse_dhcp_or_ra_route_table,            NETWORK_CONFIG_SOURCE_DHCP6,            0
 IPv6AcceptRA.UseRedirect,                        config_parse_bool,                              0,                                      offsetof(Network, ndisc_use_redirect)
 IPv6AcceptRA.UseGateway,                         config_parse_bool,                              0,                                      offsetof(Network, ndisc_use_gateway)
 IPv6AcceptRA.UseRoutePrefix,                     config_parse_bool,                              0,                                      offsetof(Network, ndisc_use_route_prefix)
@@ -346,7 +347,7 @@ IPv6AcceptRA.UseHopLimit,                        config_parse_bool,
 IPv6AcceptRA.UseReachableTime,                   config_parse_bool,                              0,                                      offsetof(Network, ndisc_use_reachable_time)
 IPv6AcceptRA.UseRetransmissionTime,              config_parse_bool,                              0,                                      offsetof(Network, ndisc_use_retransmission_time)
 IPv6AcceptRA.DHCPv6Client,                       config_parse_ndisc_start_dhcp6_client,          0,                                      offsetof(Network, ndisc_start_dhcp6_client)
-IPv6AcceptRA.RouteTable,                         config_parse_dhcp_or_ra_route_table,            AF_INET6,                               0
+IPv6AcceptRA.RouteTable,                         config_parse_dhcp_or_ra_route_table,            NETWORK_CONFIG_SOURCE_NDISC,            0
 IPv6AcceptRA.RouteMetric,                        config_parse_ndisc_route_metric,                0,                                      0
 IPv6AcceptRA.QuickAck,                           config_parse_bool,                              0,                                      offsetof(Network, ndisc_quickack)
 IPv6AcceptRA.UseCaptivePortal,                   config_parse_bool,                              0,                                      offsetof(Network, ndisc_use_captive_portal)
@@ -669,7 +670,7 @@ DHCP.IAID,                                       config_parse_iaid,
 DHCP.DUIDType,                                   config_parse_network_duid_type,                 0,                                      0
 DHCP.DUIDRawData,                                config_parse_network_duid_rawdata,              0,                                      0
 DHCP.RouteMetric,                                config_parse_dhcp_route_metric,                 AF_UNSPEC,                              0
-DHCP.RouteTable,                                 config_parse_dhcp_or_ra_route_table,            AF_INET,                                0
+DHCP.RouteTable,                                 config_parse_dhcp_or_ra_route_table,            NETWORK_CONFIG_SOURCE_DHCP4,            0
 DHCP.UseTimezone,                                config_parse_bool,                              0,                                      offsetof(Network, dhcp_use_timezone)
 DHCP.ListenPort,                                 config_parse_uint16,                            0,                                      offsetof(Network, dhcp_client_port)
 DHCP.RapidCommit,                                config_parse_bool,                              0,                                      offsetof(Network, dhcp6_use_rapid_commit)
index 17cf78db37af046feecb1c56b02cc2b44c009e59..dfe524d150d23196f8d7bcce72a348f1dde69bbf 100644 (file)
@@ -424,6 +424,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                 .dhcp6_client_start_mode = _DHCP6_CLIENT_START_MODE_INVALID,
                 .dhcp6_send_release = true,
                 .dhcp6_pd_prefix_route_type = RTN_UNREACHABLE,
+                .dhcp6_route_table = RT_TABLE_MAIN,
 
                 .dhcp_pd = -1,
                 .dhcp_pd_announce = true,
index d1765a2bf46d354e04739bc8d0f65a19fd63ab9d..625b3b9a08c3184d2c5d9acd9694e0efe2c40b5b 100644 (file)
@@ -205,6 +205,8 @@ typedef struct Network {
         char *dhcp6_netlabel;
         bool dhcp6_send_release;
         NFTSetContext dhcp6_nft_set_context;
+        uint32_t dhcp6_route_table;
+        bool dhcp6_route_table_set;
 
         /* DHCP Server Support */
         bool dhcp_server;