netfilter: ipset: Support updating extensions when the set is full
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Sun, 30 Nov 2014 18:56:52 +0000 (19:56 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 3 Dec 2014 11:43:34 +0000 (12:43 +0100)
When the set was full (hash type and maxelem reached), it was not
possible to update the extension part of already existing elements.
The patch removes this limitation.

Fixes: https://bugzilla.netfilter.org/show_bug.cgi?id=880
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/ipset/ip_set_hash_gen.h

index fee7c64e4dd183e5e2fa9d312bbd5cf3134f59f8..a12ee045258b0b035d5f0d5f3d148a93a0934c7f 100644 (file)
@@ -633,29 +633,6 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        bool flag_exist = flags & IPSET_FLAG_EXIST;
        u32 key, multi = 0;
 
-       if (h->elements >= h->maxelem && SET_WITH_FORCEADD(set)) {
-               rcu_read_lock_bh();
-               t = rcu_dereference_bh(h->table);
-               key = HKEY(value, h->initval, t->htable_bits);
-               n = hbucket(t,key);
-               if (n->pos) {
-                       /* Choosing the first entry in the array to replace */
-                       j = 0;
-                       goto reuse_slot;
-               }
-               rcu_read_unlock_bh();
-       }
-       if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem)
-               /* FIXME: when set is full, we slow down here */
-               mtype_expire(set, h, NLEN(set->family), set->dsize);
-
-       if (h->elements >= h->maxelem) {
-               if (net_ratelimit())
-                       pr_warn("Set %s is full, maxelem %u reached\n",
-                               set->name, h->maxelem);
-               return -IPSET_ERR_HASH_FULL;
-       }
-
        rcu_read_lock_bh();
        t = rcu_dereference_bh(h->table);
        key = HKEY(value, h->initval, t->htable_bits);
@@ -680,6 +657,23 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                    j != AHASH_MAX(h) + 1)
                        j = i;
        }
+       if (h->elements >= h->maxelem && SET_WITH_FORCEADD(set) && n->pos) {
+               /* Choosing the first entry in the array to replace */
+               j = 0;
+               goto reuse_slot;
+       }
+       if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem)
+               /* FIXME: when set is full, we slow down here */
+               mtype_expire(set, h, NLEN(set->family), set->dsize);
+
+       if (h->elements >= h->maxelem) {
+               if (net_ratelimit())
+                       pr_warn("Set %s is full, maxelem %u reached\n",
+                               set->name, h->maxelem);
+               ret = -IPSET_ERR_HASH_FULL;
+               goto out;
+       }
+
 reuse_slot:
        if (j != AHASH_MAX(h) + 1) {
                /* Fill out reused slot */