]> granicus.if.org Git - ipset/commitdiff
Listing for hash types fixed
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Fri, 29 Oct 2010 20:21:01 +0000 (22:21 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Fri, 29 Oct 2010 20:21:01 +0000 (22:21 +0200)
The listing was incorrect for large sets, when multiple messages were
required. I assume that one full hash bucket fills into one message,
but that is true for all current hash types.

kernel/include/linux/netfilter/ip_set_chash.h

index 6fd1d32f79dd1d2cadce4a9b194b11d7873ca6b2..9a1e26ca5202c7958d6a40e2b9cf2b96e685b12a 100644 (file)
@@ -567,6 +567,8 @@ type_pf_list(struct ip_set *set,
        struct slist *n;
        const struct type_pf_elem *data;
        u32 first = cb->args[2];
+       /* We assume that one hash bucket fills into one page */
+       void *incomplete;
        int i;
 
        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
@@ -574,6 +576,7 @@ type_pf_list(struct ip_set *set,
                return -EFAULT;
        pr_debug("list hash set %s", set->name);
        for (; cb->args[2] < jhash_size(h->htable_bits); cb->args[2]++) {
+               incomplete = skb_tail_pointer(skb);
                slist_for_each(n, &h->htable[cb->args[2]]) {
                        for (i = 0; i < h->array_size; i++) {
                                data = chash_data(n, i);
@@ -602,8 +605,13 @@ type_pf_list(struct ip_set *set,
        return 0;
 
 nla_put_failure:
-       nla_nest_cancel(skb, nested);
+       nlmsg_trim(skb, incomplete);
        ipset_nest_end(skb, atd);
+       if (unlikely(first == cb->args[2])) {
+               pr_warn("Can't list set %s: one bucket does not fit into "
+                       "a message. Please report it!\n", set->name);
+               cb->args[2] = 0;
+       }
        return 0;
 }
 
@@ -993,12 +1001,15 @@ type_pf_tlist(struct ip_set *set,
        struct slist *n;
        const struct type_pf_elem *data;
        u32 first = cb->args[2];
+       /* We assume that one hash bucket fills into one page */
+       void *incomplete;
        int i;
 
        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
        if (!atd)
                return -EFAULT;
        for (; cb->args[2] < jhash_size(h->htable_bits); cb->args[2]++) {
+               incomplete = skb_tail_pointer(skb);
                slist_for_each(n, &h->htable[cb->args[2]]) {
                        for (i = 0; i < h->array_size; i++) {
                                data = chash_tdata(n, i);
@@ -1029,8 +1040,13 @@ type_pf_tlist(struct ip_set *set,
        return 0;
 
 nla_put_failure:
-       nla_nest_cancel(skb, nested);
+       nlmsg_trim(skb, incomplete);
        ipset_nest_end(skb, atd);
+       if (unlikely(first == cb->args[2])) {
+               pr_warn("Can't list set %s: one bucket does not fit into "
+                       "a message. Please report it!\n", set->name);
+               cb->args[2] = 0;
+       }
        return 0;
 }