aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/xt_hashlimit.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 26a668a84aa2..cc430f926a85 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -157,11 +157,22 @@ dsthash_find(const struct xt_hashlimit_htable *ht,
157/* allocate dsthash_ent, initialize dst, put in htable and lock it */ 157/* allocate dsthash_ent, initialize dst, put in htable and lock it */
158static struct dsthash_ent * 158static struct dsthash_ent *
159dsthash_alloc_init(struct xt_hashlimit_htable *ht, 159dsthash_alloc_init(struct xt_hashlimit_htable *ht,
160 const struct dsthash_dst *dst) 160 const struct dsthash_dst *dst, bool *race)
161{ 161{
162 struct dsthash_ent *ent; 162 struct dsthash_ent *ent;
163 163
164 spin_lock(&ht->lock); 164 spin_lock(&ht->lock);
165
166 /* Two or more packets may race to create the same entry in the
167 * hashtable, double check if this packet lost race.
168 */
169 ent = dsthash_find(ht, dst);
170 if (ent != NULL) {
171 spin_unlock(&ht->lock);
172 *race = true;
173 return ent;
174 }
175
165 /* initialize hash with random val at the time we allocate 176 /* initialize hash with random val at the time we allocate
166 * the first hashtable entry */ 177 * the first hashtable entry */
167 if (unlikely(!ht->rnd_initialized)) { 178 if (unlikely(!ht->rnd_initialized)) {
@@ -585,6 +596,7 @@ hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
585 unsigned long now = jiffies; 596 unsigned long now = jiffies;
586 struct dsthash_ent *dh; 597 struct dsthash_ent *dh;
587 struct dsthash_dst dst; 598 struct dsthash_dst dst;
599 bool race = false;
588 u32 cost; 600 u32 cost;
589 601
590 if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0) 602 if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0)
@@ -593,13 +605,18 @@ hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
593 rcu_read_lock_bh(); 605 rcu_read_lock_bh();
594 dh = dsthash_find(hinfo, &dst); 606 dh = dsthash_find(hinfo, &dst);
595 if (dh == NULL) { 607 if (dh == NULL) {
596 dh = dsthash_alloc_init(hinfo, &dst); 608 dh = dsthash_alloc_init(hinfo, &dst, &race);
597 if (dh == NULL) { 609 if (dh == NULL) {
598 rcu_read_unlock_bh(); 610 rcu_read_unlock_bh();
599 goto hotdrop; 611 goto hotdrop;
612 } else if (race) {
613 /* Already got an entry, update expiration timeout */
614 dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
615 rateinfo_recalc(dh, now, hinfo->cfg.mode);
616 } else {
617 dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
618 rateinfo_init(dh, hinfo);
600 } 619 }
601 dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
602 rateinfo_init(dh, hinfo);
603 } else { 620 } else {
604 /* update expiration timeout */ 621 /* update expiration timeout */
605 dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); 622 dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);