Commit 2cb4bbd7 authored by Liping Zhang's avatar Liping Zhang Committed by Pablo Neira Ayuso

netfilter: limit: use per-rule spinlock to improve the scalability

The limit token is independent between each rules, so there's no
need to use a global spinlock.
Signed-off-by: default avatarLiping Zhang <zlpnobody@gmail.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent fc09e4a7
...@@ -17,9 +17,8 @@ ...@@ -17,9 +17,8 @@
#include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h>
static DEFINE_SPINLOCK(limit_lock);
struct nft_limit { struct nft_limit {
spinlock_t lock;
u64 last; u64 last;
u64 tokens; u64 tokens;
u64 tokens_max; u64 tokens_max;
...@@ -34,7 +33,7 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost) ...@@ -34,7 +33,7 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
u64 now, tokens; u64 now, tokens;
s64 delta; s64 delta;
spin_lock_bh(&limit_lock); spin_lock_bh(&limit->lock);
now = ktime_get_ns(); now = ktime_get_ns();
tokens = limit->tokens + now - limit->last; tokens = limit->tokens + now - limit->last;
if (tokens > limit->tokens_max) if (tokens > limit->tokens_max)
...@@ -44,11 +43,11 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost) ...@@ -44,11 +43,11 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
delta = tokens - cost; delta = tokens - cost;
if (delta >= 0) { if (delta >= 0) {
limit->tokens = delta; limit->tokens = delta;
spin_unlock_bh(&limit_lock); spin_unlock_bh(&limit->lock);
return limit->invert; return limit->invert;
} }
limit->tokens = tokens; limit->tokens = tokens;
spin_unlock_bh(&limit_lock); spin_unlock_bh(&limit->lock);
return !limit->invert; return !limit->invert;
} }
...@@ -86,6 +85,7 @@ static int nft_limit_init(struct nft_limit *limit, ...@@ -86,6 +85,7 @@ static int nft_limit_init(struct nft_limit *limit,
limit->invert = true; limit->invert = true;
} }
limit->last = ktime_get_ns(); limit->last = ktime_get_ns();
spin_lock_init(&limit->lock);
return 0; return 0;
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/netfilter/xt_limit.h> #include <linux/netfilter/xt_limit.h>
struct xt_limit_priv { struct xt_limit_priv {
spinlock_t lock;
unsigned long prev; unsigned long prev;
uint32_t credit; uint32_t credit;
}; };
...@@ -32,8 +33,6 @@ MODULE_ALIAS("ip6t_limit"); ...@@ -32,8 +33,6 @@ MODULE_ALIAS("ip6t_limit");
* see net/sched/sch_tbf.c in the linux source tree * see net/sched/sch_tbf.c in the linux source tree
*/ */
static DEFINE_SPINLOCK(limit_lock);
/* Rusty: This is my (non-mathematically-inclined) understanding of /* Rusty: This is my (non-mathematically-inclined) understanding of
this algorithm. The `average rate' in jiffies becomes your initial this algorithm. The `average rate' in jiffies becomes your initial
amount of credit `credit' and the most credit you can ever have amount of credit `credit' and the most credit you can ever have
...@@ -72,7 +71,7 @@ limit_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -72,7 +71,7 @@ limit_mt(const struct sk_buff *skb, struct xt_action_param *par)
struct xt_limit_priv *priv = r->master; struct xt_limit_priv *priv = r->master;
unsigned long now = jiffies; unsigned long now = jiffies;
spin_lock_bh(&limit_lock); spin_lock_bh(&priv->lock);
priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY; priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY;
if (priv->credit > r->credit_cap) if (priv->credit > r->credit_cap)
priv->credit = r->credit_cap; priv->credit = r->credit_cap;
...@@ -80,11 +79,11 @@ limit_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -80,11 +79,11 @@ limit_mt(const struct sk_buff *skb, struct xt_action_param *par)
if (priv->credit >= r->cost) { if (priv->credit >= r->cost) {
/* We're not limited. */ /* We're not limited. */
priv->credit -= r->cost; priv->credit -= r->cost;
spin_unlock_bh(&limit_lock); spin_unlock_bh(&priv->lock);
return true; return true;
} }
spin_unlock_bh(&limit_lock); spin_unlock_bh(&priv->lock);
return false; return false;
} }
...@@ -126,6 +125,8 @@ static int limit_mt_check(const struct xt_mtchk_param *par) ...@@ -126,6 +125,8 @@ static int limit_mt_check(const struct xt_mtchk_param *par)
r->credit_cap = priv->credit; /* Credits full. */ r->credit_cap = priv->credit; /* Credits full. */
r->cost = user2credits(r->avg); r->cost = user2credits(r->avg);
} }
spin_lock_init(&priv->lock);
return 0; return 0;
} }
......
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