Skip to content

Commit

Permalink
netfilter: limit: use per-rule spinlock to improve the scalability
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Liping Zhang authored and Pablo Neira Ayuso committed Mar 13, 2017
1 parent fc09e4a commit 2cb4bbd
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 10 deletions.
10 changes: 5 additions & 5 deletions net/netfilter/nft_limit.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand Down
11 changes: 6 additions & 5 deletions net/netfilter/xt_limit.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/netfilter/xt_limit.h>

struct xt_limit_priv {
spinlock_t lock;
unsigned long prev;
uint32_t credit;
};
Expand All @@ -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
Expand Down Expand Up @@ -72,19 +71,19 @@ 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;

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;
}

Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 2cb4bbd

Please sign in to comment.