netfilter: nf_tables: add set garbage collection helpers
authorPatrick McHardy <kaber@trash.net>
Thu, 26 Mar 2015 12:39:38 +0000 (12:39 +0000)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 1 Apr 2015 09:17:29 +0000 (11:17 +0200)
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 <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nf_tables.h
net/netfilter/nf_tables_api.c

index f2726c537248dafb290fcfc32044eb2954103d67..6fd44959bf870143f74fea9d492191027f8d7773 100644 (file)
@@ -459,6 +459,62 @@ static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
 
 void nft_set_elem_destroy(const struct nft_set *set, void *elem);
 
+/**
+ *     struct nft_set_gc_batch_head - nf_tables set garbage collection batch
+ *
+ *     @rcu: rcu head
+ *     @set: set the elements belong to
+ *     @cnt: count of elements
+ */
+struct nft_set_gc_batch_head {
+       struct rcu_head                 rcu;
+       const struct nft_set            *set;
+       unsigned int                    cnt;
+};
+
+#define NFT_SET_GC_BATCH_SIZE  ((PAGE_SIZE -                             \
+                                 sizeof(struct nft_set_gc_batch_head)) / \
+                                sizeof(void *))
+
+/**
+ *     struct nft_set_gc_batch - nf_tables set garbage collection batch
+ *
+ *     @head: GC batch head
+ *     @elems: garbage collection elements
+ */
+struct nft_set_gc_batch {
+       struct nft_set_gc_batch_head    head;
+       void                            *elems[NFT_SET_GC_BATCH_SIZE];
+};
+
+struct nft_set_gc_batch *nft_set_gc_batch_alloc(const struct nft_set *set,
+                                               gfp_t gfp);
+void nft_set_gc_batch_release(struct rcu_head *rcu);
+
+static inline void nft_set_gc_batch_complete(struct nft_set_gc_batch *gcb)
+{
+       if (gcb != NULL)
+               call_rcu(&gcb->head.rcu, nft_set_gc_batch_release);
+}
+
+static inline struct nft_set_gc_batch *
+nft_set_gc_batch_check(const struct nft_set *set, struct nft_set_gc_batch *gcb,
+                      gfp_t gfp)
+{
+       if (gcb != NULL) {
+               if (gcb->head.cnt + 1 < ARRAY_SIZE(gcb->elems))
+                       return gcb;
+               nft_set_gc_batch_complete(gcb);
+       }
+       return nft_set_gc_batch_alloc(set, gfp);
+}
+
+static inline void nft_set_gc_batch_add(struct nft_set_gc_batch *gcb,
+                                       void *elem)
+{
+       gcb->elems[gcb->head.cnt++] = elem;
+}
+
 /**
  *     struct nft_expr_type - nf_tables expression type
  *
index 9e032dbc149cea990cd19c3b685cb363ff1860ae..138e47fddab773ee994584c2076f9e0932b1f2cc 100644 (file)
@@ -3482,6 +3482,31 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
        return err;
 }
 
+void nft_set_gc_batch_release(struct rcu_head *rcu)
+{
+       struct nft_set_gc_batch *gcb;
+       unsigned int i;
+
+       gcb = container_of(rcu, struct nft_set_gc_batch, head.rcu);
+       for (i = 0; i < gcb->head.cnt; i++)
+               nft_set_elem_destroy(gcb->head.set, gcb->elems[i]);
+       kfree(gcb);
+}
+EXPORT_SYMBOL_GPL(nft_set_gc_batch_release);
+
+struct nft_set_gc_batch *nft_set_gc_batch_alloc(const struct nft_set *set,
+                                               gfp_t gfp)
+{
+       struct nft_set_gc_batch *gcb;
+
+       gcb = kzalloc(sizeof(*gcb), gfp);
+       if (gcb == NULL)
+               return gcb;
+       gcb->head.set = set;
+       return gcb;
+}
+EXPORT_SYMBOL_GPL(nft_set_gc_batch_alloc);
+
 static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
                                   u32 portid, u32 seq)
 {