From: Natarajan KV <natarajankv91@gmail.com>
To: stable@vger.kernel.org
Cc: gregkh@linuxfoundation.org, pablo@netfilter.org,
kadlec@netfilter.org, fw@strlen.de
Subject: [PATCH v3 6.6.y 7/8] netfilter: nft_set_pipapo: move cloning of match info to insert/removal path
Date: Wed, 04 Mar 2026 20:55:26 +0400 [thread overview]
Message-ID: <1772643278.pipapo-v3.7@gmail.com> (raw)
In-Reply-To: <1772643278.pipapo-v3.0@gmail.com>
Adaptation of commit 3f1d886cc7c3 ("netfilter: nft_set_pipapo: move
cloning of match info to insert/removal path") to 6.6.122.
Currently pipapo_clone() is called from the commit and abort
callbacks. commit and abort must not fail, but pipapo_clone()
can fail with ENOMEM.
Move pipapo_clone() from the commit/abort callbacks to the
insert and removal paths via pipapo_maybe_clone(), which
creates the working copy on demand and can propagate allocation
failures.
commit just swaps clone to match and sets clone to NULL.
abort just frees the clone.
Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges")
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Natarajan KV <natarajankv91@gmail.com>
---
net/netfilter/nft_set_pipapo.c | 89 ++++++++++++++++++----------------
1 file changed, 46 insertions(+), 43 deletions(-)
diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
index 176f1a8956a9..57b45e3b11ca 100644
--- a/net/netfilter/nft_set_pipapo.c
+++ b/net/netfilter/nft_set_pipapo.c
@@ -1208,14 +1208,16 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
const u8 *start = (const u8 *)elem->key.val.data, *end;
struct nft_pipapo_elem *e = elem->priv, *dup;
- struct nft_pipapo *priv = nft_set_priv(set);
- struct nft_pipapo_match *m = priv->clone;
+ struct nft_pipapo_match *m = pipapo_maybe_clone(set);
u8 genmask = nft_genmask_next(net);
u64 tstamp = nft_net_tstamp(net);
struct nft_pipapo_field *f;
const u8 *start_p, *end_p;
int i, bsize_max, err = 0;
+ if (!m)
+ return -ENOMEM;
+
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
end = (const u8 *)nft_set_ext_key_end(ext)->data;
else
@@ -1269,8 +1271,6 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
}
/* Insert */
- priv->dirty = true;
-
bsize_max = m->bsize_max;
nft_pipapo_for_each_field(f, i, m) {
@@ -1630,8 +1630,6 @@ static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m)
* NFT_SET_ELEM_DEAD_BIT.
*/
if (__nft_set_elem_expired(&e->ext, tstamp)) {
- priv->dirty = true;
-
gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
if (!gc)
return;
@@ -1709,46 +1707,54 @@ static void pipapo_reclaim_match(struct rcu_head *rcu)
static void nft_pipapo_commit(struct nft_set *set)
{
struct nft_pipapo *priv = nft_set_priv(set);
- struct nft_pipapo_match *new_clone, *old;
-
- if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set)))
- pipapo_gc(set, priv->clone);
-
- if (!priv->dirty)
- return;
+ struct nft_pipapo_match *old;
- new_clone = pipapo_clone(priv->clone);
- if (!new_clone)
+ if (!priv->clone)
return;
- priv->dirty = false;
+ if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set)))
+ pipapo_gc(set, priv->clone);
old = rcu_access_pointer(priv->match);
rcu_assign_pointer(priv->match, priv->clone);
+ priv->clone = NULL;
+
if (old)
call_rcu(&old->rcu, pipapo_reclaim_match);
-
- priv->clone = new_clone;
}
-static void nft_pipapo_abort(const struct nft_set *set)
+static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old);
+
+/**
+ * pipapo_maybe_clone() - Build clone for pending data changes, if not existing
+ * @set: nftables API set representation
+ *
+ * Return: newly created or existing clone, if any. NULL on allocation failure.
+ */
+static struct nft_pipapo_match *pipapo_maybe_clone(const struct nft_set *set)
{
struct nft_pipapo *priv = nft_set_priv(set);
- struct nft_pipapo_match *new_clone, *m;
+ struct nft_pipapo_match *m;
- if (!priv->dirty)
- return;
+ if (priv->clone)
+ return priv->clone;
- m = rcu_dereference_protected(priv->match, nft_pipapo_transaction_mutex_held(set));
+ m = rcu_dereference_protected(priv->match,
+ nft_pipapo_transaction_mutex_held(set));
+ priv->clone = pipapo_clone(m);
- new_clone = pipapo_clone(m);
- if (!new_clone)
- return;
+ return priv->clone;
+}
- priv->dirty = false;
+static void nft_pipapo_abort(const struct nft_set *set)
+{
+ struct nft_pipapo *priv = nft_set_priv(set);
+
+ if (!priv->clone)
+ return;
pipapo_free_match(priv->clone);
- priv->clone = new_clone;
+ priv->clone = NULL;
}
/**
@@ -1787,10 +1793,13 @@ static void nft_pipapo_activate(const struct net *net,
static void *pipapo_deactivate(const struct net *net, const struct nft_set *set,
const u8 *data, const struct nft_set_ext *ext)
{
- struct nft_pipapo *priv = nft_set_priv(set);
+ struct nft_pipapo_match *m = pipapo_maybe_clone(set);
struct nft_pipapo_elem *e;
- e = pipapo_get(priv->clone, data, nft_genmask_next(net), nft_net_tstamp(net));
+ if (!m)
+ return NULL;
+
+ e = pipapo_get(m, data, nft_genmask_next(net), nft_net_tstamp(net));
if (IS_ERR(e))
return NULL;
@@ -1973,8 +1982,7 @@ static bool pipapo_match_field(struct nft_pipapo_field *f,
static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
const struct nft_set_elem *elem)
{
- struct nft_pipapo *priv = nft_set_priv(set);
- struct nft_pipapo_match *m = priv->clone;
+ struct nft_pipapo_match *m = pipapo_maybe_clone(set);
struct nft_pipapo_elem *e = elem->priv;
int rules_f0, first_rule = 0;
const u8 *data;
@@ -2014,7 +2022,6 @@ static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
match_end += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
if (last && f->mt[rulemap[i].to].e == e) {
- priv->dirty = true;
pipapo_drop(m, rulemap);
return;
}
@@ -2087,7 +2094,11 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
switch (iter->type) {
case NFT_ITER_UPDATE:
- m = priv->clone;
+ m = pipapo_maybe_clone(set);
+ if (!m) {
+ iter->err = -ENOMEM;
+ break;
+ }
nft_pipapo_do_walk(ctx, set, m, iter);
break;
case NFT_ITER_READ:
@@ -2199,20 +2210,12 @@ static int nft_pipapo_init(const struct nft_set *set,
f->mt = NULL;
}
- /* Create an initial clone of matching data for next insertion */
- priv->clone = pipapo_clone(m);
- if (!priv->clone) {
- err = -ENOMEM;
- goto out_free;
- }
-
- priv->dirty = false;
+ priv->clone = NULL;
rcu_assign_pointer(priv->match, m);
return 0;
-out_free:
free_percpu(m->scratch);
out_scratch:
kfree(m);
--
2.34.1
next prev parent reply other threads:[~2026-03-04 16:55 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-04 13:38 [PATCH] netfilter: nft_set_pipapo: clear dirty flag on abort/commit clone failure Natarajan KV
2026-03-04 13:47 ` Greg KH
2026-03-04 13:50 ` Florian Westphal
2026-03-04 15:08 ` [PATCH v2] netfilter: nft_set_pipapo: move clone allocation to insert/removal path Natarajan KV
2026-03-04 15:12 ` Greg KH
2026-03-04 16:54 ` [PATCH v3 6.6.y 0/8] " Natarajan KV
2026-03-04 16:54 ` [PATCH v3 6.6.y 1/8] netfilter: nft_set_pipapo: move prove_locking helper around Natarajan KV
2026-03-04 16:54 ` [PATCH v3 6.6.y 2/8] netfilter: nft_set_pipapo: make pipapo_clone helper return NULL Natarajan KV
2026-03-04 16:55 ` [PATCH v3 6.6.y 3/8] netfilter: nft_set_pipapo: prepare destroy function for on-demand clone Natarajan KV
2026-03-04 16:55 ` [PATCH v3 6.6.y 4/8] netfilter: nft_set_pipapo: prepare walk " Natarajan KV
2026-03-04 16:55 ` [PATCH v3 6.6.y 5/8] netfilter: nft_set_pipapo: merge deactivate helper into caller Natarajan KV
2026-03-04 16:55 ` [PATCH v3 6.6.y 6/8] netfilter: nft_set_pipapo: prepare pipapo_get helper for on-demand clone Natarajan KV
2026-03-04 16:55 ` Natarajan KV [this message]
2026-03-04 16:55 ` [PATCH v3 6.6.y 8/8] netfilter: nft_set_pipapo: remove dirty flag Natarajan KV
2026-03-04 21:30 ` [PATCH v3 6.6.y 0/8] netfilter: nft_set_pipapo: move clone allocation to insert/removal path 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=1772643278.pipapo-v3.7@gmail.com \
--to=natarajankv91@gmail.com \
--cc=fw@strlen.de \
--cc=gregkh@linuxfoundation.org \
--cc=kadlec@netfilter.org \
--cc=pablo@netfilter.org \
--cc=stable@vger.kernel.org \
/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