From e198f1a8474c0e6bf64fe0dbe7701bb14c885bf8 Mon Sep 17 00:00:00 2001 From: Govind Venugopal Date: Fri, 30 Jan 2026 07:38:13 -0700 Subject: [PATCH] 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 --- src/network/networkd-dhcp-common.c | 2 + src/network/networkd-dhcp-prefix-delegation.c | 84 +++++++++++++++++++ src/network/networkd-dhcp-prefix-delegation.h | 1 + 3 files changed, 87 insertions(+) diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 2d8ee46ad9b..619c2f63770 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -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) { diff --git a/src/network/networkd-dhcp-prefix-delegation.c b/src/network/networkd-dhcp-prefix-delegation.c index 59ad2daaee3..f53d7d1c5aa 100644 --- a/src/network/networkd-dhcp-prefix-delegation.c +++ b/src/network/networkd-dhcp-prefix-delegation.c @@ -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, diff --git a/src/network/networkd-dhcp-prefix-delegation.h b/src/network/networkd-dhcp-prefix-delegation.h index 3ffc2beb541..502f98eb029 100644 --- a/src/network/networkd-dhcp-prefix-delegation.h +++ b/src/network/networkd-dhcp-prefix-delegation.h @@ -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); -- 2.47.3