network: fix NFTSet population when [DHCPPrefixDelegation] Assign=no (#40049)

When [DHCPPrefixDelegation] Assign=no, networkd creates routes instead of
addresses. These routes need to populate nftables sets for firewall
rules to work correctly.

This commit adds dhcp_pd_route_modify_nft_set() to handle NFT set
updates for DHCP-PD routes, similar to how address_modify_nft_set()
handles them for addresses.

Fixes: #38383
This commit is contained in:
Govind Venugopal
2026-01-30 23:38:13 +09:00
committed by GitHub
parent 3762ada7e3
commit e198f1a847
3 changed files with 87 additions and 0 deletions
+2
View File
@@ -18,6 +18,7 @@
#include "hexdecoct.h"
#include "in-addr-prefix-util.h"
#include "networkd-dhcp-common.h"
#include "networkd-dhcp-prefix-delegation.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
@@ -106,6 +107,7 @@ void network_adjust_dhcp(Network *network) {
}
network_adjust_dhcp4(network);
network_adjust_dhcp_prefix_delegation(network);
}
static bool duid_needs_product_uuid(const DUID *duid) {
@@ -157,6 +157,63 @@ static int dhcp_pd_get_assigned_subnet_prefix(Link *link, const struct in6_addr
return -ENOENT;
}
static void dhcp_pd_route_modify_nft_set(Route *route, Link *link, bool add) {
int r;
assert(route);
assert(link);
assert(link->manager);
assert(link->network);
if (!link->manager->nfnl)
return;
if (route->family != AF_INET6)
return;
if (route->source != NETWORK_CONFIG_SOURCE_DHCP_PD)
return;
/* When Assign=yes, address_modify_nft_set() manages the NFT set, not this function. */
if (link->network->dhcp_pd_assign)
return;
NFTSetContext *nft_set_context = &link->network->dhcp_pd_nft_set_context;
FOREACH_ARRAY(nft_set, nft_set_context->sets, nft_set_context->n_sets) {
assert(nft_set);
switch (nft_set->source) {
case NFT_SET_SOURCE_ADDRESS:
/* Should be already warned in network_adjust_dhcp_prefix_delegation(). */
continue;
case NFT_SET_SOURCE_PREFIX:
r = nft_set_element_modify_iprange(link->manager->nfnl, add, nft_set->nfproto, route->family, nft_set->table, nft_set->set,
&route->dst, route->dst_prefixlen);
break;
case NFT_SET_SOURCE_IFINDEX: {
uint32_t ifindex = link->ifindex;
r = nft_set_element_modify_any(link->manager->nfnl, add, nft_set->nfproto, nft_set->table, nft_set->set,
&ifindex, sizeof(ifindex));
break;
}
default:
assert_not_reached();
}
if (r < 0)
log_warning_errno(r, "Failed to %s NFT set entry: family %s, table %s, set %s, IP prefix %s, ignoring: %m",
add ? "add" : "delete",
nfproto_to_string(nft_set->nfproto), nft_set->table, nft_set->set,
IN_ADDR_PREFIX_TO_STRING(route->family, &route->dst, route->dst_prefixlen));
else
log_debug("%s NFT set entry: family %s, table %s, set %s, IP prefix %s",
add ? "Added" : "Deleted",
nfproto_to_string(nft_set->nfproto), nft_set->table, nft_set->set,
IN_ADDR_PREFIX_TO_STRING(route->family, &route->dst, route->dst_prefixlen));
}
}
int dhcp_pd_remove(Link *link, bool only_marked) {
int ret = 0;
@@ -185,6 +242,9 @@ int dhcp_pd_remove(Link *link, bool only_marked) {
link_remove_dhcp_pd_subnet_prefix(link, &route->dst.in6);
/* Remove NFTSet entries before removing the route */
dhcp_pd_route_modify_nft_set(route, link, /* add= */ false);
RET_GATHER(ret, route_remove_and_cancel(route, link->manager));
}
} else {
@@ -285,6 +345,9 @@ static int dhcp_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Reques
if (r <= 0)
return r;
/* Update NFTSet entries when route is successfully configured */
dhcp_pd_route_modify_nft_set(route, link, /* add= */ true);
r = dhcp_pd_check_ready(link);
if (r < 0)
link_enter_failed(link);
@@ -1333,6 +1396,27 @@ int link_drop_dhcp_pd_config(Link *link, Network *network) {
return 0;
}
void network_adjust_dhcp_prefix_delegation(Network *network) {
assert(network);
if (!network->dhcp_pd)
return;
if (network->dhcp_pd_assign)
return;
/* If Assign=no, then DHCPv6 PD will create routes instead of addresses.
* NFTSet=address:... is not supported in this case. */
FOREACH_ARRAY(nft_set, network->dhcp_pd_nft_set_context.sets, network->dhcp_pd_nft_set_context.n_sets)
if (nft_set->source == NFT_SET_SOURCE_ADDRESS) {
log_warning("%s: In [DHCPPrefixDelegation] section, when Assign= is disabled, "
"NFTSet=address:... is not supported and will be ignored.",
network->filename);
break;
}
}
int config_parse_dhcp_pd_subnet_id(
const char *unit,
const char *filename,
@@ -14,6 +14,7 @@ int dhcp6_pd_prefix_acquired(Link *uplink);
void dhcp4_pd_prefix_lost(Link *uplink);
void dhcp6_pd_prefix_lost(Link *uplink);
int dhcp_pd_reconfigure_address(Address *address, Link *link);
void network_adjust_dhcp_prefix_delegation(Network *network);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_pd_subnet_id);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_pd_prefix_route_type);