This patch provides an interface to maintain the list of connections and the lookup function to obtain the number of connections in the list. Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- v2: pass cache name to nf_conncount_cache_alloc() as parameter. include/net/netfilter/nf_conntrack_count.h | 15 +++++++ net/netfilter/nf_conncount.c | 68 +++++++++++++++++++++--------- 2 files changed, 63 insertions(+), 20 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_count.h b/include/net/netfilter/nf_conntrack_count.h index e61184fbfb71..4b4fc9f986a2 100644 --- a/include/net/netfilter/nf_conntrack_count.h +++ b/include/net/netfilter/nf_conntrack_count.h @@ -13,4 +13,19 @@ unsigned int nf_conncount_count(struct net *net, const u32 *key, const struct nf_conntrack_tuple *tuple, const struct nf_conntrack_zone *zone); + +struct kmem_cache; + +struct kmem_cache *nf_conncount_cache_alloc(const char *cache_name); +void nf_conncount_cache_free(struct kmem_cache *cache, struct hlist_head *hhead); + +unsigned int nf_conncount_lookup(struct net *net, struct kmem_cache *cache, + struct hlist_head *head, + const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_zone *zone, + bool *addit); + +bool nf_conncount_add(struct kmem_cache *cache, struct hlist_head *head, + const struct nf_conntrack_tuple *tuple); + #endif diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c index 153e690e2893..f1584d403950 100644 --- a/net/netfilter/nf_conncount.c +++ b/net/netfilter/nf_conncount.c @@ -79,24 +79,27 @@ static int key_diff(const u32 *a, const u32 *b, unsigned int klen) return memcmp(a, b, klen * sizeof(u32)); } -static bool add_hlist(struct hlist_head *head, +bool nf_conncount_add(struct kmem_cache *conncount_cache, + struct hlist_head *head, const struct nf_conntrack_tuple *tuple) { struct nf_conncount_tuple *conn; - conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC); + conn = kmem_cache_alloc(conncount_cache, GFP_ATOMIC); if (conn == NULL) return false; conn->tuple = *tuple; hlist_add_head(&conn->node, head); return true; } - -static unsigned int check_hlist(struct net *net, - struct hlist_head *head, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_zone *zone, - bool *addit) +EXPORT_SYMBOL_GPL(nf_conncount_add); + +unsigned int nf_conncount_lookup(struct net *net, + struct kmem_cache *conncount_cache, + struct hlist_head *head, + const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_zone *zone, + bool *addit) { const struct nf_conntrack_tuple_hash *found; struct nf_conncount_tuple *conn; @@ -131,7 +134,7 @@ static unsigned int check_hlist(struct net *net, */ nf_ct_put(found_ct); hlist_del(&conn->node); - kmem_cache_free(conncount_conn_cachep, conn); + kmem_cache_free(conncount_cache, conn); continue; } @@ -141,6 +144,7 @@ static unsigned int check_hlist(struct net *net, return length; } +EXPORT_SYMBOL_GPL(nf_conncount_lookup); static void tree_nodes_free(struct rb_root *root, struct nf_conncount_rb *gc_nodes[], @@ -187,13 +191,17 @@ count_tree(struct net *net, struct rb_root *root, } else { /* same source network -> be counted! */ unsigned int count; - count = check_hlist(net, &rbconn->hhead, tuple, zone, &addit); + + count = nf_conncount_lookup(net, conncount_conn_cachep, + &rbconn->hhead, tuple, + zone, &addit); tree_nodes_free(root, gc_nodes, gc_count); if (!addit) return count; - if (!add_hlist(&rbconn->hhead, tuple)) + if (!nf_conncount_add(conncount_conn_cachep, + &rbconn->hhead, tuple)) return 0; /* hotdrop */ return count + 1; @@ -203,7 +211,8 @@ count_tree(struct net *net, struct rb_root *root, continue; /* only used for GC on hhead, retval and 'addit' ignored */ - check_hlist(net, &rbconn->hhead, tuple, zone, &addit); + nf_conncount_lookup(net, conncount_conn_cachep, &rbconn->hhead, + tuple, zone, &addit); if (hlist_empty(&rbconn->hhead)) gc_nodes[gc_count++] = rbconn; } @@ -303,11 +312,19 @@ struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family } EXPORT_SYMBOL_GPL(nf_conncount_init); -static void destroy_tree(struct rb_root *r) +void nf_conncount_cache_free(struct kmem_cache *cache, struct hlist_head *hhead) { struct nf_conncount_tuple *conn; - struct nf_conncount_rb *rbconn; struct hlist_node *n; + + hlist_for_each_entry_safe(conn, n, hhead, node) + kmem_cache_free(conncount_conn_cachep, conn); +} +EXPORT_SYMBOL_GPL(nf_conncount_cache_free); + +static void destroy_tree(struct rb_root *r) +{ + struct nf_conncount_rb *rbconn; struct rb_node *node; while ((node = rb_first(r)) != NULL) { @@ -315,8 +332,7 @@ static void destroy_tree(struct rb_root *r) rb_erase(node, r); - hlist_for_each_entry_safe(conn, n, &rbconn->hhead, node) - kmem_cache_free(conncount_conn_cachep, conn); + nf_conncount_cache_free(conncount_conn_cachep, &rbconn->hhead); kmem_cache_free(conncount_rb_cachep, rbconn); } @@ -336,6 +352,20 @@ void nf_conncount_destroy(struct net *net, unsigned int family, } EXPORT_SYMBOL_GPL(nf_conncount_destroy); +struct kmem_cache *nf_conncount_cache_alloc(const char *cache_name) +{ + struct kmem_cache *conncount_cache; + + conncount_cache = kmem_cache_create(cache_name, + sizeof(struct nf_conncount_tuple), + 0, 0, NULL); + if (!conncount_cache) + return ERR_PTR(-ENOMEM); + + return conncount_cache; +} +EXPORT_SYMBOL_GPL(nf_conncount_cache_alloc); + static int __init nf_conncount_modinit(void) { int i; @@ -346,10 +376,8 @@ static int __init nf_conncount_modinit(void) for (i = 0; i < CONNCOUNT_LOCK_SLOTS; ++i) spin_lock_init(&nf_conncount_locks[i]); - conncount_conn_cachep = kmem_cache_create("nf_conncount_tuple", - sizeof(struct nf_conncount_tuple), - 0, 0, NULL); - if (!conncount_conn_cachep) + conncount_conn_cachep = nf_conncount_cache_alloc("nf_conncount_tuple"); + if (IS_ERR(conncount_conn_cachep)) return -ENOMEM; conncount_rb_cachep = kmem_cache_create("nf_conncount_rb", -- 2.11.0 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html