Skip to content

Commit 8411b64

Browse files
committed
netfilter: nf_tables: support for set flushing
This patch adds support for set flushing, that consists of walking over the set elements if the NFTA_SET_ELEM_LIST_ELEMENTS attribute is set. This patch requires the following changes: 1) Add set->ops->deactivate_one() operation: This allows us to deactivate an element from the set element walk path, given we can skip the lookup that happens in ->deactivate(). 2) Add a new nft_trans_alloc_gfp() function since we need to allocate transactions using GFP_ATOMIC given the set walk path happens with held rcu_read_lock. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent 37df530 commit 8411b64

File tree

4 files changed

+56
-7
lines changed

4 files changed

+56
-7
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ struct nft_expr;
259259
* @lookup: look up an element within the set
260260
* @insert: insert new element into set
261261
* @activate: activate new element in the next generation
262-
* @deactivate: deactivate element in the next generation
262+
* @deactivate: lookup for element and deactivate it in the next generation
263+
* @deactivate_one: deactivate element in the next generation
263264
* @remove: remove element from set
264265
* @walk: iterate over all set elemeennts
265266
* @privsize: function to return size of set private data
@@ -294,6 +295,9 @@ struct nft_set_ops {
294295
void * (*deactivate)(const struct net *net,
295296
const struct nft_set *set,
296297
const struct nft_set_elem *elem);
298+
bool (*deactivate_one)(const struct net *net,
299+
const struct nft_set *set,
300+
void *priv);
297301
void (*remove)(const struct nft_set *set,
298302
const struct nft_set_elem *elem);
299303
void (*walk)(const struct nft_ctx *ctx,

net/netfilter/nf_tables_api.c

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,12 @@ static void nft_ctx_init(struct nft_ctx *ctx,
111111
ctx->seq = nlh->nlmsg_seq;
112112
}
113113

114-
static struct nft_trans *nft_trans_alloc(const struct nft_ctx *ctx,
115-
int msg_type, u32 size)
114+
static struct nft_trans *nft_trans_alloc_gfp(const struct nft_ctx *ctx,
115+
int msg_type, u32 size, gfp_t gfp)
116116
{
117117
struct nft_trans *trans;
118118

119-
trans = kzalloc(sizeof(struct nft_trans) + size, GFP_KERNEL);
119+
trans = kzalloc(sizeof(struct nft_trans) + size, gfp);
120120
if (trans == NULL)
121121
return NULL;
122122

@@ -126,6 +126,12 @@ static struct nft_trans *nft_trans_alloc(const struct nft_ctx *ctx,
126126
return trans;
127127
}
128128

129+
static struct nft_trans *nft_trans_alloc(const struct nft_ctx *ctx,
130+
int msg_type, u32 size)
131+
{
132+
return nft_trans_alloc_gfp(ctx, msg_type, size, GFP_KERNEL);
133+
}
134+
129135
static void nft_trans_destroy(struct nft_trans *trans)
130136
{
131137
list_del(&trans->list);
@@ -3876,6 +3882,34 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
38763882
return err;
38773883
}
38783884

3885+
static int nft_flush_set(const struct nft_ctx *ctx,
3886+
const struct nft_set *set,
3887+
const struct nft_set_iter *iter,
3888+
const struct nft_set_elem *elem)
3889+
{
3890+
struct nft_trans *trans;
3891+
int err;
3892+
3893+
trans = nft_trans_alloc_gfp(ctx, NFT_MSG_DELSETELEM,
3894+
sizeof(struct nft_trans_elem), GFP_ATOMIC);
3895+
if (!trans)
3896+
return -ENOMEM;
3897+
3898+
if (!set->ops->deactivate_one(ctx->net, set, elem->priv)) {
3899+
err = -ENOENT;
3900+
goto err1;
3901+
}
3902+
3903+
nft_trans_elem_set(trans) = (struct nft_set *)set;
3904+
nft_trans_elem(trans) = *((struct nft_set_elem *)elem);
3905+
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
3906+
3907+
return 0;
3908+
err1:
3909+
kfree(trans);
3910+
return err;
3911+
}
3912+
38793913
static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
38803914
struct sk_buff *skb, const struct nlmsghdr *nlh,
38813915
const struct nlattr * const nla[])
@@ -3886,9 +3920,6 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
38863920
struct nft_ctx ctx;
38873921
int rem, err = 0;
38883922

3889-
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
3890-
return -EINVAL;
3891-
38923923
err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, genmask);
38933924
if (err < 0)
38943925
return err;
@@ -3900,6 +3931,18 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
39003931
if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
39013932
return -EBUSY;
39023933

3934+
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) {
3935+
struct nft_set_dump_args args = {
3936+
.iter = {
3937+
.genmask = genmask,
3938+
.fn = nft_flush_set,
3939+
},
3940+
};
3941+
set->ops->walk(&ctx, set, &args.iter);
3942+
3943+
return args.iter.err;
3944+
}
3945+
39033946
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
39043947
err = nft_del_setelem(&ctx, set, attr);
39053948
if (err < 0)

net/netfilter/nft_set_hash.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ static struct nft_set_ops nft_hash_ops __read_mostly = {
397397
.insert = nft_hash_insert,
398398
.activate = nft_hash_activate,
399399
.deactivate = nft_hash_deactivate,
400+
.deactivate_one = nft_hash_deactivate_one,
400401
.remove = nft_hash_remove,
401402
.lookup = nft_hash_lookup,
402403
.update = nft_hash_update,

net/netfilter/nft_set_rbtree.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ static struct nft_set_ops nft_rbtree_ops __read_mostly = {
304304
.insert = nft_rbtree_insert,
305305
.remove = nft_rbtree_remove,
306306
.deactivate = nft_rbtree_deactivate,
307+
.deactivate_one = nft_rbtree_deactivate_one,
307308
.activate = nft_rbtree_activate,
308309
.lookup = nft_rbtree_lookup,
309310
.walk = nft_rbtree_walk,

0 commit comments

Comments
 (0)