]> granicus.if.org Git - ipset/commitdiff
hash:*net*: nomatch flag not excluded on set resize
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Mon, 1 Apr 2013 19:13:20 +0000 (21:13 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Tue, 9 Apr 2013 19:42:16 +0000 (21:42 +0200)
If a resize is triggered the nomatch flag is not excluded at hashing,
which leads to the element missed at lookup in the resized set.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
kernel/include/linux/netfilter/ipset/ip_set_ahash.h
kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
kernel/net/netfilter/ipset/ip_set_hash_net.c
kernel/net/netfilter/ipset/ip_set_hash_netiface.c
kernel/net/netfilter/ipset/ip_set_hash_netport.c

index 77d8cdb01cd87165bcf6d0c20174dbefc1d641ff..5d3645364b8a7620fc8853be71431a5c0619840b 100644 (file)
@@ -294,6 +294,7 @@ ip_set_hash_destroy(struct ip_set *set)
 #define type_pf_data_tlist     TOKEN(TYPE, PF, _data_tlist)
 #define type_pf_data_next      TOKEN(TYPE, PF, _data_next)
 #define type_pf_data_flags     TOKEN(TYPE, PF, _data_flags)
+#define type_pf_data_reset_flags TOKEN(TYPE, PF, _data_reset_flags)
 #ifdef IP_SET_HASH_WITH_NETS
 #define type_pf_data_match     TOKEN(TYPE, PF, _data_match)
 #else
@@ -388,9 +389,9 @@ type_pf_resize(struct ip_set *set, bool retried)
        struct ip_set_hash *h = set->data;
        struct htable *t, *orig = h->table;
        u8 htable_bits = orig->htable_bits;
-       const struct type_pf_elem *data;
+       struct type_pf_elem *data;
        struct hbucket *n, *m;
-       u32 i, j;
+       u32 i, j, flags = 0;
        int ret;
 
 retry:
@@ -415,9 +416,16 @@ retry:
                n = hbucket(orig, i);
                for (j = 0; j < n->pos; j++) {
                        data = ahash_data(n, j);
+#ifdef IP_SET_HASH_WITH_NETS
+                       flags = 0;
+                       type_pf_data_reset_flags(data, &flags);
+#endif
                        m = hbucket(t, HKEY(data, h->initval, htable_bits));
-                       ret = type_pf_elem_add(m, data, AHASH_MAX(h), 0);
+                       ret = type_pf_elem_add(m, data, AHASH_MAX(h), flags);
                        if (ret < 0) {
+#ifdef IP_SET_HASH_WITH_NETS
+                               type_pf_data_flags(data, flags);
+#endif
                                read_unlock_bh(&set->lock);
                                ahash_destroy(t);
                                if (ret == -EAGAIN)
@@ -839,9 +847,9 @@ type_pf_tresize(struct ip_set *set, bool retried)
        struct ip_set_hash *h = set->data;
        struct htable *t, *orig = h->table;
        u8 htable_bits = orig->htable_bits;
-       const struct type_pf_elem *data;
+       struct type_pf_elem *data;
        struct hbucket *n, *m;
-       u32 i, j;
+       u32 i, j, flags = 0;
        int ret;
 
        /* Try to cleanup once */
@@ -876,10 +884,17 @@ retry:
                n = hbucket(orig, i);
                for (j = 0; j < n->pos; j++) {
                        data = ahash_tdata(n, j);
+#ifdef IP_SET_HASH_WITH_NETS
+                       flags = 0;
+                       type_pf_data_reset_flags(data, &flags);
+#endif
                        m = hbucket(t, HKEY(data, h->initval, htable_bits));
-                       ret = type_pf_elem_tadd(m, data, AHASH_MAX(h), 0,
-                                               ip_set_timeout_get(type_pf_data_timeout(data)));
+                       ret = type_pf_elem_tadd(m, data, AHASH_MAX(h), flags,
+                               ip_set_timeout_get(type_pf_data_timeout(data)));
                        if (ret < 0) {
+#ifdef IP_SET_HASH_WITH_NETS
+                               type_pf_data_flags(data, flags);
+#endif
                                read_unlock_bh(&set->lock);
                                ahash_destroy(t);
                                if (ret == -EAGAIN)
@@ -1190,6 +1205,7 @@ type_pf_gc_init(struct ip_set *set)
 #undef type_pf_data_tlist
 #undef type_pf_data_next
 #undef type_pf_data_flags
+#undef type_pf_data_reset_flags
 #undef type_pf_data_match
 
 #undef type_pf_elem
index 2d5cd4ee30eb4d5872b4aa9be7199a3d8999f6c7..270e7d054e76dfa12c1edbea1d3bcf63f339f4d1 100644 (file)
@@ -104,6 +104,15 @@ hash_ipportnet4_data_flags(struct hash_ipportnet4_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
+static inline void
+hash_ipportnet4_data_reset_flags(struct hash_ipportnet4_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
+}
+
 static inline int
 hash_ipportnet4_data_match(const struct hash_ipportnet4_elem *elem)
 {
@@ -414,6 +423,15 @@ hash_ipportnet6_data_flags(struct hash_ipportnet6_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
+static inline void
+hash_ipportnet6_data_reset_flags(struct hash_ipportnet6_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
+}
+
 static inline int
 hash_ipportnet6_data_match(const struct hash_ipportnet6_elem *elem)
 {
index 29e94b981f3f3fe4853a9683a1cbecdfc9d7ec42..8658d40a8ecb33f3e4533df2f948ddca01da18ee 100644 (file)
@@ -87,7 +87,16 @@ hash_net4_data_copy(struct hash_net4_elem *dst,
 static inline void
 hash_net4_data_flags(struct hash_net4_elem *dst, u32 flags)
 {
-       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
+}
+
+static inline void
+hash_net4_data_reset_flags(struct hash_net4_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
 }
 
 static inline int
@@ -308,7 +317,16 @@ hash_net6_data_copy(struct hash_net6_elem *dst,
 static inline void
 hash_net6_data_flags(struct hash_net6_elem *dst, u32 flags)
 {
-       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
+}
+
+static inline void
+hash_net6_data_reset_flags(struct hash_net6_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
 }
 
 static inline int
index 45a101439bc5dc62798e62b1516b78a9d8096272..10942e6fb460a3c10d81235d8347f127a6014fa4 100644 (file)
@@ -198,7 +198,16 @@ hash_netiface4_data_copy(struct hash_netiface4_elem *dst,
 static inline void
 hash_netiface4_data_flags(struct hash_netiface4_elem *dst, u32 flags)
 {
-       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
+}
+
+static inline void
+hash_netiface4_data_reset_flags(struct hash_netiface4_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
 }
 
 static inline int
@@ -494,7 +503,7 @@ hash_netiface6_data_copy(struct hash_netiface6_elem *dst,
 static inline void
 hash_netiface6_data_flags(struct hash_netiface6_elem *dst, u32 flags)
 {
-       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
 static inline int
@@ -503,6 +512,15 @@ hash_netiface6_data_match(const struct hash_netiface6_elem *elem)
        return elem->nomatch ? -ENOTEMPTY : 1;
 }
 
+static inline void
+hash_netiface6_data_reset_flags(struct hash_netiface6_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
+}
+
 static inline void
 hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem)
 {
index 7ef700de596c54d09f8873a4498da207bfd5a828..e5d942aebe94667e0cc8c69a3d4499808b1b1bd4 100644 (file)
@@ -104,6 +104,15 @@ hash_netport4_data_flags(struct hash_netport4_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
+static inline void
+hash_netport4_data_reset_flags(struct hash_netport4_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
+}
+
 static inline int
 hash_netport4_data_match(const struct hash_netport4_elem *elem)
 {
@@ -375,6 +384,15 @@ hash_netport6_data_flags(struct hash_netport6_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
+static inline void
+hash_netport6_data_reset_flags(struct hash_netport6_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
+}
+
 static inline int
 hash_netport6_data_match(const struct hash_netport6_elem *elem)
 {