forked from Minki/linux
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: Liping Zhang <zlpnobody@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
fc09e4a75a
commit
2cb4bbd75b
@ -17,9 +17,8 @@
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
|
||||
static DEFINE_SPINLOCK(limit_lock);
|
||||
|
||||
struct nft_limit {
|
||||
spinlock_t lock;
|
||||
u64 last;
|
||||
u64 tokens;
|
||||
u64 tokens_max;
|
||||
@ -34,7 +33,7 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
|
||||
u64 now, tokens;
|
||||
s64 delta;
|
||||
|
||||
spin_lock_bh(&limit_lock);
|
||||
spin_lock_bh(&limit->lock);
|
||||
now = ktime_get_ns();
|
||||
tokens = limit->tokens + now - limit->last;
|
||||
if (tokens > limit->tokens_max)
|
||||
@ -44,11 +43,11 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
|
||||
delta = tokens - cost;
|
||||
if (delta >= 0) {
|
||||
limit->tokens = delta;
|
||||
spin_unlock_bh(&limit_lock);
|
||||
spin_unlock_bh(&limit->lock);
|
||||
return limit->invert;
|
||||
}
|
||||
limit->tokens = tokens;
|
||||
spin_unlock_bh(&limit_lock);
|
||||
spin_unlock_bh(&limit->lock);
|
||||
return !limit->invert;
|
||||
}
|
||||
|
||||
@ -86,6 +85,7 @@ static int nft_limit_init(struct nft_limit *limit,
|
||||
limit->invert = true;
|
||||
}
|
||||
limit->last = ktime_get_ns();
|
||||
spin_lock_init(&limit->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/netfilter/xt_limit.h>
|
||||
|
||||
struct xt_limit_priv {
|
||||
spinlock_t lock;
|
||||
unsigned long prev;
|
||||
uint32_t credit;
|
||||
};
|
||||
@ -32,8 +33,6 @@ MODULE_ALIAS("ip6t_limit");
|
||||
* 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
|
||||
this algorithm. The `average rate' in jiffies becomes your initial
|
||||
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)
|
||||
struct xt_limit_priv *priv = r->master;
|
||||
unsigned long now = jiffies;
|
||||
|
||||
spin_lock_bh(&limit_lock);
|
||||
spin_lock_bh(&priv->lock);
|
||||
priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY;
|
||||
if (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)
|
||||
if (priv->credit >= r->cost) {
|
||||
/* We're not limited. */
|
||||
priv->credit -= r->cost;
|
||||
spin_unlock_bh(&limit_lock);
|
||||
spin_unlock_bh(&priv->lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&limit_lock);
|
||||
spin_unlock_bh(&priv->lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -126,6 +125,8 @@ static int limit_mt_check(const struct xt_mtchk_param *par)
|
||||
r->credit_cap = priv->credit; /* Credits full. */
|
||||
r->cost = user2credits(r->avg);
|
||||
}
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user