Commit 5c789e13 authored by Yi-Hung Wei's avatar Yi-Hung Wei Committed by Pablo Neira Ayuso

netfilter: nf_conncount: Add list lock and gc worker, and RCU for init tree search

This patch is originally from Florian Westphal.

This patch does the following 3 main tasks.

1) Add list lock to 'struct nf_conncount_list' so that we can
alter the lists containing the individual connections without holding the
main tree lock.  It would be useful when we only need to add/remove to/from
a list without allocate/remove a node in the tree.  With this change, we
update nft_connlimit accordingly since we longer need to maintain
a list lock in nft_connlimit now.

2) Use RCU for the initial tree search to improve tree look up performance.

3) Add a garbage collection worker. This worker is schedule when there
are excessive tree node that needed to be recycled.

Moreover,the rbnode reclaim logic is moved from search tree to insert tree
to avoid race condition.
Signed-off-by: default avatarYi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 34848d5c
...@@ -5,9 +5,17 @@ ...@@ -5,9 +5,17 @@
struct nf_conncount_data; struct nf_conncount_data;
enum nf_conncount_list_add {
NF_CONNCOUNT_ADDED, /* list add was ok */
NF_CONNCOUNT_ERR, /* -ENOMEM, must drop skb */
NF_CONNCOUNT_SKIP, /* list is already reclaimed by gc */
};
struct nf_conncount_list { struct nf_conncount_list {
spinlock_t list_lock;
struct list_head head; /* connections with the same filtering key */ struct list_head head; /* connections with the same filtering key */
unsigned int count; /* length of list */ unsigned int count; /* length of list */
bool dead;
}; };
struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family, struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family,
...@@ -28,11 +36,12 @@ void nf_conncount_lookup(struct net *net, struct nf_conncount_list *list, ...@@ -28,11 +36,12 @@ void nf_conncount_lookup(struct net *net, struct nf_conncount_list *list,
void nf_conncount_list_init(struct nf_conncount_list *list); void nf_conncount_list_init(struct nf_conncount_list *list);
bool nf_conncount_add(struct nf_conncount_list *list, enum nf_conncount_list_add
const struct nf_conntrack_tuple *tuple, nf_conncount_add(struct nf_conncount_list *list,
const struct nf_conntrack_zone *zone); const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_zone *zone);
void nf_conncount_gc_list(struct net *net, bool nf_conncount_gc_list(struct net *net,
struct nf_conncount_list *list); struct nf_conncount_list *list);
void nf_conncount_cache_free(struct nf_conncount_list *list); void nf_conncount_cache_free(struct nf_conncount_list *list);
......
This diff is collapsed.
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <net/netfilter/nf_conntrack_zones.h> #include <net/netfilter/nf_conntrack_zones.h>
struct nft_connlimit { struct nft_connlimit {
spinlock_t lock;
struct nf_conncount_list list; struct nf_conncount_list list;
u32 limit; u32 limit;
bool invert; bool invert;
...@@ -45,7 +44,6 @@ static inline void nft_connlimit_do_eval(struct nft_connlimit *priv, ...@@ -45,7 +44,6 @@ static inline void nft_connlimit_do_eval(struct nft_connlimit *priv,
return; return;
} }
spin_lock_bh(&priv->lock);
nf_conncount_lookup(nft_net(pkt), &priv->list, tuple_ptr, zone, nf_conncount_lookup(nft_net(pkt), &priv->list, tuple_ptr, zone,
&addit); &addit);
count = priv->list.count; count = priv->list.count;
...@@ -53,14 +51,12 @@ static inline void nft_connlimit_do_eval(struct nft_connlimit *priv, ...@@ -53,14 +51,12 @@ static inline void nft_connlimit_do_eval(struct nft_connlimit *priv,
if (!addit) if (!addit)
goto out; goto out;
if (!nf_conncount_add(&priv->list, tuple_ptr, zone)) { if (nf_conncount_add(&priv->list, tuple_ptr, zone) == NF_CONNCOUNT_ERR) {
regs->verdict.code = NF_DROP; regs->verdict.code = NF_DROP;
spin_unlock_bh(&priv->lock);
return; return;
} }
count++; count++;
out: out:
spin_unlock_bh(&priv->lock);
if ((count > priv->limit) ^ priv->invert) { if ((count > priv->limit) ^ priv->invert) {
regs->verdict.code = NFT_BREAK; regs->verdict.code = NFT_BREAK;
...@@ -88,7 +84,6 @@ static int nft_connlimit_do_init(const struct nft_ctx *ctx, ...@@ -88,7 +84,6 @@ static int nft_connlimit_do_init(const struct nft_ctx *ctx,
invert = true; invert = true;
} }
spin_lock_init(&priv->lock);
nf_conncount_list_init(&priv->list); nf_conncount_list_init(&priv->list);
priv->limit = limit; priv->limit = limit;
priv->invert = invert; priv->invert = invert;
...@@ -213,7 +208,6 @@ static int nft_connlimit_clone(struct nft_expr *dst, const struct nft_expr *src) ...@@ -213,7 +208,6 @@ static int nft_connlimit_clone(struct nft_expr *dst, const struct nft_expr *src)
struct nft_connlimit *priv_dst = nft_expr_priv(dst); struct nft_connlimit *priv_dst = nft_expr_priv(dst);
struct nft_connlimit *priv_src = nft_expr_priv(src); struct nft_connlimit *priv_src = nft_expr_priv(src);
spin_lock_init(&priv_dst->lock);
nf_conncount_list_init(&priv_dst->list); nf_conncount_list_init(&priv_dst->list);
priv_dst->limit = priv_src->limit; priv_dst->limit = priv_src->limit;
priv_dst->invert = priv_src->invert; priv_dst->invert = priv_src->invert;
...@@ -232,15 +226,8 @@ static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx, ...@@ -232,15 +226,8 @@ static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx,
static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr) static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr)
{ {
struct nft_connlimit *priv = nft_expr_priv(expr); struct nft_connlimit *priv = nft_expr_priv(expr);
bool ret;
spin_lock_bh(&priv->lock); return nf_conncount_gc_list(net, &priv->list);
nf_conncount_gc_list(net, &priv->list);
ret = list_empty(&priv->list.head);
spin_unlock_bh(&priv->lock);
return ret;
} }
static struct nft_expr_type nft_connlimit_type; static struct nft_expr_type nft_connlimit_type;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment