Skip to content

Commit cfed7e1

Browse files
kaberummakynes
authored andcommitted
netfilter: nf_tables: add set garbage collection helpers
Add helpers for GC batch destruction: since element destruction needs a RCU grace period for all set implementations, add some helper functions for asynchronous batch destruction. Elements are collected in a batch structure, which is asynchronously released using RCU once its full. Signed-off-by: Patrick McHardy <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent c3e1b00 commit cfed7e1

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,62 @@ static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
459459

460460
void nft_set_elem_destroy(const struct nft_set *set, void *elem);
461461

462+
/**
463+
* struct nft_set_gc_batch_head - nf_tables set garbage collection batch
464+
*
465+
* @rcu: rcu head
466+
* @set: set the elements belong to
467+
* @cnt: count of elements
468+
*/
469+
struct nft_set_gc_batch_head {
470+
struct rcu_head rcu;
471+
const struct nft_set *set;
472+
unsigned int cnt;
473+
};
474+
475+
#define NFT_SET_GC_BATCH_SIZE ((PAGE_SIZE - \
476+
sizeof(struct nft_set_gc_batch_head)) / \
477+
sizeof(void *))
478+
479+
/**
480+
* struct nft_set_gc_batch - nf_tables set garbage collection batch
481+
*
482+
* @head: GC batch head
483+
* @elems: garbage collection elements
484+
*/
485+
struct nft_set_gc_batch {
486+
struct nft_set_gc_batch_head head;
487+
void *elems[NFT_SET_GC_BATCH_SIZE];
488+
};
489+
490+
struct nft_set_gc_batch *nft_set_gc_batch_alloc(const struct nft_set *set,
491+
gfp_t gfp);
492+
void nft_set_gc_batch_release(struct rcu_head *rcu);
493+
494+
static inline void nft_set_gc_batch_complete(struct nft_set_gc_batch *gcb)
495+
{
496+
if (gcb != NULL)
497+
call_rcu(&gcb->head.rcu, nft_set_gc_batch_release);
498+
}
499+
500+
static inline struct nft_set_gc_batch *
501+
nft_set_gc_batch_check(const struct nft_set *set, struct nft_set_gc_batch *gcb,
502+
gfp_t gfp)
503+
{
504+
if (gcb != NULL) {
505+
if (gcb->head.cnt + 1 < ARRAY_SIZE(gcb->elems))
506+
return gcb;
507+
nft_set_gc_batch_complete(gcb);
508+
}
509+
return nft_set_gc_batch_alloc(set, gfp);
510+
}
511+
512+
static inline void nft_set_gc_batch_add(struct nft_set_gc_batch *gcb,
513+
void *elem)
514+
{
515+
gcb->elems[gcb->head.cnt++] = elem;
516+
}
517+
462518
/**
463519
* struct nft_expr_type - nf_tables expression type
464520
*

net/netfilter/nf_tables_api.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3482,6 +3482,31 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
34823482
return err;
34833483
}
34843484

3485+
void nft_set_gc_batch_release(struct rcu_head *rcu)
3486+
{
3487+
struct nft_set_gc_batch *gcb;
3488+
unsigned int i;
3489+
3490+
gcb = container_of(rcu, struct nft_set_gc_batch, head.rcu);
3491+
for (i = 0; i < gcb->head.cnt; i++)
3492+
nft_set_elem_destroy(gcb->head.set, gcb->elems[i]);
3493+
kfree(gcb);
3494+
}
3495+
EXPORT_SYMBOL_GPL(nft_set_gc_batch_release);
3496+
3497+
struct nft_set_gc_batch *nft_set_gc_batch_alloc(const struct nft_set *set,
3498+
gfp_t gfp)
3499+
{
3500+
struct nft_set_gc_batch *gcb;
3501+
3502+
gcb = kzalloc(sizeof(*gcb), gfp);
3503+
if (gcb == NULL)
3504+
return gcb;
3505+
gcb->head.set = set;
3506+
return gcb;
3507+
}
3508+
EXPORT_SYMBOL_GPL(nft_set_gc_batch_alloc);
3509+
34853510
static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
34863511
u32 portid, u32 seq)
34873512
{

0 commit comments

Comments
 (0)