From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Cc: davem@davemloft.net, netdev@vger.kernel.org, kuba@kernel.org,
pabeni@redhat.com, edumazet@google.com, horms@kernel.org,
fw@strlen.de, ja@ssi.bg
Subject: [PATCH net-next 7/8] netfilter: nf_tables: call set ops .commit when building new ruleset blob
Date: Tue, 18 Aug 2026 01:29:56 +0200 [thread overview]
Message-ID: <20260817232957.1281637-8-pablo@netfilter.org> (raw)
In-Reply-To: <20260817232957.1281637-1-pablo@netfilter.org>
The rbtree set only builds the b-search array after the new ruleset has
been published through set ops .commit.
This exposes an empty set for a short time span which results in a bogus
mismatch for the following batch:
destroy table ip x
table ip x {
...
}
The same problem also affects the pipapo set backend which also provides
a set ops .commit interface too.
This patch moves the set ops .commit call right before building and
publishing the chain blob. The commit path now performs an early
handling of the DELSETELEM command to remove stale elements from the
clone before it is published via rcu. Note that DELSETELEM notifications
are still delivered in order. NEWSETELEM commands are handled after the
set is published, since this clears the previous genbit to 1 to prepare
the element for the next control plane transaction. This comes at the
cost of one extra iteration over the transaction list.
Suggested-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_tables_api.c | 56 ++++++++++++++++++++++++++++++-----
1 file changed, 48 insertions(+), 8 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index b51ba77b5151..c112ecc4fca3 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -7191,16 +7191,19 @@ static void nft_setelem_remove(const struct net *net,
}
static void nft_trans_elems_remove(const struct nft_ctx *ctx,
- const struct nft_trans_elem *te)
+ const struct nft_trans_elem *te,
+ bool notify)
{
int i;
for (i = 0; i < te->nelems; i++) {
WARN_ON_ONCE(te->elems[i].update);
- nf_tables_setelem_notify(ctx, te->set,
- te->elems[i].priv,
- te->nft_trans.msg_type);
+ if (notify) {
+ nf_tables_setelem_notify(ctx, te->set,
+ te->elems[i].priv,
+ te->nft_trans.msg_type);
+ }
nft_setelem_remove(ctx->net, te->set, te->elems[i].priv);
if (!nft_setelem_is_catchall(te->set, te->elems[i].priv)) {
@@ -7210,6 +7213,20 @@ static void nft_trans_elems_remove(const struct nft_ctx *ctx,
}
}
+static void nft_trans_elems_remove_notify(const struct nft_ctx *ctx,
+ const struct nft_trans_elem *te)
+{
+ int i;
+
+ for (i = 0; i < te->nelems; i++) {
+ WARN_ON_ONCE(te->elems[i].update);
+
+ nf_tables_setelem_notify(ctx, te->set,
+ te->elems[i].priv,
+ te->nft_trans.msg_type);
+ }
+}
+
static bool nft_setelem_valid_key_end(const struct nft_set *set,
struct nlattr **nla, u32 flags)
{
@@ -10863,9 +10880,29 @@ static void nf_tables_commit_audit_log(struct list_head *adl, u32 generation)
}
}
-static void nft_set_commit_update(struct nftables_pernet *nft_net)
+static void nft_set_commit_update(struct nft_ctx *ctx,
+ struct nftables_pernet *nft_net)
{
struct nft_set *set, *next;
+ struct nft_trans_elem *te;
+ struct nft_trans *trans;
+
+ if (list_empty(&nft_net->set_update_list))
+ return;
+
+ list_for_each_entry(trans, &nft_net->commit_list, list) {
+ nft_ctx_update(ctx, trans);
+
+ switch (trans->msg_type) {
+ case NFT_MSG_DELSETELEM:
+ te = nft_trans_container_elem(trans);
+ if (!te->set->ops->commit)
+ break;
+
+ nft_trans_elems_remove(ctx, te, false);
+ break;
+ }
+ }
list_for_each_entry_safe(set, next, &nft_net->set_update_list, pending_update) {
list_del_init(&set->pending_update);
@@ -10974,6 +11011,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
}
/* step 2. Make rules_gen_X visible to packet path */
+ nft_set_commit_update(&ctx, nft_net);
+
list_for_each_entry(table, &nft_net->tables, list) {
list_for_each_entry(chain, &table->chains, list)
nf_tables_commit_chain(net, chain);
@@ -11111,7 +11150,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
case NFT_MSG_DELSETELEM:
case NFT_MSG_DESTROYSETELEM:
te = nft_trans_container_elem(trans);
- nft_trans_elems_remove(&ctx, te);
+ if (te->set->ops->commit)
+ nft_trans_elems_remove_notify(&ctx, te);
+ else
+ nft_trans_elems_remove(&ctx, te, true);
break;
case NFT_MSG_NEWOBJ:
if (nft_trans_obj_update(trans)) {
@@ -11180,8 +11222,6 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
}
}
- nft_set_commit_update(nft_net);
-
nft_commit_notify(net, NETLINK_CB(skb).portid);
nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
nf_tables_commit_audit_log(&adl, nft_base_seq(net));
--
2.47.3
next prev parent reply other threads:[~2026-08-17 23:30 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-17 23:29 [PATCH net-next 0/8] Netfilter/IPVS fixes for net-next Pablo Neira Ayuso
2026-08-17 23:29 ` [PATCH net-next 1/8] netfilter: validate L4 headers after userspace packet writes Pablo Neira Ayuso
2026-08-17 23:29 ` [PATCH net-next 2/8] netfilter: ipset: remove need to allocate memory on delete operations Pablo Neira Ayuso
2026-08-17 23:29 ` [PATCH net-next 3/8] netfilter: nf_tables: don't queue packet path object notifications Pablo Neira Ayuso
2026-08-17 23:29 ` [PATCH net-next 4/8] netfilter: nf_conntrack_expect: consolidate check for insertion of dead expectation Pablo Neira Ayuso
2026-08-17 23:29 ` [PATCH net-next 5/8] netfilter: ctnetlink: do not expose expectation DEAD flag Pablo Neira Ayuso
2026-08-17 23:29 ` [PATCH net-next 6/8] netfilter: nf_tables: move set_update_list to nftables per-netns Pablo Neira Ayuso
2026-08-17 23:29 ` Pablo Neira Ayuso [this message]
2026-08-17 23:29 ` [PATCH net-next 8/8] ipvs: fix integer overflow in ftp helper port/address parsing Pablo Neira Ayuso
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260817232957.1281637-8-pablo@netfilter.org \
--to=pablo@netfilter.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fw@strlen.de \
--cc=horms@kernel.org \
--cc=ja@ssi.bg \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox