Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os 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>

authored by

Liping Zhang and committed by
Pablo Neira Ayuso
2cb4bbd7 fc09e4a7

+11 -10
+5 -5
net/netfilter/nft_limit.c
··· 17 17 #include <linux/netfilter/nf_tables.h> 18 18 #include <net/netfilter/nf_tables.h> 19 19 20 - static DEFINE_SPINLOCK(limit_lock); 21 - 22 20 struct nft_limit { 21 + spinlock_t lock; 23 22 u64 last; 24 23 u64 tokens; 25 24 u64 tokens_max; ··· 33 34 u64 now, tokens; 34 35 s64 delta; 35 36 36 - spin_lock_bh(&limit_lock); 37 + spin_lock_bh(&limit->lock); 37 38 now = ktime_get_ns(); 38 39 tokens = limit->tokens + now - limit->last; 39 40 if (tokens > limit->tokens_max) ··· 43 44 delta = tokens - cost; 44 45 if (delta >= 0) { 45 46 limit->tokens = delta; 46 - spin_unlock_bh(&limit_lock); 47 + spin_unlock_bh(&limit->lock); 47 48 return limit->invert; 48 49 } 49 50 limit->tokens = tokens; 50 - spin_unlock_bh(&limit_lock); 51 + spin_unlock_bh(&limit->lock); 51 52 return !limit->invert; 52 53 } 53 54 ··· 85 86 limit->invert = true; 86 87 } 87 88 limit->last = ktime_get_ns(); 89 + spin_lock_init(&limit->lock); 88 90 89 91 return 0; 90 92 }
+6 -5
net/netfilter/xt_limit.c
··· 18 18 #include <linux/netfilter/xt_limit.h> 19 19 20 20 struct xt_limit_priv { 21 + spinlock_t lock; 21 22 unsigned long prev; 22 23 uint32_t credit; 23 24 }; ··· 32 31 /* The algorithm used is the Simple Token Bucket Filter (TBF) 33 32 * see net/sched/sch_tbf.c in the linux source tree 34 33 */ 35 - 36 - static DEFINE_SPINLOCK(limit_lock); 37 34 38 35 /* Rusty: This is my (non-mathematically-inclined) understanding of 39 36 this algorithm. The `average rate' in jiffies becomes your initial ··· 71 72 struct xt_limit_priv *priv = r->master; 72 73 unsigned long now = jiffies; 73 74 74 - spin_lock_bh(&limit_lock); 75 + spin_lock_bh(&priv->lock); 75 76 priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY; 76 77 if (priv->credit > r->credit_cap) 77 78 priv->credit = r->credit_cap; ··· 79 80 if (priv->credit >= r->cost) { 80 81 /* We're not limited. */ 81 82 priv->credit -= r->cost; 82 - spin_unlock_bh(&limit_lock); 83 + spin_unlock_bh(&priv->lock); 83 84 return true; 84 85 } 85 86 86 - spin_unlock_bh(&limit_lock); 87 + spin_unlock_bh(&priv->lock); 87 88 return false; 88 89 } 89 90 ··· 125 126 r->credit_cap = priv->credit; /* Credits full. */ 126 127 r->cost = user2credits(r->avg); 127 128 } 129 + spin_lock_init(&priv->lock); 130 + 128 131 return 0; 129 132 } 130 133