networkd: add RouteTable= to [DHCPv6] section

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.
This commit is contained in:
Nandakumar Raghavan
2026-05-20 03:03:33 +09:00
committed by Yu Watanabe
parent 94bbfd2a34
commit f7e6645ac6
7 changed files with 45 additions and 6 deletions
+17
View 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>
+17 -3
View 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;
+1
View 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) {
@@ -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)
+4 -3
View 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)
+1
View 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,
+2
View 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;