From 62a3d29539aa109fed1c8a20d63ef95948b13842 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Mon, 23 Aug 2010 16:48:14 +0200 Subject: Cleanup, compatibility - Use is_vmalloc_addr when freeing vmalloc or kmalloc-ed areas. Thus we can get rid of a flag and simplify some functions. - When checking "same" sets, ignore hash size, because resizing changes it. - 2.6.35 compatibility added. - Discuss backward/forward compatibilities in the README file. --- README | 11 ++++++++ kernel/include/linux/netfilter/ip_set.h | 28 ++++++++------------- kernel/include/linux/netfilter/ip_set_chash.h | 24 +++++++----------- kernel/ip_set_bitmap_ip.c | 6 ++--- kernel/ip_set_bitmap_ipmac.c | 4 +-- kernel/ip_set_bitmap_port.c | 6 ++--- kernel/ip_set_hash_ip.c | 6 ++--- kernel/ip_set_hash_ipport.c | 4 +-- kernel/ip_set_hash_ipportip.c | 4 +-- kernel/ip_set_hash_ipportnet.c | 4 +-- kernel/ip_set_hash_net.c | 4 +-- kernel/xt_set.c | 36 ++++++++++++++++----------- 12 files changed, 71 insertions(+), 66 deletions(-) diff --git a/README b/README index 45d3eb9..6c7749f 100644 --- a/README +++ b/README @@ -54,3 +54,14 @@ That's it! Read the ipset(8) and iptables(8), ip6tables(8) manpages on how to use ipset and its match and target from iptables. + +Compatibilities: + +- The ipset 5.x userspace utility contains a backward compatibility + interface to support the syntax of ipset 4.x. +- The ipset 5.x userspace utility can't talk to the kernel part of ipset 4.x. +- The ipset 5.x kernel part can't talk to the userspace utility from + ipset 4.x. +- The ipset 5.x kernel part can work together with the set match and SET + target from iptables 1.4.7 and below, however if you need the IPv6 support + from ipset 5.x, then you have to use iptables 1.4.8 or above. diff --git a/kernel/include/linux/netfilter/ip_set.h b/kernel/include/linux/netfilter/ip_set.h index b83454a..1c41396 100644 --- a/kernel/include/linux/netfilter/ip_set.h +++ b/kernel/include/linux/netfilter/ip_set.h @@ -245,13 +245,6 @@ struct ip_set_type_variant { bool (*same_set)(const struct ip_set *a, const struct ip_set *b); }; -/* Flags for the set type variants */ -enum ip_set_type_flags { - /* Set members created by kmalloc */ - IP_SET_FLAG_KMALLOC_BIT = 0, - IP_SET_FLAG_KMALLOC = (1 << IP_SET_FLAG_KMALLOC_BIT), -}; - /* The core set type structure */ struct ip_set_type { struct list_head list; @@ -294,8 +287,6 @@ struct ip_set { const struct ip_set_type_variant *variant; /* The actual INET family */ u8 family; - /* Set type flags, filled/modified by create/resize */ - u8 flags; /* The type specific data */ void *data; }; @@ -318,12 +309,14 @@ extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb, /* Allocate members */ static inline void * -ip_set_alloc(size_t size, gfp_t gfp_mask, u8 *flags) +ip_set_alloc(size_t size, gfp_t gfp_mask) { - void *members = kzalloc(size, gfp_mask | __GFP_NOWARN); + void *members = NULL; + + if (size < KMALLOC_MAX_SIZE) + members = kzalloc(size, gfp_mask | __GFP_NOWARN); if (members) { - *flags |= IP_SET_FLAG_KMALLOC; pr_debug("%p: allocated with kmalloc", members); return members; } @@ -331,21 +324,20 @@ ip_set_alloc(size_t size, gfp_t gfp_mask, u8 *flags) members = __vmalloc(size, gfp_mask | __GFP_ZERO, PAGE_KERNEL); if (!members) return NULL; - *flags &= ~IP_SET_FLAG_KMALLOC; pr_debug("%p: allocated with vmalloc", members); return members; } static inline void -ip_set_free(void *members, u8 flags) +ip_set_free(void *members) { pr_debug("%p: free with %s", members, - flags & IP_SET_FLAG_KMALLOC ? "kmalloc" : "vmalloc"); - if (flags & IP_SET_FLAG_KMALLOC) - kfree(members); - else + is_vmalloc_addr(members) ? "vfree" : "kfree"); + if (is_vmalloc_addr(members)) vfree(members); + else + kfree(members); } static inline bool diff --git a/kernel/include/linux/netfilter/ip_set_chash.h b/kernel/include/linux/netfilter/ip_set_chash.h index e0e16bd..5e615e4 100644 --- a/kernel/include/linux/netfilter/ip_set_chash.h +++ b/kernel/include/linux/netfilter/ip_set_chash.h @@ -86,7 +86,7 @@ del_cidr(struct chash_nets *nets, u8 host_mask, u8 cidr) } static void -chash_destroy(struct slist *t, u8 htable_bits, u8 flags) +chash_destroy(struct slist *t, u8 htable_bits) { struct slist *n, *tmp; u32 i; @@ -96,7 +96,7 @@ chash_destroy(struct slist *t, u8 htable_bits, u8 flags) /* FIXME: slab cache */ kfree(n); - ip_set_free(t, flags); + ip_set_free(t); } static size_t @@ -146,7 +146,7 @@ ip_set_hash_destroy(struct ip_set *set) if (with_timeout(h->timeout)) del_timer_sync(&h->gc); - chash_destroy(h->htable, h->htable_bits, set->flags); + chash_destroy(h->htable, h->htable_bits); kfree(h); set->data = NULL; @@ -296,7 +296,6 @@ type_pf_resize(struct ip_set *set, gfp_t gfp_flags, bool retried) struct slist *t, *n; const struct type_pf_elem *data; u32 i, j; - u8 oflags, flags; int ret; retry: @@ -306,12 +305,11 @@ retry: /* In case we have plenty of memory :-) */ return -IPSET_ERR_HASH_FULL; t = ip_set_alloc(jhash_size(htable_bits) * sizeof(struct slist), - gfp_flags, &flags); + gfp_flags); if (!t) return -ENOMEM; write_lock_bh(&set->lock); - flags = oflags = set->flags; for (i = 0; i < jhash_size(h->htable_bits); i++) { next_slot: slist_for_each(n, &h->htable[i]) { @@ -325,7 +323,7 @@ next_slot: data, gfp_flags); if (ret < 0) { write_unlock_bh(&set->lock); - chash_destroy(t, htable_bits, flags); + chash_destroy(t, htable_bits); if (ret == -EAGAIN) goto retry; return ret; @@ -339,10 +337,9 @@ next_slot: h->htable = t; h->htable_bits = htable_bits; - set->flags = flags; write_unlock_bh(&set->lock); - chash_destroy(n, i, oflags); + chash_destroy(n, i); return 0; } @@ -750,7 +747,6 @@ type_pf_tresize(struct ip_set *set, gfp_t gfp_flags, bool retried) struct slist *t, *n; const struct type_pf_elem *data; u32 i, j; - u8 oflags, flags; int ret; /* Try to cleanup once */ @@ -770,12 +766,11 @@ retry: /* In case we have plenty of memory :-) */ return -IPSET_ERR_HASH_FULL; t = ip_set_alloc(jhash_size(htable_bits) * sizeof(struct slist), - gfp_flags, &flags); + gfp_flags); if (!t) return -ENOMEM; write_lock_bh(&set->lock); - flags = oflags = set->flags; for (i = 0; i < jhash_size(h->htable_bits); i++) { next_slot: slist_for_each(n, &h->htable[i]) { @@ -790,7 +785,7 @@ next_slot: type_pf_data_timeout(data)); if (ret < 0) { write_unlock_bh(&set->lock); - chash_destroy(t, htable_bits, flags); + chash_destroy(t, htable_bits); if (ret == -EAGAIN) goto retry; return ret; @@ -804,10 +799,9 @@ next_slot: h->htable = t; h->htable_bits = htable_bits; - set->flags = flags; write_unlock_bh(&set->lock); - chash_destroy(n, i, oflags); + chash_destroy(n, i); return 0; } diff --git a/kernel/ip_set_bitmap_ip.c b/kernel/ip_set_bitmap_ip.c index e63bcda..76baa13 100644 --- a/kernel/ip_set_bitmap_ip.c +++ b/kernel/ip_set_bitmap_ip.c @@ -180,7 +180,7 @@ bitmap_ip_destroy(struct ip_set *set) { struct bitmap_ip *map = set->data; - ip_set_free(map->members, set->flags); + ip_set_free(map->members); kfree(map); set->data = NULL; @@ -423,7 +423,7 @@ bitmap_ip_timeout_destroy(struct ip_set *set) struct bitmap_ip_timeout *map = set->data; del_timer_sync(&map->gc); - ip_set_free(map->members, set->flags); + ip_set_free(map->members); kfree(map); set->data = NULL; @@ -575,7 +575,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, u32 first_ip, u32 last_ip, u32 elements, u32 hosts, u8 netmask) { - map->members = ip_set_alloc(map->memsize, GFP_KERNEL, &set->flags); + map->members = ip_set_alloc(map->memsize, GFP_KERNEL); if (!map->members) return false; map->first_ip = first_ip; diff --git a/kernel/ip_set_bitmap_ipmac.c b/kernel/ip_set_bitmap_ipmac.c index 5833c77..c595e18 100644 --- a/kernel/ip_set_bitmap_ipmac.c +++ b/kernel/ip_set_bitmap_ipmac.c @@ -423,7 +423,7 @@ bitmap_ipmac_destroy(struct ip_set *set) if (with_timeout(map->timeout)) del_timer_sync(&map->gc); - ip_set_free(map->members, set->flags); + ip_set_free(map->members); kfree(map); set->data = NULL; @@ -553,7 +553,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, u32 first_ip, u32 last_ip) { map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize, - GFP_KERNEL, &set->flags); + GFP_KERNEL); if (!map->members) return false; map->first_ip = first_ip; diff --git a/kernel/ip_set_bitmap_port.c b/kernel/ip_set_bitmap_port.c index c96b06c..c385f99 100644 --- a/kernel/ip_set_bitmap_port.c +++ b/kernel/ip_set_bitmap_port.c @@ -166,7 +166,7 @@ bitmap_port_destroy(struct ip_set *set) { struct bitmap_port *map = set->data; - ip_set_free(map->members, set->flags); + ip_set_free(map->members); kfree(map); set->data = NULL; @@ -403,7 +403,7 @@ bitmap_port_timeout_destroy(struct ip_set *set) struct bitmap_port_timeout *map = set->data; del_timer_sync(&map->gc); - ip_set_free(map->members, set->flags); + ip_set_free(map->members); kfree(map); set->data = NULL; @@ -551,7 +551,7 @@ static bool init_map_port(struct ip_set *set, struct bitmap_port *map, u16 first_port, u16 last_port) { - map->members = ip_set_alloc(map->memsize, GFP_KERNEL, &set->flags); + map->members = ip_set_alloc(map->memsize, GFP_KERNEL); if (!map->members) return false; map->first_port = first_port; diff --git a/kernel/ip_set_hash_ip.c b/kernel/ip_set_hash_ip.c index 1af96ac..3295b26 100644 --- a/kernel/ip_set_hash_ip.c +++ b/kernel/ip_set_hash_ip.c @@ -212,11 +212,11 @@ hash_ip_same_set(const struct ip_set *a, const struct ip_set *b) { struct chash *x = a->data; struct chash *y = b->data; - + + /* Resizing changes htable_bits, so we ignore it */ return x->maxelem == y->maxelem && x->timeout == y->timeout && x->netmask == y->netmask - && x->htable_bits == y->htable_bits /* resizing ? */ && x->array_size == y->array_size && x->chain_limit == y->chain_limit; } @@ -431,7 +431,7 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) h->timeout = IPSET_NO_TIMEOUT; h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist), - GFP_KERNEL, &set->flags); + GFP_KERNEL); if (!h->htable) { kfree(h); return -ENOMEM; diff --git a/kernel/ip_set_hash_ipport.c b/kernel/ip_set_hash_ipport.c index f0274f9..8554c80 100644 --- a/kernel/ip_set_hash_ipport.c +++ b/kernel/ip_set_hash_ipport.c @@ -229,10 +229,10 @@ hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b) struct chash *x = a->data; struct chash *y = b->data; + /* Resizing changes htable_bits, so we ignore it */ return x->maxelem == y->maxelem && x->timeout == y->timeout && x->proto == y->proto - && x->htable_bits == y->htable_bits /* resizing ? */ && x->array_size == y->array_size && x->chain_limit == y->chain_limit; } @@ -473,7 +473,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) h->timeout = IPSET_NO_TIMEOUT; h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist), - GFP_KERNEL, &set->flags); + GFP_KERNEL); if (!h->htable) { kfree(h); return -ENOMEM; diff --git a/kernel/ip_set_hash_ipportip.c b/kernel/ip_set_hash_ipportip.c index 16e6f17..d2db3a9 100644 --- a/kernel/ip_set_hash_ipportip.c +++ b/kernel/ip_set_hash_ipportip.c @@ -241,10 +241,10 @@ hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b) struct chash *x = a->data; struct chash *y = b->data; + /* Resizing changes htable_bits, so we ignore it */ return x->maxelem == y->maxelem && x->timeout == y->timeout && x->proto == y->proto - && x->htable_bits == y->htable_bits /* resizing ? */ && x->array_size == y->array_size && x->chain_limit == y->chain_limit; } @@ -500,7 +500,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head, h->timeout = IPSET_NO_TIMEOUT; h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist), - GFP_KERNEL, &set->flags); + GFP_KERNEL); if (!h->htable) { kfree(h); return -ENOMEM; diff --git a/kernel/ip_set_hash_ipportnet.c b/kernel/ip_set_hash_ipportnet.c index f356a88..f2c0d07 100644 --- a/kernel/ip_set_hash_ipportnet.c +++ b/kernel/ip_set_hash_ipportnet.c @@ -270,10 +270,10 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b) struct chash *x = a->data; struct chash *y = b->data; + /* Resizing changes htable_bits, so we ignore it */ return x->maxelem == y->maxelem && x->timeout == y->timeout && x->proto == y->proto - && x->htable_bits == y->htable_bits /* resizing ? */ && x->array_size == y->array_size && x->chain_limit == y->chain_limit; } @@ -567,7 +567,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head, h->timeout = IPSET_NO_TIMEOUT; h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist), - GFP_KERNEL, &set->flags); + GFP_KERNEL); if (!h->htable) { kfree(h); return -ENOMEM; diff --git a/kernel/ip_set_hash_net.c b/kernel/ip_set_hash_net.c index 42112a2..6b755ce 100644 --- a/kernel/ip_set_hash_net.c +++ b/kernel/ip_set_hash_net.c @@ -211,9 +211,9 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b) struct chash *x = a->data; struct chash *y = b->data; + /* Resizing changes htable_bits, so we ignore it */ return x->maxelem == y->maxelem && x->timeout == y->timeout - && x->htable_bits == y->htable_bits /* resizing ? */ && x->array_size == y->array_size && x->chain_limit == y->chain_limit; } @@ -442,7 +442,7 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) h->timeout = IPSET_NO_TIMEOUT; h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist), - GFP_KERNEL, &set->flags); + GFP_KERNEL); if (!h->htable) { kfree(h); return -ENOMEM; diff --git a/kernel/xt_set.c b/kernel/xt_set.c index 4734cc4..05bd84e 100644 --- a/kernel/xt_set.c +++ b/kernel/xt_set.c @@ -48,6 +48,14 @@ match_set(ip_set_id_t index, const struct sk_buff *skb, #error "Linux kernel version too old: must be >= 2.6.31" #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) +#define CHECK_OK 1 +#define CHECK_FAIL 0 +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */ +#define CHECK_OK 0 +#define CHECK_FAIL -EINVAL +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) static bool set_match_v0(const struct sk_buff *skb, const struct xt_match_param *par) @@ -96,17 +104,17 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("Cannot find set indentified by id %u to match", info->match_set.index); - return 0; /* error */ + return CHECK_FAIL; /* error */ } if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { pr_warning("That's nasty!"); - return 0; /* error */ + return CHECK_FAIL; /* error */ } /* Fill out compatibility data */ compat_flags(&info->match_set); - return 1; + return CHECK_OK; } static void @@ -155,7 +163,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("cannot find add_set index %u as target", info->add_set.index); - return 0; /* error */ + return CHECK_FAIL; /* error */ } } @@ -164,20 +172,20 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("cannot find del_set index %u as target", info->del_set.index); - return 0; /* error */ + return CHECK_FAIL; /* error */ } } if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 || info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) { pr_warning("That's nasty!"); - return 0; /* error */ + return CHECK_FAIL; /* error */ } /* Fill out compatibility data */ compat_flags(&info->add_set); compat_flags(&info->del_set); - return 1; + return CHECK_OK; } static void @@ -225,14 +233,14 @@ set_match_checkentry(const struct xt_mtchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("Cannot find set indentified by id %u to match", info->match_set.index); - return 0; /* error */ + return CHECK_FAIL; /* error */ } if (info->match_set.dim > IPSET_DIM_MAX) { pr_warning("That's nasty!"); - return 0; /* error */ + return CHECK_FAIL; /* error */ } - return 1; + return CHECK_OK; } static void @@ -283,7 +291,7 @@ set_target_checkentry(const struct xt_tgchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("cannot find add_set index %u as target", info->add_set.index); - return 0; /* error */ + return CHECK_FAIL; /* error */ } } @@ -292,16 +300,16 @@ set_target_checkentry(const struct xt_tgchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("cannot find del_set index %u as target", info->del_set.index); - return 0; /* error */ + return CHECK_FAIL; /* error */ } } if (info->add_set.dim > IPSET_DIM_MAX || info->del_set.flags > IPSET_DIM_MAX) { pr_warning("That's nasty!"); - return 0; /* error */ + return CHECK_FAIL; /* error */ } - return 1; + return CHECK_OK; } static void -- cgit v1.2.3