Skip to content

Commit 8d8540c

Browse files
committed
netfilter: nft_set_rbtree: add timeout support
Add garbage collection logic to expire elements stored in the rb-tree representation. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 57a4c9c commit 8d8540c

File tree

1 file changed

+72
-3
lines changed

1 file changed

+72
-3
lines changed

net/netfilter/nft_set_rbtree.c

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ struct nft_rbtree {
2222
struct rb_root root;
2323
rwlock_t lock;
2424
seqcount_t count;
25+
struct delayed_work gc_work;
2526
};
2627

2728
struct nft_rbtree_elem {
@@ -265,15 +266,20 @@ static void nft_rbtree_activate(const struct net *net,
265266
struct nft_rbtree_elem *rbe = elem->priv;
266267

267268
nft_set_elem_change_active(net, set, &rbe->ext);
269+
nft_set_elem_clear_busy(&rbe->ext);
268270
}
269271

270272
static bool nft_rbtree_flush(const struct net *net,
271273
const struct nft_set *set, void *priv)
272274
{
273275
struct nft_rbtree_elem *rbe = priv;
274276

275-
nft_set_elem_change_active(net, set, &rbe->ext);
276-
return true;
277+
if (!nft_set_elem_mark_busy(&rbe->ext) ||
278+
!nft_is_active(net, &rbe->ext)) {
279+
nft_set_elem_change_active(net, set, &rbe->ext);
280+
return true;
281+
}
282+
return false;
277283
}
278284

279285
static void *nft_rbtree_deactivate(const struct net *net,
@@ -347,6 +353,62 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
347353
read_unlock_bh(&priv->lock);
348354
}
349355

356+
static void nft_rbtree_gc(struct work_struct *work)
357+
{
358+
struct nft_set_gc_batch *gcb = NULL;
359+
struct rb_node *node, *prev = NULL;
360+
struct nft_rbtree_elem *rbe;
361+
struct nft_rbtree *priv;
362+
struct nft_set *set;
363+
int i;
364+
365+
priv = container_of(work, struct nft_rbtree, gc_work.work);
366+
set = nft_set_container_of(priv);
367+
368+
write_lock_bh(&priv->lock);
369+
write_seqcount_begin(&priv->count);
370+
for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
371+
rbe = rb_entry(node, struct nft_rbtree_elem, node);
372+
373+
if (nft_rbtree_interval_end(rbe)) {
374+
prev = node;
375+
continue;
376+
}
377+
if (!nft_set_elem_expired(&rbe->ext))
378+
continue;
379+
if (nft_set_elem_mark_busy(&rbe->ext))
380+
continue;
381+
382+
gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC);
383+
if (!gcb)
384+
goto out;
385+
386+
atomic_dec(&set->nelems);
387+
nft_set_gc_batch_add(gcb, rbe);
388+
389+
if (prev) {
390+
rbe = rb_entry(prev, struct nft_rbtree_elem, node);
391+
atomic_dec(&set->nelems);
392+
nft_set_gc_batch_add(gcb, rbe);
393+
}
394+
node = rb_next(node);
395+
}
396+
out:
397+
if (gcb) {
398+
for (i = 0; i < gcb->head.cnt; i++) {
399+
rbe = gcb->elems[i];
400+
rb_erase(&rbe->node, &priv->root);
401+
}
402+
}
403+
write_seqcount_end(&priv->count);
404+
write_unlock_bh(&priv->lock);
405+
406+
nft_set_gc_batch_complete(gcb);
407+
408+
queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
409+
nft_set_gc_interval(set));
410+
}
411+
350412
static unsigned int nft_rbtree_privsize(const struct nlattr * const nla[],
351413
const struct nft_set_desc *desc)
352414
{
@@ -362,6 +424,12 @@ static int nft_rbtree_init(const struct nft_set *set,
362424
rwlock_init(&priv->lock);
363425
seqcount_init(&priv->count);
364426
priv->root = RB_ROOT;
427+
428+
INIT_DEFERRABLE_WORK(&priv->gc_work, nft_rbtree_gc);
429+
if (set->flags & NFT_SET_TIMEOUT)
430+
queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
431+
nft_set_gc_interval(set));
432+
365433
return 0;
366434
}
367435

@@ -371,6 +439,7 @@ static void nft_rbtree_destroy(const struct nft_set *set)
371439
struct nft_rbtree_elem *rbe;
372440
struct rb_node *node;
373441

442+
cancel_delayed_work_sync(&priv->gc_work);
374443
while ((node = priv->root.rb_node) != NULL) {
375444
rb_erase(node, &priv->root);
376445
rbe = rb_entry(node, struct nft_rbtree_elem, node);
@@ -395,7 +464,7 @@ static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features,
395464

396465
static struct nft_set_type nft_rbtree_type __read_mostly = {
397466
.owner = THIS_MODULE,
398-
.features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT,
467+
.features = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT | NFT_SET_TIMEOUT,
399468
.ops = {
400469
.privsize = nft_rbtree_privsize,
401470
.elemsize = offsetof(struct nft_rbtree_elem, ext),

0 commit comments

Comments
 (0)