From cb76e46e97b0013305a7c96c2230a791675a15cf Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Tue, 10 Nov 2009 21:53:19 +0100 Subject: ipset 4.0 released See ChangeLog files --- kernel/ChangeLog | 8 + kernel/include/linux/netfilter_ipv4/ip_set.h | 67 +- .../include/linux/netfilter_ipv4/ip_set_bitmaps.h | 21 +- .../include/linux/netfilter_ipv4/ip_set_compat.h | 23 +- .../include/linux/netfilter_ipv4/ip_set_getport.h | 6 +- .../include/linux/netfilter_ipv4/ip_set_hashes.h | 16 +- .../include/linux/netfilter_ipv4/ip_set_iphash.h | 2 +- kernel/include/linux/netfilter_ipv4/ip_set_ipmap.h | 2 +- .../linux/netfilter_ipv4/ip_set_ipporthash.h | 2 +- .../linux/netfilter_ipv4/ip_set_ipportiphash.h | 2 +- .../linux/netfilter_ipv4/ip_set_ipportnethash.h | 2 +- .../include/linux/netfilter_ipv4/ip_set_iptree.h | 2 +- .../linux/netfilter_ipv4/ip_set_iptreemap.h | 2 +- .../include/linux/netfilter_ipv4/ip_set_macipmap.h | 2 +- .../include/linux/netfilter_ipv4/ip_set_nethash.h | 2 +- .../include/linux/netfilter_ipv4/ip_set_portmap.h | 2 +- .../include/linux/netfilter_ipv4/ip_set_setlist.h | 2 +- kernel/ip_set.c | 894 ++++----------------- kernel/ip_set_iphash.c | 28 +- kernel/ip_set_ipmap.c | 48 +- kernel/ip_set_ipporthash.c | 36 +- kernel/ip_set_ipportiphash.c | 42 +- kernel/ip_set_ipportnethash.c | 66 +- kernel/ip_set_iptree.c | 27 +- kernel/ip_set_iptreemap.c | 54 +- kernel/ip_set_macipmap.c | 55 +- kernel/ip_set_nethash.c | 44 +- kernel/ip_set_portmap.c | 44 +- kernel/ip_set_setlist.c | 36 +- 29 files changed, 507 insertions(+), 1030 deletions(-) (limited to 'kernel') diff --git a/kernel/ChangeLog b/kernel/ChangeLog index 849e98e..192f689 100644 --- a/kernel/ChangeLog +++ b/kernel/ChangeLog @@ -1,5 +1,13 @@ +4.0 - Compilation of ip_set_iptree.c fails with kernel 2.6.20 due to missing include of linux/jiffies.h (Jan Engelhardt) + - Do not use DECLARE_MUTEX (compatibility fix on 2.6.31-rt, Jan + Engelhardt) + - Flushing iptreemap type of sets caused high ksoftirqd load due to + zeroed out timeout parameter (bug reported by Georg Chini) + - New protocol is introduced to handle aligment issues properly + (bug reported by Georg Chini) + - Binding support is removed 3.2 - Mixed up formats in ip_set_iptree.c (Rob Sterenborg) diff --git a/kernel/include/linux/netfilter_ipv4/ip_set.h b/kernel/include/linux/netfilter_ipv4/ip_set.h index 3667352..da17319 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set.h @@ -40,7 +40,8 @@ /* * Used so that the kernel module and ipset-binary can match their versions */ -#define IP_SET_PROTOCOL_VERSION 3 +#define IP_SET_PROTOCOL_UNALIGNED 3 +#define IP_SET_PROTOCOL_VERSION 4 #define IP_SET_MAXNAMELEN 32 /* set names and set typenames */ @@ -228,7 +229,7 @@ struct ip_set_req_max_sets { struct ip_set_req_setnames { unsigned op; ip_set_id_t index; /* set to list/save */ - u_int32_t size; /* size to get setdata/bindings */ + u_int32_t size; /* size to get setdata */ /* followed by sets number of struct ip_set_name_list */ }; @@ -302,6 +303,11 @@ static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b) /* General limit for the elements in a set */ #define MAX_RANGE 0x0000FFFF +/* Alignment: 'unsigned long' unsupported */ +#define IPSET_ALIGNTO 4 +#define IPSET_ALIGN(len) (((len) + IPSET_ALIGNTO - 1) & ~(IPSET_ALIGNTO - 1)) +#define IPSET_VALIGN(len, old) ((old) ? (len) : IPSET_ALIGN(len)) + #ifdef __KERNEL__ #include #include @@ -350,16 +356,13 @@ struct ip_set_type { */ int (*testip_kernel) (struct ip_set *set, const struct sk_buff * skb, - ip_set_ip_t *ip, - const u_int32_t *flags, - unsigned char index); + const u_int32_t *flags); /* test for IP in set (userspace: ipset -T set IP) * return 0 if not in set, 1 if in set. */ int (*testip) (struct ip_set *set, - const void *data, u_int32_t size, - ip_set_ip_t *ip); + const void *data, u_int32_t size); /* * Size of the data structure passed by when @@ -373,8 +376,7 @@ struct ip_set_type { * If the address was not already in the set, 0 is returned. */ int (*addip) (struct ip_set *set, - const void *data, u_int32_t size, - ip_set_ip_t *ip); + const void *data, u_int32_t size); /* Add IP into set (kernel: iptables ... -j SET set src|dst) * Return -EEXIST if the address is already in the set, @@ -382,10 +384,8 @@ struct ip_set_type { * If the address was not already in the set, 0 is returned. */ int (*addip_kernel) (struct ip_set *set, - const struct sk_buff * skb, - ip_set_ip_t *ip, - const u_int32_t *flags, - unsigned char index); + const struct sk_buff * skb, + const u_int32_t *flags); /* remove IP from set (userspace: ipset -D set --entry x) * Return -EEXIST if the address is NOT in the set, @@ -393,8 +393,7 @@ struct ip_set_type { * If the address really was in the set, 0 is returned. */ int (*delip) (struct ip_set *set, - const void *data, u_int32_t size, - ip_set_ip_t *ip); + const void *data, u_int32_t size); /* remove IP from set (kernel: iptables ... -j SET --entry x) * Return -EEXIST if the address is NOT in the set, @@ -402,10 +401,8 @@ struct ip_set_type { * If the address really was in the set, 0 is returned. */ int (*delip_kernel) (struct ip_set *set, - const struct sk_buff * skb, - ip_set_ip_t *ip, - const u_int32_t *flags, - unsigned char index); + const struct sk_buff * skb, + const u_int32_t *flags); /* new set creation - allocated type specific items */ @@ -443,7 +440,7 @@ struct ip_set_type { /* Listing: Get the size for the set members */ - int (*list_members_size) (const struct ip_set *set); + int (*list_members_size) (const struct ip_set *set, char dont_align); /* Listing: Get the set members * @@ -453,7 +450,7 @@ struct ip_set_type { * correct. */ void (*list_members) (const struct ip_set *set, - void *data); + void *data, char dont_align); char typename[IP_SET_MAXNAMELEN]; unsigned char features; @@ -471,20 +468,11 @@ struct ip_set { char name[IP_SET_MAXNAMELEN]; /* the name of the set */ rwlock_t lock; /* lock for concurrency control */ ip_set_id_t id; /* set id for swapping */ - ip_set_id_t binding; /* default binding for the set */ atomic_t ref; /* in kernel and in hash references */ struct ip_set_type *type; /* the set types */ void *data; /* pooltype specific data */ }; -/* Structure to bind set elements to sets */ -struct ip_set_hash { - struct list_head list; /* list of clashing entries in hash */ - ip_set_ip_t ip; /* ip from set */ - ip_set_id_t id; /* set id */ - ip_set_id_t binding; /* set we bind the element to */ -}; - /* register and unregister set references */ extern ip_set_id_t ip_set_get_byname(const char name[IP_SET_MAXNAMELEN]); extern ip_set_id_t ip_set_get_byindex(ip_set_id_t index); @@ -515,12 +503,11 @@ extern int ip_set_testip_kernel(ip_set_id_t id, #define UADT0(type, adt, args...) \ static int \ -FNAME(type,_u,adt)(struct ip_set *set, const void *data, u_int32_t size,\ - ip_set_ip_t *hash_ip) \ +FNAME(type,_u,adt)(struct ip_set *set, const void *data, u_int32_t size)\ { \ const STRUCT(ip_set_req_,type) *req = data; \ \ - return FNAME(type,_,adt)(set, hash_ip , ## args); \ + return FNAME(type,_,adt)(set , ## args); \ } #define UADT(type, adt, args...) \ @@ -530,14 +517,12 @@ FNAME(type,_u,adt)(struct ip_set *set, const void *data, u_int32_t size,\ static int \ FNAME(type,_k,adt)(struct ip_set *set, \ const struct sk_buff *skb, \ - ip_set_ip_t *hash_ip, \ - const u_int32_t *flags, \ - unsigned char index) \ + const u_int32_t *flags) \ { \ - ip_set_ip_t ip = getfn(skb, flags[index]); \ + ip_set_ip_t ip = getfn(skb, flags); \ \ KADT_CONDITION \ - return FNAME(type,_,adt)(set, hash_ip, ip , ##args); \ + return FNAME(type,_,adt)(set, ip , ##args); \ } #define REGISTER_MODULE(type) \ @@ -559,9 +544,9 @@ module_exit(ip_set_##type##_fini); /* Common functions */ static inline ip_set_ip_t -ipaddr(const struct sk_buff *skb, u_int32_t flag) +ipaddr(const struct sk_buff *skb, const u_int32_t *flags) { - return ntohl(flag & IPSET_SRC ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr); + return ntohl(flags[0] & IPSET_SRC ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr); } #define jhash_ip(map, i, ip) jhash_1word(ip, *(map->initval + i)) @@ -571,4 +556,6 @@ ipaddr(const struct sk_buff *skb, u_int32_t flag) #endif /* __KERNEL__ */ +#define UNUSED __attribute__ ((unused)) + #endif /*_IP_SET_H*/ diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_bitmaps.h b/kernel/include/linux/netfilter_ipv4/ip_set_bitmaps.h index 90e87e3..da3493f 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_bitmaps.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_bitmaps.h @@ -77,22 +77,21 @@ type##_list_header(const struct ip_set *set, void *data) \ __##type##_list_header(map, header); \ } -#define BITMAP_LIST_MEMBERS_SIZE(type) \ +#define BITMAP_LIST_MEMBERS_SIZE(type, dtype, sizeid, testfn) \ static int \ -type##_list_members_size(const struct ip_set *set) \ +type##_list_members_size(const struct ip_set *set, char dont_align) \ { \ const struct ip_set_##type *map = set->data; \ + ip_set_ip_t i, elements = 0; \ \ - return map->size; \ -} - -#define BITMAP_LIST_MEMBERS(type) \ -static void \ -type##_list_members(const struct ip_set *set, void *data) \ -{ \ - const struct ip_set_##type *map = set->data; \ + if (dont_align) \ + return map->size; \ + \ + for (i = 0; i < sizeid; i++) \ + if (testfn) \ + elements++; \ \ - memcpy(data, map->members, map->size); \ + return elements * IPSET_ALIGN(sizeof(dtype)); \ } #define IP_SET_TYPE(type, __features) \ diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_compat.h b/kernel/include/linux/netfilter_ipv4/ip_set_compat.h index 96c2024..9f17397 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_compat.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_compat.h @@ -65,7 +65,28 @@ static inline void *kzalloc(size_t size, gfp_t flags) #define KMEM_CACHE_CREATE(name, size) \ kmem_cache_create(name, size, 0, 0, NULL) #endif - + +#ifndef NIPQUAD +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] +#endif + +#ifndef HIPQUAD +#if defined(__LITTLE_ENDIAN) +#define HIPQUAD(addr) \ + ((unsigned char *)&addr)[3], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[0] +#elif defined(__BIG_ENDIAN) +#define HIPQUAD NIPQUAD +#else +#error "Please fix asm/byteorder.h" +#endif /* __LITTLE_ENDIAN */ +#endif #endif /* __KERNEL__ */ #endif /* _IP_SET_COMPAT_H */ diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_getport.h b/kernel/include/linux/netfilter_ipv4/ip_set_getport.h index 9e322bf..18ed729 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_getport.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_getport.h @@ -7,7 +7,7 @@ /* We must handle non-linear skbs */ static inline ip_set_ip_t -get_port(const struct sk_buff *skb, u_int32_t flags) +get_port(const struct sk_buff *skb, const u_int32_t *flags) { struct iphdr *iph = ip_hdr(skb); u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET; @@ -23,7 +23,7 @@ get_port(const struct sk_buff *skb, u_int32_t flags) /* No choice either */ return INVALID_PORT; - return ntohs(flags & IPSET_SRC ? + return ntohs(flags[0] & IPSET_SRC ? tcph.source : tcph.dest); } case IPPROTO_UDP: { @@ -36,7 +36,7 @@ get_port(const struct sk_buff *skb, u_int32_t flags) /* No choice either */ return INVALID_PORT; - return ntohs(flags & IPSET_SRC ? + return ntohs(flags[0] & IPSET_SRC ? udph.source : udph.dest); } default: diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_hashes.h b/kernel/include/linux/netfilter_ipv4/ip_set_hashes.h index f7d6a69..f62ae37 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_hashes.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_hashes.h @@ -182,30 +182,31 @@ type##_list_header(const struct ip_set *set, void *data) \ #define HASH_LIST_MEMBERS_SIZE(type, dtype) \ static int \ -type##_list_members_size(const struct ip_set *set) \ +type##_list_members_size(const struct ip_set *set, char dont_align) \ { \ const struct ip_set_##type *map = set->data; \ \ - return (map->hashsize * sizeof(dtype)); \ + return (map->hashsize * IPSET_VALIGN(sizeof(dtype), dont_align));\ } #define HASH_LIST_MEMBERS(type, dtype) \ static void \ -type##_list_members(const struct ip_set *set, void *data) \ +type##_list_members(const struct ip_set *set, void *data, char dont_align)\ { \ const struct ip_set_##type *map = set->data; \ - dtype *elem; \ + dtype *elem, *d; \ uint32_t i; \ \ for (i = 0; i < map->hashsize; i++) { \ elem = HARRAY_ELEM(map->members, dtype *, i); \ - ((dtype *)data)[i] = *elem; \ + d = data + i * IPSET_VALIGN(sizeof(dtype), dont_align); \ + *d = *elem; \ } \ } #define HASH_LIST_MEMBERS_MEMCPY(type, dtype) \ static void \ -type##_list_members(const struct ip_set *set, void *data) \ +type##_list_members(const struct ip_set *set, void *data, char dont_align)\ { \ const struct ip_set_##type *map = set->data; \ dtype *elem; \ @@ -213,7 +214,8 @@ type##_list_members(const struct ip_set *set, void *data) \ \ for (i = 0; i < map->hashsize; i++) { \ elem = HARRAY_ELEM(map->members, dtype *, i); \ - memcpy((((dtype *)data)+i), elem, sizeof(dtype)); \ + memcpy(data + i * IPSET_VALIGN(sizeof(dtype), dont_align),\ + elem, sizeof(dtype)); \ } \ } diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_iphash.h b/kernel/include/linux/netfilter_ipv4/ip_set_iphash.h index 277bc8c..0a0c7e8 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_iphash.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_iphash.h @@ -4,7 +4,7 @@ #include #include -#define SETTYPE_NAME "iphash" +#define SETTYPE_NAME "iphash" struct ip_set_iphash { ip_set_ip_t *members; /* the iphash proper */ diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_ipmap.h b/kernel/include/linux/netfilter_ipv4/ip_set_ipmap.h index ce4b29b..d16c0ae 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_ipmap.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_ipmap.h @@ -4,7 +4,7 @@ #include #include -#define SETTYPE_NAME "ipmap" +#define SETTYPE_NAME "ipmap" struct ip_set_ipmap { void *members; /* the ipmap proper */ diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_ipporthash.h b/kernel/include/linux/netfilter_ipv4/ip_set_ipporthash.h index b5db5f5..a3b781a 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_ipporthash.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_ipporthash.h @@ -4,7 +4,7 @@ #include #include -#define SETTYPE_NAME "ipporthash" +#define SETTYPE_NAME "ipporthash" struct ip_set_ipporthash { ip_set_ip_t *members; /* the ipporthash proper */ diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_ipportiphash.h b/kernel/include/linux/netfilter_ipv4/ip_set_ipportiphash.h index eb6cf55..2202c51 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_ipportiphash.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_ipportiphash.h @@ -4,7 +4,7 @@ #include #include -#define SETTYPE_NAME "ipportiphash" +#define SETTYPE_NAME "ipportiphash" struct ipportip { ip_set_ip_t ip; diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_ipportnethash.h b/kernel/include/linux/netfilter_ipv4/ip_set_ipportnethash.h index 951da92..73b2430 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_ipportnethash.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_ipportnethash.h @@ -4,7 +4,7 @@ #include #include -#define SETTYPE_NAME "ipportnethash" +#define SETTYPE_NAME "ipportnethash" struct ipportip { ip_set_ip_t ip; diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_iptree.h b/kernel/include/linux/netfilter_ipv4/ip_set_iptree.h index de5cf47..36bf5ac 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_iptree.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_iptree.h @@ -3,7 +3,7 @@ #include -#define SETTYPE_NAME "iptree" +#define SETTYPE_NAME "iptree" struct ip_set_iptreed { unsigned long expires[256]; /* x.x.x.ADDR */ diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_iptreemap.h b/kernel/include/linux/netfilter_ipv4/ip_set_iptreemap.h index a58bc4e..6ea771a 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_iptreemap.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_iptreemap.h @@ -3,7 +3,7 @@ #include -#define SETTYPE_NAME "iptreemap" +#define SETTYPE_NAME "iptreemap" #ifdef __KERNEL__ struct ip_set_iptreemap_d { diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_macipmap.h b/kernel/include/linux/netfilter_ipv4/ip_set_macipmap.h index 19418f3..0615e9f 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_macipmap.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_macipmap.h @@ -4,7 +4,7 @@ #include #include -#define SETTYPE_NAME "macipmap" +#define SETTYPE_NAME "macipmap" /* general flags */ #define IPSET_MACIP_MATCHUNSET 1 diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_nethash.h b/kernel/include/linux/netfilter_ipv4/ip_set_nethash.h index b2d006f..cf0b794 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_nethash.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_nethash.h @@ -4,7 +4,7 @@ #include #include -#define SETTYPE_NAME "nethash" +#define SETTYPE_NAME "nethash" struct ip_set_nethash { ip_set_ip_t *members; /* the nethash proper */ diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_portmap.h b/kernel/include/linux/netfilter_ipv4/ip_set_portmap.h index 8ea6ba2..37f411e 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_portmap.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_portmap.h @@ -4,7 +4,7 @@ #include #include -#define SETTYPE_NAME "portmap" +#define SETTYPE_NAME "portmap" struct ip_set_portmap { void *members; /* the portmap proper */ diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_setlist.h b/kernel/include/linux/netfilter_ipv4/ip_set_setlist.h index ca044d8..7cc6ed0 100644 --- a/kernel/include/linux/netfilter_ipv4/ip_set_setlist.h +++ b/kernel/include/linux/netfilter_ipv4/ip_set_setlist.h @@ -3,7 +3,7 @@ #include -#define SETTYPE_NAME "setlist" +#define SETTYPE_NAME "setlist" #define IP_SET_SETLIST_ADD_AFTER 0 #define IP_SET_SETLIST_ADD_BEFORE 1 diff --git a/kernel/ip_set.c b/kernel/ip_set.c index c836d85..30185c5 100644 --- a/kernel/ip_set.c +++ b/kernel/ip_set.c @@ -39,19 +39,18 @@ static struct list_head set_type_list; /* all registered sets */ static struct ip_set **ip_set_list; /* all individual sets */ static DEFINE_RWLOCK(ip_set_lock); /* protects the lists and the hash */ -static DECLARE_MUTEX(ip_set_app_mutex); /* serializes user access */ +static struct semaphore ip_set_app_mutex; /* serializes user access */ static ip_set_id_t ip_set_max = CONFIG_IP_NF_SET_MAX; -static ip_set_id_t ip_set_bindings_hash_size = CONFIG_IP_NF_SET_HASHSIZE; -static struct list_head *ip_set_hash; /* hash of bindings */ -static unsigned int ip_set_hash_random; /* random seed */ +static int protocol_version = IP_SET_PROTOCOL_VERSION; -#define SETNAME_EQ(a,b) (strncmp(a,b,IP_SET_MAXNAMELEN) == 0) +#define STREQ(a,b) (strncmp(a,b,IP_SET_MAXNAMELEN) == 0) +#define DONT_ALIGN (protocol_version == IP_SET_PROTOCOL_UNALIGNED) +#define ALIGNED(len) IPSET_VALIGN(len, DONT_ALIGN) /* * Sets are identified either by the index in ip_set_list or by id. - * The id never changes and is used to find a key in the hash. - * The index may change by swapping and used at all other places - * (set/SET netfilter modules, binding value, etc.) + * The id never changes. The index may change by swapping and used + * by external references (set/SET netfilter modules, etc.) * * Userspace requests are serialized by ip_set_mutex and sets can * be deleted only from userspace. Therefore ip_set_list locking @@ -73,166 +72,25 @@ __ip_set_put(ip_set_id_t index) atomic_dec(&ip_set_list[index]->ref); } -/* - * Binding routines - */ - -static inline struct ip_set_hash * -__ip_set_find(u_int32_t key, ip_set_id_t id, ip_set_ip_t ip) -{ - struct ip_set_hash *set_hash; - - list_for_each_entry(set_hash, &ip_set_hash[key], list) - if (set_hash->id == id && set_hash->ip == ip) - return set_hash; - - return NULL; -} - -static ip_set_id_t -ip_set_find_in_hash(ip_set_id_t id, ip_set_ip_t ip) -{ - u_int32_t key = jhash_2words(id, ip, ip_set_hash_random) - % ip_set_bindings_hash_size; - struct ip_set_hash *set_hash; - - ASSERT_READ_LOCK(&ip_set_lock); - IP_SET_ASSERT(ip_set_list[id]); - DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip)); - - set_hash = __ip_set_find(key, id, ip); - - DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name, - HIPQUAD(ip), - set_hash != NULL ? ip_set_list[set_hash->binding]->name : ""); - - return (set_hash != NULL ? set_hash->binding : IP_SET_INVALID_ID); -} - -static inline void -__set_hash_del(struct ip_set_hash *set_hash) -{ - ASSERT_WRITE_LOCK(&ip_set_lock); - IP_SET_ASSERT(ip_set_list[set_hash->binding]); - - __ip_set_put(set_hash->binding); - list_del(&set_hash->list); - kfree(set_hash); -} - -static int -ip_set_hash_del(ip_set_id_t id, ip_set_ip_t ip) -{ - u_int32_t key = jhash_2words(id, ip, ip_set_hash_random) - % ip_set_bindings_hash_size; - struct ip_set_hash *set_hash; - - IP_SET_ASSERT(ip_set_list[id]); - DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip)); - write_lock_bh(&ip_set_lock); - set_hash = __ip_set_find(key, id, ip); - DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name, - HIPQUAD(ip), - set_hash != NULL ? ip_set_list[set_hash->binding]->name : ""); - - if (set_hash != NULL) - __set_hash_del(set_hash); - write_unlock_bh(&ip_set_lock); - return 0; -} - -static int -ip_set_hash_add(ip_set_id_t id, ip_set_ip_t ip, ip_set_id_t binding) -{ - u_int32_t key = jhash_2words(id, ip, ip_set_hash_random) - % ip_set_bindings_hash_size; - struct ip_set_hash *set_hash; - int ret = 0; - - IP_SET_ASSERT(ip_set_list[id]); - IP_SET_ASSERT(ip_set_list[binding]); - DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name, - HIPQUAD(ip), ip_set_list[binding]->name); - write_lock_bh(&ip_set_lock); - set_hash = __ip_set_find(key, id, ip); - if (!set_hash) { - set_hash = kmalloc(sizeof(struct ip_set_hash), GFP_ATOMIC); - if (!set_hash) { - ret = -ENOMEM; - goto unlock; - } - INIT_LIST_HEAD(&set_hash->list); - set_hash->id = id; - set_hash->ip = ip; - list_add(&set_hash->list, &ip_set_hash[key]); - } else { - IP_SET_ASSERT(ip_set_list[set_hash->binding]); - DP("overwrite binding: %s", - ip_set_list[set_hash->binding]->name); - __ip_set_put(set_hash->binding); - } - set_hash->binding = binding; - __ip_set_get(set_hash->binding); - DP("stored: key %u, id %u (%s), ip %u.%u.%u.%u, binding %u (%s)", - key, id, ip_set_list[id]->name, - HIPQUAD(ip), binding, ip_set_list[binding]->name); - unlock: - write_unlock_bh(&ip_set_lock); - return ret; -} - -#define FOREACH_HASH_DO(fn, args...) \ -({ \ - ip_set_id_t __key; \ - struct ip_set_hash *__set_hash; \ - \ - for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \ - list_for_each_entry(__set_hash, &ip_set_hash[__key], list) \ - fn(__set_hash , ## args); \ - } \ -}) - -#define FOREACH_HASH_RW_DO(fn, args...) \ -({ \ - ip_set_id_t __key; \ - struct ip_set_hash *__set_hash, *__n; \ - \ - ASSERT_WRITE_LOCK(&ip_set_lock); \ - for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \ - list_for_each_entry_safe(__set_hash, __n, &ip_set_hash[__key], list)\ - fn(__set_hash , ## args); \ - } \ -}) - /* Add, del and test set entries from kernel */ -#define follow_bindings(index, set, ip) \ -((index = ip_set_find_in_hash((set)->id, ip)) != IP_SET_INVALID_ID \ - || (index = (set)->binding) != IP_SET_INVALID_ID) - int ip_set_testip_kernel(ip_set_id_t index, const struct sk_buff *skb, const u_int32_t *flags) { struct ip_set *set; - ip_set_ip_t ip; int res; - unsigned char i = 0; - - IP_SET_ASSERT(flags[i]); + read_lock_bh(&ip_set_lock); - do { - set = ip_set_list[index]; - IP_SET_ASSERT(set); - DP("set %s, index %u", set->name, index); - read_lock_bh(&set->lock); - res = set->type->testip_kernel(set, skb, &ip, flags, i++); - read_unlock_bh(&set->lock); - i += !!(set->type->features & IPSET_DATA_DOUBLE); - } while (res > 0 - && flags[i] - && follow_bindings(index, set, ip)); + set = ip_set_list[index]; + IP_SET_ASSERT(set); + DP("set %s, index %u", set->name, index); + + read_lock_bh(&set->lock); + res = set->type->testip_kernel(set, skb, flags); + read_unlock_bh(&set->lock); + read_unlock_bh(&ip_set_lock); return (res < 0 ? 0 : res); @@ -244,26 +102,20 @@ ip_set_addip_kernel(ip_set_id_t index, const u_int32_t *flags) { struct ip_set *set; - ip_set_ip_t ip; int res; - unsigned char i = 0; - IP_SET_ASSERT(flags[i]); retry: read_lock_bh(&ip_set_lock); - do { - set = ip_set_list[index]; - IP_SET_ASSERT(set); - DP("set %s, index %u", set->name, index); - write_lock_bh(&set->lock); - res = set->type->addip_kernel(set, skb, &ip, flags, i++); - write_unlock_bh(&set->lock); - i += !!(set->type->features & IPSET_DATA_DOUBLE); - } while ((res == 0 || res == -EEXIST) - && flags[i] - && follow_bindings(index, set, ip)); - read_unlock_bh(&ip_set_lock); + set = ip_set_list[index]; + IP_SET_ASSERT(set); + DP("set %s, index %u", set->name, index); + write_lock_bh(&set->lock); + res = set->type->addip_kernel(set, skb, flags); + write_unlock_bh(&set->lock); + + read_unlock_bh(&ip_set_lock); + /* Retry function called without holding any lock */ if (res == -EAGAIN && set->type->retry && (res = set->type->retry(set)) == 0) @@ -278,23 +130,17 @@ ip_set_delip_kernel(ip_set_id_t index, const u_int32_t *flags) { struct ip_set *set; - ip_set_ip_t ip; int res; - unsigned char i = 0; - IP_SET_ASSERT(flags[i]); read_lock_bh(&ip_set_lock); - do { - set = ip_set_list[index]; - IP_SET_ASSERT(set); - DP("set %s, index %u", set->name, index); - write_lock_bh(&set->lock); - res = set->type->delip_kernel(set, skb, &ip, flags, i++); - write_unlock_bh(&set->lock); - i += !!(set->type->features & IPSET_DATA_DOUBLE); - } while ((res == 0 || res == -EEXIST) - && flags[i] - && follow_bindings(index, set, ip)); + set = ip_set_list[index]; + IP_SET_ASSERT(set); + DP("set %s, index %u", set->name, index); + + write_lock_bh(&set->lock); + res = set->type->delip_kernel(set, skb, flags); + write_unlock_bh(&set->lock); + read_unlock_bh(&ip_set_lock); return res; @@ -308,7 +154,7 @@ find_set_type(const char *name) struct ip_set_type *set_type; list_for_each_entry(set_type, &set_type_list, list) - if (!strncmp(set_type->typename, name, IP_SET_MAXNAMELEN - 1)) + if (STREQ(set_type->typename, name)) return set_type; return NULL; } @@ -369,7 +215,7 @@ __ip_set_get_byname(const char *name, struct ip_set **set) for (i = 0; i < ip_set_max; i++) { if (ip_set_list[i] != NULL - && SETNAME_EQ(ip_set_list[i]->name, name)) { + && STREQ(ip_set_list[i]->name, name)) { __ip_set_get(i); index = i; *set = ip_set_list[i]; @@ -379,7 +225,8 @@ __ip_set_get_byname(const char *name, struct ip_set **set) return index; } -void __ip_set_put_byindex(ip_set_id_t index) +void +__ip_set_put_byindex(ip_set_id_t index) { if (ip_set_list[index]) __ip_set_put(index); @@ -402,7 +249,7 @@ ip_set_get_byname(const char *name) down(&ip_set_app_mutex); for (i = 0; i < ip_set_max; i++) { if (ip_set_list[i] != NULL - && SETNAME_EQ(ip_set_list[i]->name, name)) { + && STREQ(ip_set_list[i]->name, name)) { __ip_set_get(i); index = i; break; @@ -453,7 +300,8 @@ ip_set_id(ip_set_id_t index) * reference count by 1. The caller shall not assume the index * to be valid, after calling this function. */ -void ip_set_put_byindex(ip_set_id_t index) +void +ip_set_put_byindex(ip_set_id_t index) { down(&ip_set_app_mutex); if (ip_set_list[index]) @@ -469,7 +317,7 @@ ip_set_find_byname(const char *name) for (i = 0; i < ip_set_max; i++) { if (ip_set_list[i] != NULL - && SETNAME_EQ(ip_set_list[i]->name, name)) { + && STREQ(ip_set_list[i]->name, name)) { index = i; break; } @@ -487,37 +335,18 @@ ip_set_find_byindex(ip_set_id_t index) } /* - * Add, del, test, bind and unbind + * Add, del and test */ -static inline int -__ip_set_testip(struct ip_set *set, - const void *data, - u_int32_t size, - ip_set_ip_t *ip) -{ - int res; - - read_lock_bh(&set->lock); - res = set->type->testip(set, data, size, ip); - read_unlock_bh(&set->lock); - - return res; -} - static int -__ip_set_addip(ip_set_id_t index, - const void *data, - u_int32_t size) +ip_set_addip(struct ip_set *set, const void *data, u_int32_t size) { - struct ip_set *set = ip_set_list[index]; - ip_set_ip_t ip; int res; IP_SET_ASSERT(set); do { write_lock_bh(&set->lock); - res = set->type->addip(set, data, size, &ip); + res = set->type->addip(set, data, size); write_unlock_bh(&set->lock); } while (res == -EAGAIN && set->type->retry @@ -527,289 +356,33 @@ __ip_set_addip(ip_set_id_t index, } static int -ip_set_addip(ip_set_id_t index, - const void *data, - u_int32_t size) -{ - struct ip_set *set = ip_set_list[index]; - - IP_SET_ASSERT(set); - - if (size - sizeof(struct ip_set_req_adt) != set->type->reqsize) { - ip_set_printk("data length wrong (want %lu, have %zu)", - (long unsigned)set->type->reqsize, - size - sizeof(struct ip_set_req_adt)); - return -EINVAL; - } - return __ip_set_addip(index, - data + sizeof(struct ip_set_req_adt), - size - sizeof(struct ip_set_req_adt)); -} - -static int -ip_set_delip(ip_set_id_t index, - const void *data, - u_int32_t size) +ip_set_delip(struct ip_set *set, const void *data, u_int32_t size) { - struct ip_set *set = ip_set_list[index]; - ip_set_ip_t ip; int res; IP_SET_ASSERT(set); - if (size - sizeof(struct ip_set_req_adt) != set->type->reqsize) { - ip_set_printk("data length wrong (want %lu, have %zu)", - (long unsigned)set->type->reqsize, - size - sizeof(struct ip_set_req_adt)); - return -EINVAL; - } write_lock_bh(&set->lock); - res = set->type->delip(set, - data + sizeof(struct ip_set_req_adt), - size - sizeof(struct ip_set_req_adt), - &ip); + res = set->type->delip(set, data, size); write_unlock_bh(&set->lock); return res; } static int -ip_set_testip(ip_set_id_t index, - const void *data, - u_int32_t size) +ip_set_testip(struct ip_set *set, const void *data, u_int32_t size) { - struct ip_set *set = ip_set_list[index]; - ip_set_ip_t ip; int res; IP_SET_ASSERT(set); - if (size - sizeof(struct ip_set_req_adt) != set->type->reqsize) { - ip_set_printk("data length wrong (want %lu, have %zu)", - (long unsigned)set->type->reqsize, - size - sizeof(struct ip_set_req_adt)); - return -EINVAL; - } - res = __ip_set_testip(set, - data + sizeof(struct ip_set_req_adt), - size - sizeof(struct ip_set_req_adt), - &ip); + read_lock_bh(&set->lock); + res = set->type->testip(set, data, size); + read_unlock_bh(&set->lock); return (res > 0 ? -EEXIST : res); } -static int -ip_set_bindip(ip_set_id_t index, - const void *data, - u_int32_t size) -{ - struct ip_set *set = ip_set_list[index]; - const struct ip_set_req_bind *req_bind; - ip_set_id_t binding; - ip_set_ip_t ip; - int res; - - IP_SET_ASSERT(set); - if (size < sizeof(struct ip_set_req_bind)) - return -EINVAL; - - req_bind = data; - - if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_DEFAULT)) { - /* Default binding of a set */ - const char *binding_name; - - if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN) - return -EINVAL; - - binding_name = data + sizeof(struct ip_set_req_bind); - - binding = ip_set_find_byname(binding_name); - if (binding == IP_SET_INVALID_ID) - return -ENOENT; - - write_lock_bh(&ip_set_lock); - /* Sets as binding values are referenced */ - if (set->binding != IP_SET_INVALID_ID) - __ip_set_put(set->binding); - set->binding = binding; - __ip_set_get(set->binding); - write_unlock_bh(&ip_set_lock); - - return 0; - } - binding = ip_set_find_byname(req_bind->binding); - if (binding == IP_SET_INVALID_ID) - return -ENOENT; - - res = __ip_set_testip(set, - data + sizeof(struct ip_set_req_bind), - size - sizeof(struct ip_set_req_bind), - &ip); - DP("set %s, ip: %u.%u.%u.%u, binding %s", - set->name, HIPQUAD(ip), ip_set_list[binding]->name); - - if (res >= 0) - res = ip_set_hash_add(set->id, ip, binding); - - return res; -} - -#define FOREACH_SET_DO(fn, args...) \ -({ \ - ip_set_id_t __i; \ - struct ip_set *__set; \ - \ - for (__i = 0; __i < ip_set_max; __i++) { \ - __set = ip_set_list[__i]; \ - if (__set != NULL) \ - fn(__set , ##args); \ - } \ -}) - -static inline void -__set_hash_del_byid(struct ip_set_hash *set_hash, ip_set_id_t id) -{ - if (set_hash->id == id) - __set_hash_del(set_hash); -} - -static inline void -__unbind_default(struct ip_set *set) -{ - if (set->binding != IP_SET_INVALID_ID) { - /* Sets as binding values are referenced */ - __ip_set_put(set->binding); - set->binding = IP_SET_INVALID_ID; - } -} - -static int -ip_set_unbindip(ip_set_id_t index, - const void *data, - u_int32_t size) -{ - struct ip_set *set; - const struct ip_set_req_bind *req_bind; - ip_set_ip_t ip; - int res; - - DP(""); - if (size < sizeof(struct ip_set_req_bind)) - return -EINVAL; - - req_bind = data; - - DP("%u %s", index, req_bind->binding); - if (index == IP_SET_INVALID_ID) { - /* unbind :all: */ - if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_DEFAULT)) { - /* Default binding of sets */ - write_lock_bh(&ip_set_lock); - FOREACH_SET_DO(__unbind_default); - write_unlock_bh(&ip_set_lock); - return 0; - } else if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_ALL)) { - /* Flush all bindings of all sets*/ - write_lock_bh(&ip_set_lock); - FOREACH_HASH_RW_DO(__set_hash_del); - write_unlock_bh(&ip_set_lock); - return 0; - } - DP("unreachable reached!"); - return -EINVAL; - } - - set = ip_set_list[index]; - IP_SET_ASSERT(set); - if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_DEFAULT)) { - /* Default binding of set */ - ip_set_id_t binding = ip_set_find_byindex(set->binding); - - if (binding == IP_SET_INVALID_ID) - return -ENOENT; - - write_lock_bh(&ip_set_lock); - /* Sets in hash values are referenced */ - __ip_set_put(set->binding); - set->binding = IP_SET_INVALID_ID; - write_unlock_bh(&ip_set_lock); - - return 0; - } else if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_ALL)) { - /* Flush all bindings */ - - write_lock_bh(&ip_set_lock); - FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id); - write_unlock_bh(&ip_set_lock); - return 0; - } - - res = __ip_set_testip(set, - data + sizeof(struct ip_set_req_bind), - size - sizeof(struct ip_set_req_bind), - &ip); - - DP("set %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip)); - if (res >= 0) - res = ip_set_hash_del(set->id, ip); - - return res; -} - -static int -ip_set_testbind(ip_set_id_t index, - const void *data, - u_int32_t size) -{ - struct ip_set *set = ip_set_list[index]; - const struct ip_set_req_bind *req_bind; - ip_set_id_t binding; - ip_set_ip_t ip; - int res; - - IP_SET_ASSERT(set); - if (size < sizeof(struct ip_set_req_bind)) - return -EINVAL; - - req_bind = data; - - if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_DEFAULT)) { - /* Default binding of set */ - const char *binding_name; - - if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN) - return -EINVAL; - - binding_name = data + sizeof(struct ip_set_req_bind); - - binding = ip_set_find_byname(binding_name); - if (binding == IP_SET_INVALID_ID) - return -ENOENT; - - res = (set->binding == binding) ? -EEXIST : 0; - - return res; - } - binding = ip_set_find_byname(req_bind->binding); - if (binding == IP_SET_INVALID_ID) - return -ENOENT; - - - res = __ip_set_testip(set, - data + sizeof(struct ip_set_req_bind), - size - sizeof(struct ip_set_req_bind), - &ip); - DP("set %s, ip: %u.%u.%u.%u, binding %s", - set->name, HIPQUAD(ip), ip_set_list[binding]->name); - - if (res >= 0) - res = (ip_set_find_in_hash(set->id, ip) == binding) - ? -EEXIST : 0; - - return res; -} - static struct ip_set_type * find_set_type_rlock(const char *typename) { @@ -835,7 +408,7 @@ find_free_id(const char *name, if (ip_set_list[i] == NULL) { if (*id == IP_SET_INVALID_ID) *id = *index = i; - } else if (SETNAME_EQ(name, ip_set_list[i]->name)) + } else if (STREQ(name, ip_set_list[i]->name)) /* Name clash */ return -EEXIST; } @@ -879,7 +452,6 @@ ip_set_create(const char *name, return -ENOMEM; rwlock_init(&set->lock); strncpy(set->name, name, IP_SET_MAXNAMELEN); - set->binding = IP_SET_INVALID_ID; atomic_set(&set->ref, 0); /* @@ -978,9 +550,6 @@ ip_set_destroy_set(ip_set_id_t index) IP_SET_ASSERT(set); DP("set: %s", set->name); write_lock_bh(&ip_set_lock); - FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id); - if (set->binding != IP_SET_INVALID_ID) - __ip_set_put(set->binding); ip_set_list[index] = NULL; write_unlock_bh(&ip_set_lock); @@ -1038,8 +607,13 @@ ip_set_flush(ip_set_id_t index) if (index != IP_SET_INVALID_ID) { IP_SET_ASSERT(ip_set_list[index]); ip_set_flush_set(ip_set_list[index]); - } else - FOREACH_SET_DO(ip_set_flush_set); + } else { + ip_set_id_t i; + + for (i = 0; i < ip_set_max; i++) + if (ip_set_list[i] != NULL) + ip_set_flush_set(ip_set_list[i]); + } return 0; } @@ -1056,7 +630,7 @@ ip_set_rename(ip_set_id_t index, const char *name) write_lock_bh(&ip_set_lock); for (i = 0; i < ip_set_max; i++) { if (ip_set_list[i] != NULL - && SETNAME_EQ(ip_set_list[i]->name, name)) { + && STREQ(ip_set_list[i]->name, name)) { res = -EEXIST; goto unlock; } @@ -1107,39 +681,8 @@ ip_set_swap(ip_set_id_t from_index, ip_set_id_t to_index) * List set data */ -static inline void -__set_hash_bindings_size_list(struct ip_set_hash *set_hash, - ip_set_id_t id, u_int32_t *size) -{ - if (set_hash->id == id) - *size += sizeof(struct ip_set_hash_list); -} - -static inline void -__set_hash_bindings_size_save(struct ip_set_hash *set_hash, - ip_set_id_t id, u_int32_t *size) -{ - if (set_hash->id == id) - *size += sizeof(struct ip_set_hash_save); -} - -static inline void -__set_hash_bindings(struct ip_set_hash *set_hash, - ip_set_id_t id, void *data, int *used) -{ - if (set_hash->id == id) { - struct ip_set_hash_list *hash_list = data + *used; - - hash_list->ip = set_hash->ip; - hash_list->binding = set_hash->binding; - *used += sizeof(struct ip_set_hash_list); - } -} - -static int ip_set_list_set(ip_set_id_t index, - void *data, - int *used, - int len) +static int +ip_set_list_set(ip_set_id_t index, void *data, int *used, int len) { struct ip_set *set = ip_set_list[index]; struct ip_set_list *set_list; @@ -1147,22 +690,22 @@ static int ip_set_list_set(ip_set_id_t index, /* Pointer to our header */ set_list = data + *used; - DP("set: %s, used: %d %p %p", set->name, *used, data, data + *used); + DP("set: %s, used: %d len %u %p %p", set->name, *used, len, data, data + *used); /* Get and ensure header size */ - if (*used + sizeof(struct ip_set_list) > len) + if (*used + ALIGNED(sizeof(struct ip_set_list)) > len) goto not_enough_mem; - *used += sizeof(struct ip_set_list); + *used += ALIGNED(sizeof(struct ip_set_list)); read_lock_bh(&set->lock); /* Get and ensure set specific header size */ - set_list->header_size = set->type->header_size; + set_list->header_size = ALIGNED(set->type->header_size); if (*used + set_list->header_size > len) goto unlock_set; /* Fill in the header */ set_list->index = index; - set_list->binding = set->binding; + set_list->binding = IP_SET_INVALID_ID; set_list->ref = atomic_read(&set->ref); /* Fill in set spefific header data */ @@ -1170,27 +713,18 @@ static int ip_set_list_set(ip_set_id_t index, *used += set_list->header_size; /* Get and ensure set specific members size */ - set_list->members_size = set->type->list_members_size(set); + set_list->members_size = set->type->list_members_size(set, DONT_ALIGN); if (*used + set_list->members_size > len) goto unlock_set; /* Fill in set spefific members data */ - set->type->list_members(set, data + *used); + set->type->list_members(set, data + *used, DONT_ALIGN); *used += set_list->members_size; read_unlock_bh(&set->lock); /* Bindings */ - - /* Get and ensure set specific bindings size */ set_list->bindings_size = 0; - FOREACH_HASH_DO(__set_hash_bindings_size_list, - set->id, &set_list->bindings_size); - if (*used + set_list->bindings_size > len) - goto not_enough_mem; - /* Fill in set spefific bindings data */ - FOREACH_HASH_DO(__set_hash_bindings, set->id, data, used); - return 0; unlock_set: @@ -1203,10 +737,28 @@ static int ip_set_list_set(ip_set_id_t index, /* * Save sets */ -static int ip_set_save_set(ip_set_id_t index, - void *data, - int *used, - int len) +static inline int +ip_set_save_marker(void *data, int *used, int len) +{ + struct ip_set_save *set_save; + + DP("used %u, len %u", *used, len); + /* Get and ensure header size */ + if (*used + ALIGNED(sizeof(struct ip_set_save)) > len) + return -ENOMEM; + + /* Marker: just for backward compatibility */ + set_save = data + *used; + set_save->index = IP_SET_INVALID_ID; + set_save->header_size = 0; + set_save->members_size = 0; + *used += ALIGNED(sizeof(struct ip_set_save)); + + return 0; +} + +static int +ip_set_save_set(ip_set_id_t index, void *data, int *used, int len) { struct ip_set *set; struct ip_set_save *set_save; @@ -1215,9 +767,9 @@ static int ip_set_save_set(ip_set_id_t index, set_save = data + *used; /* Get and ensure header size */ - if (*used + sizeof(struct ip_set_save) > len) + if (*used + ALIGNED(sizeof(struct ip_set_save)) > len) goto not_enough_mem; - *used += sizeof(struct ip_set_save); + *used += ALIGNED(sizeof(struct ip_set_save)); set = ip_set_list[index]; DP("set: %s, used: %d(%d) %p %p", set->name, *used, len, @@ -1225,13 +777,13 @@ static int ip_set_save_set(ip_set_id_t index, read_lock_bh(&set->lock); /* Get and ensure set specific header size */ - set_save->header_size = set->type->header_size; + set_save->header_size = ALIGNED(set->type->header_size); if (*used + set_save->header_size > len) goto unlock_set; /* Fill in the header */ set_save->index = index; - set_save->binding = set->binding; + set_save->binding = IP_SET_INVALID_ID; /* Fill in set spefific header data */ set->type->list_header(set, data + *used); @@ -1240,12 +792,12 @@ static int ip_set_save_set(ip_set_id_t index, DP("set header filled: %s, used: %d(%lu) %p %p", set->name, *used, (unsigned long)set_save->header_size, data, data + *used); /* Get and ensure set specific members size */ - set_save->members_size = set->type->list_members_size(set); + set_save->members_size = set->type->list_members_size(set, DONT_ALIGN); if (*used + set_save->members_size > len) goto unlock_set; /* Fill in set spefific members data */ - set->type->list_members(set, data + *used); + set->type->list_members(set, data + *used, DONT_ALIGN); *used += set_save->members_size; read_unlock_bh(&set->lock); DP("set members filled: %s, used: %d(%lu) %p %p", set->name, *used, @@ -1259,69 +811,15 @@ static int ip_set_save_set(ip_set_id_t index, return -EAGAIN; } -static inline void -__set_hash_save_bindings(struct ip_set_hash *set_hash, - ip_set_id_t id, - void *data, - int *used, - int len, - int *res) -{ - if (*res == 0 - && (id == IP_SET_INVALID_ID || set_hash->id == id)) { - struct ip_set_hash_save *hash_save = data + *used; - /* Ensure bindings size */ - if (*used + sizeof(struct ip_set_hash_save) > len) { - *res = -ENOMEM; - return; - } - hash_save->id = set_hash->id; - hash_save->ip = set_hash->ip; - hash_save->binding = set_hash->binding; - *used += sizeof(struct ip_set_hash_save); - } -} - -static int ip_set_save_bindings(ip_set_id_t index, - void *data, - int *used, - int len) -{ - int res = 0; - struct ip_set_save *set_save; - - DP("used %u, len %u", *used, len); - /* Get and ensure header size */ - if (*used + sizeof(struct ip_set_save) > len) - return -ENOMEM; - - /* Marker */ - set_save = data + *used; - set_save->index = IP_SET_INVALID_ID; - set_save->header_size = 0; - set_save->members_size = 0; - *used += sizeof(struct ip_set_save); - - DP("marker added used %u, len %u", *used, len); - /* Fill in bindings data */ - if (index != IP_SET_INVALID_ID) - /* Sets are identified by id in hash */ - index = ip_set_list[index]->id; - FOREACH_HASH_DO(__set_hash_save_bindings, index, data, used, len, &res); - - return res; -} - /* * Restore sets */ -static int ip_set_restore(void *data, - int len) +static int +ip_set_restore(void *data, int len) { int res = 0; int line = 0, used = 0, members_size; struct ip_set *set; - struct ip_set_hash_save *hash_save; struct ip_set_restore *set_restore; ip_set_id_t index; @@ -1329,12 +827,12 @@ static int ip_set_restore(void *data, while (1) { line++; - DP("%d %zu %d", used, sizeof(struct ip_set_restore), len); + DP("%d %zu %d", used, ALIGNED(sizeof(struct ip_set_restore)), len); /* Get and ensure header size */ - if (used + sizeof(struct ip_set_restore) > len) + if (used + ALIGNED(sizeof(struct ip_set_restore)) > len) return line; set_restore = data + used; - used += sizeof(struct ip_set_restore); + used += ALIGNED(sizeof(struct ip_set_restore)); /* Ensure data size */ if (used @@ -1345,7 +843,7 @@ static int ip_set_restore(void *data, /* Check marker */ if (set_restore->index == IP_SET_INVALID_ID) { line--; - goto bindings; + goto finish; } /* Try to create the set */ @@ -1358,7 +856,7 @@ static int ip_set_restore(void *data, if (res != 0) return line; - used += set_restore->header_size; + used += ALIGNED(set_restore->header_size); index = ip_set_find_byindex(set_restore->index); DP("index %u, restore_index %u", index, set_restore->index); @@ -1370,16 +868,16 @@ static int ip_set_restore(void *data, DP("members_size %lu reqsize %lu", (unsigned long)set_restore->members_size, (unsigned long)set->type->reqsize); - while (members_size + set->type->reqsize <= + while (members_size + ALIGNED(set->type->reqsize) <= set_restore->members_size) { line++; DP("members: %d, line %d", members_size, line); - res = __ip_set_addip(index, + res = ip_set_addip(set, data + used + members_size, set->type->reqsize); if (!(res == 0 || res == -EEXIST)) return line; - members_size += set->type->reqsize; + members_size += ALIGNED(set->type->reqsize); } DP("members_size %lu %d", @@ -1389,45 +887,7 @@ static int ip_set_restore(void *data, used += set_restore->members_size; } - bindings: - /* Loop to restore bindings */ - while (used < len) { - line++; - - DP("restore binding, line %u", line); - /* Get and ensure size */ - if (used + sizeof(struct ip_set_hash_save) > len) - return line; - hash_save = data + used; - used += sizeof(struct ip_set_hash_save); - - /* hash_save->id is used to store the index */ - index = ip_set_find_byindex(hash_save->id); - DP("restore binding index %u, id %u, %u -> %u", - index, hash_save->id, hash_save->ip, hash_save->binding); - if (index != hash_save->id) - return line; - if (ip_set_find_byindex(hash_save->binding) == IP_SET_INVALID_ID) { - DP("corrupt binding set index %u", hash_save->binding); - return line; - } - set = ip_set_list[hash_save->id]; - /* Null valued IP means default binding */ - if (hash_save->ip) - res = ip_set_hash_add(set->id, - hash_save->ip, - hash_save->binding); - else { - IP_SET_ASSERT(set->binding == IP_SET_INVALID_ID); - write_lock_bh(&ip_set_lock); - set->binding = hash_save->binding; - __ip_set_get(set->binding); - write_unlock_bh(&ip_set_lock); - DP("default binding: %u", set->binding); - } - if (res != 0) - return line; - } + finish: if (used != len) return line; @@ -1439,17 +899,17 @@ ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len) { void *data; int res = 0; /* Assume OK */ + size_t offset; unsigned *op; struct ip_set_req_adt *req_adt; ip_set_id_t index = IP_SET_INVALID_ID; - int (*adtfn)(ip_set_id_t index, + int (*adtfn)(struct ip_set *set, const void *data, u_int32_t size); struct fn_table { - int (*fn)(ip_set_id_t index, + int (*fn)(struct ip_set *set, const void *data, u_int32_t size); } adtfn_table[] = - { { ip_set_addip }, { ip_set_delip }, { ip_set_testip}, - { ip_set_bindip}, { ip_set_unbindip }, { ip_set_testbind }, + { { ip_set_addip }, { ip_set_delip }, { ip_set_testip}, }; DP("optval=%d, user=%p, len=%d", optval, user, len); @@ -1482,19 +942,22 @@ ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len) if (*op < IP_SET_OP_VERSION) { /* Check the version at the beginning of operations */ struct ip_set_req_version *req_version = data; - if (req_version->version != IP_SET_PROTOCOL_VERSION) { + if (!(req_version->version == IP_SET_PROTOCOL_UNALIGNED + || req_version->version == IP_SET_PROTOCOL_VERSION)) { res = -EPROTO; goto done; } + protocol_version = req_version->version; } switch (*op) { case IP_SET_OP_CREATE:{ struct ip_set_req_create *req_create = data; + offset = ALIGNED(sizeof(struct ip_set_req_create)); - if (len < sizeof(struct ip_set_req_create)) { + if (len < offset) { ip_set_printk("short CREATE data (want >=%zu, got %u)", - sizeof(struct ip_set_req_create), len); + offset, len); res = -EINVAL; goto done; } @@ -1503,8 +966,8 @@ ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len) res = ip_set_create(req_create->name, req_create->typename, IP_SET_INVALID_ID, - data + sizeof(struct ip_set_req_create), - len - sizeof(struct ip_set_req_create)); + data + offset, + len - offset); goto done; } case IP_SET_OP_DESTROY:{ @@ -1516,7 +979,7 @@ ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len) res = -EINVAL; goto done; } - if (SETNAME_EQ(req_destroy->name, IPSET_TOKEN_ALL)) { + if (STREQ(req_destroy->name, IPSET_TOKEN_ALL)) { /* Destroy all sets */ index = IP_SET_INVALID_ID; } else { @@ -1541,7 +1004,7 @@ ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len) res = -EINVAL; goto done; } - if (SETNAME_EQ(req_flush->name, IPSET_TOKEN_ALL)) { + if (STREQ(req_flush->name, IPSET_TOKEN_ALL)) { /* Flush all sets */ index = IP_SET_INVALID_ID; } else { @@ -1609,30 +1072,40 @@ ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len) } /* There we may have add/del/test/bind/unbind/test_bind operations */ - if (*op < IP_SET_OP_ADD_IP || *op > IP_SET_OP_TEST_BIND_SET) { + if (*op < IP_SET_OP_ADD_IP || *op > IP_SET_OP_TEST_IP) { res = -EBADMSG; goto done; } adtfn = adtfn_table[*op - IP_SET_OP_ADD_IP].fn; - if (len < sizeof(struct ip_set_req_adt)) { + if (len < ALIGNED(sizeof(struct ip_set_req_adt))) { ip_set_printk("short data in adt request (want >=%zu, got %u)", - sizeof(struct ip_set_req_adt), len); + ALIGNED(sizeof(struct ip_set_req_adt)), len); res = -EINVAL; goto done; } req_adt = data; - /* -U :all: :all:|:default: uses IP_SET_INVALID_ID */ - if (!(*op == IP_SET_OP_UNBIND_SET - && req_adt->index == IP_SET_INVALID_ID)) { - index = ip_set_find_byindex(req_adt->index); - if (index == IP_SET_INVALID_ID) { - res = -ENOENT; + index = ip_set_find_byindex(req_adt->index); + if (index == IP_SET_INVALID_ID) { + res = -ENOENT; + goto done; + } + do { + struct ip_set *set = ip_set_list[index]; + size_t offset = ALIGNED(sizeof(struct ip_set_req_adt)); + + IP_SET_ASSERT(set); + + if (len - offset != set->type->reqsize) { + ip_set_printk("data length wrong (want %lu, have %zu)", + (long unsigned)set->type->reqsize, + len - offset); + res = -EINVAL; goto done; } - } - res = adtfn(index, data, len); + res = adtfn(set, data + offset, len - offset); + } while (0); done: up(&ip_set_app_mutex); @@ -1682,10 +1155,12 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len) if (*op < IP_SET_OP_VERSION) { /* Check the version at the beginning of operations */ struct ip_set_req_version *req_version = data; - if (req_version->version != IP_SET_PROTOCOL_VERSION) { + if (!(req_version->version == IP_SET_PROTOCOL_UNALIGNED + || req_version->version == IP_SET_PROTOCOL_VERSION)) { res = -EPROTO; goto done; } + protocol_version = req_version->version; } switch (*op) { @@ -1768,7 +1243,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len) goto done; } - if (SETNAME_EQ(req_max_sets->set.name, IPSET_TOKEN_ALL)) { + if (STREQ(req_max_sets->set.name, IPSET_TOKEN_ALL)) { req_max_sets->set.index = IP_SET_INVALID_ID; } else { req_max_sets->set.name[IP_SET_MAXNAMELEN - 1] = '\0'; @@ -1795,20 +1270,21 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len) ip_set_id_t i; int used; - if (*len < sizeof(struct ip_set_req_setnames)) { + if (*len < ALIGNED(sizeof(struct ip_set_req_setnames))) { ip_set_printk("short LIST_SIZE (want >=%zu, got %d)", - sizeof(struct ip_set_req_setnames), *len); + ALIGNED(sizeof(struct ip_set_req_setnames)), + *len); res = -EINVAL; goto done; } req_setnames->size = 0; - used = sizeof(struct ip_set_req_setnames); + used = ALIGNED(sizeof(struct ip_set_req_setnames)); for (i = 0; i < ip_set_max; i++) { if (ip_set_list[i] == NULL) continue; name_list = data + used; - used += sizeof(struct ip_set_name_list); + used += ALIGNED(sizeof(struct ip_set_name_list)); if (used > copylen) { res = -EAGAIN; goto done; @@ -1830,27 +1306,12 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len) || req_setnames->index == i)) continue; /* Update size */ - switch (*op) { - case IP_SET_OP_LIST_SIZE: { - req_setnames->size += sizeof(struct ip_set_list) - + set->type->header_size - + set->type->list_members_size(set); - /* Sets are identified by id in the hash */ - FOREACH_HASH_DO(__set_hash_bindings_size_list, - set->id, &req_setnames->size); - break; - } - case IP_SET_OP_SAVE_SIZE: { - req_setnames->size += sizeof(struct ip_set_save) - + set->type->header_size - + set->type->list_members_size(set); - FOREACH_HASH_DO(__set_hash_bindings_size_save, - set->id, &req_setnames->size); - break; - } - default: - break; - } + req_setnames->size += + (*op == IP_SET_OP_LIST_SIZE ? + ALIGNED(sizeof(struct ip_set_list)) : + ALIGNED(sizeof(struct ip_set_save))) + + ALIGNED(set->type->header_size) + + set->type->list_members_size(set, DONT_ALIGN); } if (copylen != used) { res = -EAGAIN; @@ -1933,7 +1394,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len) res = ip_set_save_set(index, data, &used, *len); } if (res == 0) - res = ip_set_save_bindings(index, data, &used, *len); + res = ip_set_save_marker(data, &used, *len); if (res != 0) goto done; @@ -1945,17 +1406,16 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len) } case IP_SET_OP_RESTORE: { struct ip_set_req_setnames *req_restore = data; + size_t offset = ALIGNED(sizeof(struct ip_set_req_setnames)); int line; - if (*len < sizeof(struct ip_set_req_setnames) - || *len != req_restore->size) { + if (*len < offset || *len != req_restore->size) { ip_set_printk("invalid RESTORE (want =%lu, got %d)", (long unsigned)req_restore->size, *len); res = -EINVAL; goto done; } - line = ip_set_restore(data + sizeof(struct ip_set_req_setnames), - req_restore->size - sizeof(struct ip_set_req_setnames)); + line = ip_set_restore(data + offset, req_restore->size - offset); DP("ip_set_restore: %d", line); if (line != 0) { res = -EAGAIN; @@ -2001,40 +1461,32 @@ static struct nf_sockopt_ops so_set = { #endif }; -static int max_sets, hash_size; +static int max_sets; module_param(max_sets, int, 0600); MODULE_PARM_DESC(max_sets, "maximal number of sets"); -module_param(hash_size, int, 0600); -MODULE_PARM_DESC(hash_size, "hash size for bindings"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jozsef Kadlecsik "); MODULE_DESCRIPTION("module implementing core IP set support"); -static int __init ip_set_init(void) +static int __init +ip_set_init(void) { int res; - ip_set_id_t i; - get_random_bytes(&ip_set_hash_random, 4); + init_MUTEX(&ip_set_app_mutex); + if (max_sets) ip_set_max = max_sets; + if (ip_set_max >= IP_SET_INVALID_ID) + ip_set_max = IP_SET_INVALID_ID - 1; + ip_set_list = vmalloc(sizeof(struct ip_set *) * ip_set_max); if (!ip_set_list) { printk(KERN_ERR "Unable to create ip_set_list\n"); return -ENOMEM; } memset(ip_set_list, 0, sizeof(struct ip_set *) * ip_set_max); - if (hash_size) - ip_set_bindings_hash_size = hash_size; - ip_set_hash = vmalloc(sizeof(struct list_head) * ip_set_bindings_hash_size); - if (!ip_set_hash) { - printk(KERN_ERR "Unable to create ip_set_hash\n"); - vfree(ip_set_list); - return -ENOMEM; - } - for (i = 0; i < ip_set_bindings_hash_size; i++) - INIT_LIST_HEAD(&ip_set_hash[i]); INIT_LIST_HEAD(&set_type_list); @@ -2042,19 +1494,19 @@ static int __init ip_set_init(void) if (res != 0) { ip_set_printk("SO_SET registry failed: %d", res); vfree(ip_set_list); - vfree(ip_set_hash); return res; } - + + printk("ip_set version %u loaded\n", IP_SET_PROTOCOL_VERSION); return 0; } -static void __exit ip_set_fini(void) +static void __exit +ip_set_fini(void) { /* There can't be any existing set or binding */ nf_unregister_sockopt(&so_set); vfree(ip_set_list); - vfree(ip_set_hash); DP("these are the famous last words"); } diff --git a/kernel/ip_set_iphash.c b/kernel/ip_set_iphash.c index aac3eec..1accbe3 100644 --- a/kernel/ip_set_iphash.c +++ b/kernel/ip_set_iphash.c @@ -25,22 +25,21 @@ static int limit = MAX_RANGE; static inline __u32 -iphash_id(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +iphash_id(struct ip_set *set, ip_set_ip_t ip) { struct ip_set_iphash *map = set->data; __u32 id; u_int16_t i; ip_set_ip_t *elem; - *hash_ip = ip & map->netmask; - DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u, %u.%u.%u.%u", - set->name, HIPQUAD(ip), HIPQUAD(*hash_ip), HIPQUAD(map->netmask)); - + + ip &= map->netmask; + DP("set: %s, ip:%u.%u.%u.%u", set->name, HIPQUAD(ip)); for (i = 0; i < map->probes; i++) { - id = jhash_ip(map, i, *hash_ip) % map->hashsize; + id = jhash_ip(map, i, ip) % map->hashsize; DP("hash key: %u", id); elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id); - if (*elem == *hash_ip) + if (*elem == ip) return id; /* No shortcut - there can be deleted entries. */ } @@ -48,9 +47,9 @@ iphash_id(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) } static inline int -iphash_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +iphash_test(struct ip_set *set, ip_set_ip_t ip) { - return (ip && iphash_id(set, hash_ip, ip) != UINT_MAX); + return (ip && iphash_id(set, ip) != UINT_MAX); } #define KADT_CONDITION @@ -84,16 +83,15 @@ __iphash_add(struct ip_set_iphash *map, ip_set_ip_t *ip) } static inline int -iphash_add(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +iphash_add(struct ip_set *set, ip_set_ip_t ip) { struct ip_set_iphash *map = set->data; if (!ip || map->elements >= limit) return -ERANGE; - *hash_ip = ip & map->netmask; - - return __iphash_add(map, hash_ip); + ip &= map->netmask; + return __iphash_add(map, &ip); } UADT(iphash, add) @@ -108,7 +106,7 @@ __iphash_retry(struct ip_set_iphash *tmp, struct ip_set_iphash *map) HASH_RETRY(iphash, ip_set_ip_t) static inline int -iphash_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +iphash_del(struct ip_set *set, ip_set_ip_t ip) { struct ip_set_iphash *map = set->data; ip_set_ip_t id, *elem; @@ -116,7 +114,7 @@ iphash_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) if (!ip) return -ERANGE; - id = iphash_id(set, hash_ip, ip); + id = iphash_id(set, ip); if (id == UINT_MAX) return -EEXIST; diff --git a/kernel/ip_set_ipmap.c b/kernel/ip_set_ipmap.c index 442f0d3..be3c538 100644 --- a/kernel/ip_set_ipmap.c +++ b/kernel/ip_set_ipmap.c @@ -22,21 +22,19 @@ static inline ip_set_ip_t ip_to_id(const struct ip_set_ipmap *map, ip_set_ip_t ip) { - return (ip - map->first_ip)/map->hosts; + return ((ip & map->netmask) - map->first_ip)/map->hosts; } static inline int -ipmap_test(const struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +ipmap_test(const struct ip_set *set, ip_set_ip_t ip) { const struct ip_set_ipmap *map = set->data; if (ip < map->first_ip || ip > map->last_ip) return -ERANGE; - *hash_ip = ip & map->netmask; - DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u", - set->name, HIPQUAD(ip), HIPQUAD(*hash_ip)); - return !!test_bit(ip_to_id(map, *hash_ip), map->members); + DP("set: %s, ip:%u.%u.%u.%u", set->name, HIPQUAD(ip)); + return !!test_bit(ip_to_id(map, ip), map->members); } #define KADT_CONDITION @@ -45,16 +43,15 @@ UADT(ipmap, test) KADT(ipmap, test, ipaddr) static inline int -ipmap_add(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +ipmap_add(struct ip_set *set, ip_set_ip_t ip) { struct ip_set_ipmap *map = set->data; if (ip < map->first_ip || ip > map->last_ip) return -ERANGE; - *hash_ip = ip & map->netmask; - DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip)); - if (test_and_set_bit(ip_to_id(map, *hash_ip), map->members)) + DP("set: %s, ip:%u.%u.%u.%u", set->name, HIPQUAD(ip)); + if (test_and_set_bit(ip_to_id(map, ip), map->members)) return -EEXIST; return 0; @@ -64,16 +61,15 @@ UADT(ipmap, add) KADT(ipmap, add, ipaddr) static inline int -ipmap_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +ipmap_del(struct ip_set *set, ip_set_ip_t ip) { struct ip_set_ipmap *map = set->data; if (ip < map->first_ip || ip > map->last_ip) return -ERANGE; - *hash_ip = ip & map->netmask; - DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip)); - if (!test_and_clear_bit(ip_to_id(map, *hash_ip), map->members)) + DP("set: %s, ip:%u.%u.%u.%u", set->name, HIPQUAD(ip)); + if (!test_and_clear_bit(ip_to_id(map, ip), map->members)) return -EEXIST; return 0; @@ -130,8 +126,28 @@ __ipmap_list_header(const struct ip_set_ipmap *map, } BITMAP_LIST_HEADER(ipmap) -BITMAP_LIST_MEMBERS_SIZE(ipmap) -BITMAP_LIST_MEMBERS(ipmap) +BITMAP_LIST_MEMBERS_SIZE(ipmap, ip_set_ip_t, map->sizeid, + test_bit(i, map->members)) + +static void +ipmap_list_members(const struct ip_set *set, void *data, char dont_align) +{ + const struct ip_set_ipmap *map = set->data; + uint32_t i, n = 0; + ip_set_ip_t *d; + + if (dont_align) { + memcpy(data, map->members, map->size); + return; + } + + for (i = 0; i < map->sizeid; i++) + if (test_bit(i, map->members)) { + d = data + n * IPSET_ALIGN(sizeof(ip_set_ip_t)); + *d = map->first_ip + i * map->hosts; + n++; + } +} IP_SET_TYPE(ipmap, IPSET_TYPE_IP | IPSET_DATA_SINGLE) diff --git a/kernel/ip_set_ipporthash.c b/kernel/ip_set_ipporthash.c index c41c0a8..36e68b0 100644 --- a/kernel/ip_set_ipporthash.c +++ b/kernel/ip_set_ipporthash.c @@ -28,26 +28,23 @@ static int limit = MAX_RANGE; static inline __u32 -ipporthash_id(struct ip_set *set, ip_set_ip_t *hash_ip, - ip_set_ip_t ip, ip_set_ip_t port) +ipporthash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port) { struct ip_set_ipporthash *map = set->data; __u32 id; u_int16_t i; ip_set_ip_t *elem; - *hash_ip = pack_ip_port(map, ip, port); + ip = pack_ip_port(map, ip, port); - DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u", - set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip)); - if (!*hash_ip) + if (!ip) return UINT_MAX; for (i = 0; i < map->probes; i++) { - id = jhash_ip(map, i, *hash_ip) % map->hashsize; + id = jhash_ip(map, i, ip) % map->hashsize; DP("hash key: %u", id); elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id); - if (*elem == *hash_ip) + if (*elem == ip) return id; /* No shortcut - there can be deleted entries. */ } @@ -55,24 +52,23 @@ ipporthash_id(struct ip_set *set, ip_set_ip_t *hash_ip, } static inline int -ipporthash_test(struct ip_set *set, ip_set_ip_t *hash_ip, - ip_set_ip_t ip, ip_set_ip_t port) +ipporthash_test(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port) { struct ip_set_ipporthash *map = set->data; if (ip < map->first_ip || ip > map->last_ip) return -ERANGE; - return (ipporthash_id(set, hash_ip, ip, port) != UINT_MAX); + return (ipporthash_id(set, ip, port) != UINT_MAX); } #define KADT_CONDITION \ ip_set_ip_t port; \ \ - if (flags[index+1] == 0) \ + if (flags[1] == 0) \ return 0; \ \ - port = get_port(skb, flags[index+1]); \ + port = get_port(skb, flags++); \ \ if (port == INVALID_PORT) \ return 0; @@ -106,8 +102,7 @@ __ipporthash_add(struct ip_set_ipporthash *map, ip_set_ip_t *ip) } static inline int -ipporthash_add(struct ip_set *set, ip_set_ip_t *hash_ip, - ip_set_ip_t ip, ip_set_ip_t port) +ipporthash_add(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port) { struct ip_set_ipporthash *map = set->data; if (map->elements > limit) @@ -115,12 +110,12 @@ ipporthash_add(struct ip_set *set, ip_set_ip_t *hash_ip, if (ip < map->first_ip || ip > map->last_ip) return -ERANGE; - *hash_ip = pack_ip_port(map, ip, port); + ip = pack_ip_port(map, ip, port); - if (!*hash_ip) + if (!ip) return -ERANGE; - return __ipporthash_add(map, hash_ip); + return __ipporthash_add(map, &ip); } UADT(ipporthash, add, req->port) @@ -137,8 +132,7 @@ __ipporthash_retry(struct ip_set_ipporthash *tmp, HASH_RETRY(ipporthash, ip_set_ip_t) static inline int -ipporthash_del(struct ip_set *set, ip_set_ip_t *hash_ip, - ip_set_ip_t ip, ip_set_ip_t port) +ipporthash_del(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port) { struct ip_set_ipporthash *map = set->data; ip_set_ip_t id; @@ -147,7 +141,7 @@ ipporthash_del(struct ip_set *set, ip_set_ip_t *hash_ip, if (ip < map->first_ip || ip > map->last_ip) return -ERANGE; - id = ipporthash_id(set, hash_ip, ip, port); + id = ipporthash_id(set, ip, port); if (id == UINT_MAX) return -EEXIST; diff --git a/kernel/ip_set_ipportiphash.c b/kernel/ip_set_ipportiphash.c index 166bec4..5fe00f1 100644 --- a/kernel/ip_set_ipportiphash.c +++ b/kernel/ip_set_ipportiphash.c @@ -31,7 +31,7 @@ static int limit = MAX_RANGE; jhash_2words(ipport, ip1, *(map->initval + i)) static inline __u32 -ipportiphash_id(struct ip_set *set, ip_set_ip_t *hash_ip, +ipportiphash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1) { struct ip_set_ipportiphash *map = set->data; @@ -39,17 +39,15 @@ ipportiphash_id(struct ip_set *set, ip_set_ip_t *hash_ip, u_int16_t i; struct ipportip *elem; - *hash_ip = pack_ip_port(map, ip, port); - DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u", - set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip)); - if (!(*hash_ip || ip1)) + ip = pack_ip_port(map, ip, port); + if (!(ip || ip1)) return UINT_MAX; for (i = 0; i < map->probes; i++) { - id = jhash_ip2(map, i, *hash_ip, ip1) % map->hashsize; + id = jhash_ip2(map, i, ip, ip1) % map->hashsize; DP("hash key: %u", id); elem = HARRAY_ELEM(map->members, struct ipportip *, id); - if (elem->ip == *hash_ip && elem->ip1 == ip1) + if (elem->ip == ip && elem->ip1 == ip1) return id; /* No shortcut - there can be deleted entries. */ } @@ -57,7 +55,7 @@ ipportiphash_id(struct ip_set *set, ip_set_ip_t *hash_ip, } static inline int -ipportiphash_test(struct ip_set *set, ip_set_ip_t *hash_ip, +ipportiphash_test(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1) { struct ip_set_ipportiphash *map = set->data; @@ -65,17 +63,17 @@ ipportiphash_test(struct ip_set *set, ip_set_ip_t *hash_ip, if (ip < map->first_ip || ip > map->last_ip) return -ERANGE; - return (ipportiphash_id(set, hash_ip, ip, port, ip1) != UINT_MAX); + return (ipportiphash_id(set, ip, port, ip1) != UINT_MAX); } #define KADT_CONDITION \ ip_set_ip_t port, ip1; \ \ - if (flags[index+2] == 0) \ + if (flags[2] == 0) \ return 0; \ \ - port = get_port(skb, flags[index+1]); \ - ip1 = ipaddr(skb, flags[index+2]); \ + port = get_port(skb, flags++); \ + ip1 = ipaddr(skb, flags++); \ \ if (port == INVALID_PORT) \ return 0; @@ -85,23 +83,23 @@ KADT(ipportiphash, test, ipaddr, port, ip1) static inline int __ipportip_add(struct ip_set_ipportiphash *map, - ip_set_ip_t hash_ip, ip_set_ip_t ip1) + ip_set_ip_t ip, ip_set_ip_t ip1) { __u32 probe; u_int16_t i; struct ipportip *elem, *slot = NULL; for (i = 0; i < map->probes; i++) { - probe = jhash_ip2(map, i, hash_ip, ip1) % map->hashsize; + probe = jhash_ip2(map, i, ip, ip1) % map->hashsize; elem = HARRAY_ELEM(map->members, struct ipportip *, probe); - if (elem->ip == hash_ip && elem->ip1 == ip1) + if (elem->ip == ip && elem->ip1 == ip1) return -EEXIST; if (!(slot || elem->ip || elem->ip1)) slot = elem; /* There can be deleted entries, must check all slots */ } if (slot) { - slot->ip = hash_ip; + slot->ip = ip; slot->ip1 = ip1; map->elements++; return 0; @@ -118,7 +116,7 @@ __ipportiphash_add(struct ip_set_ipportiphash *map, } static inline int -ipportiphash_add(struct ip_set *set, ip_set_ip_t *hash_ip, +ipportiphash_add(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1) { struct ip_set_ipportiphash *map = set->data; @@ -128,11 +126,11 @@ ipportiphash_add(struct ip_set *set, ip_set_ip_t *hash_ip, if (ip < map->first_ip || ip > map->last_ip) return -ERANGE; - *hash_ip = pack_ip_port(map, ip, port); - if (!(*hash_ip || ip1)) + ip = pack_ip_port(map, ip, port); + if (!(ip || ip1)) return -ERANGE; - return __ipportip_add(map, *hash_ip, ip1); + return __ipportip_add(map, ip, ip1); } UADT(ipportiphash, add, req->port, req->ip1) @@ -149,7 +147,7 @@ __ipportiphash_retry(struct ip_set_ipportiphash *tmp, HASH_RETRY2(ipportiphash, struct ipportip) static inline int -ipportiphash_del(struct ip_set *set, ip_set_ip_t *hash_ip, +ipportiphash_del(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1) { struct ip_set_ipportiphash *map = set->data; @@ -159,7 +157,7 @@ ipportiphash_del(struct ip_set *set, ip_set_ip_t *hash_ip, if (ip < map->first_ip || ip > map->last_ip) return -ERANGE; - id = ipportiphash_id(set, hash_ip, ip, port, ip1); + id = ipportiphash_id(set, ip, port, ip1); if (id == UINT_MAX) return -EEXIST; diff --git a/kernel/ip_set_ipportnethash.c b/kernel/ip_set_ipportnethash.c index 45e53ed..9179184 100644 --- a/kernel/ip_set_ipportnethash.c +++ b/kernel/ip_set_ipportnethash.c @@ -31,7 +31,7 @@ static int limit = MAX_RANGE; jhash_2words(ipport, ip1, *(map->initval + i)) static inline __u32 -ipportnethash_id_cidr(struct ip_set *set, ip_set_ip_t *hash_ip, +ipportnethash_id_cidr(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1, uint8_t cidr) { @@ -40,18 +40,16 @@ ipportnethash_id_cidr(struct ip_set *set, ip_set_ip_t *hash_ip, u_int16_t i; struct ipportip *elem; - *hash_ip = pack_ip_port(map, ip, port); - DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u", - set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip)); + ip = pack_ip_port(map, ip, port); ip1 = pack_ip_cidr(ip1, cidr); - if (!(*hash_ip || ip1)) + if (!(ip || ip1)) return UINT_MAX; for (i = 0; i < map->probes; i++) { - id = jhash_ip2(map, i, *hash_ip, ip1) % map->hashsize; + id = jhash_ip2(map, i, ip, ip1) % map->hashsize; DP("hash key: %u", id); elem = HARRAY_ELEM(map->members, struct ipportip *, id); - if (elem->ip == *hash_ip && elem->ip1 == ip1) + if (elem->ip == ip && elem->ip1 == ip1) return id; /* No shortcut - there can be deleted entries. */ } @@ -59,7 +57,7 @@ ipportnethash_id_cidr(struct ip_set *set, ip_set_ip_t *hash_ip, } static inline __u32 -ipportnethash_id(struct ip_set *set, ip_set_ip_t *hash_ip, +ipportnethash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1) { struct ip_set_ipportnethash *map = set->data; @@ -67,8 +65,7 @@ ipportnethash_id(struct ip_set *set, ip_set_ip_t *hash_ip, int i; for (i = 0; i < 30 && map->cidr[i]; i++) { - id = ipportnethash_id_cidr(set, hash_ip, ip, port, ip1, - map->cidr[i]); + id = ipportnethash_id_cidr(set, ip, port, ip1, map->cidr[i]); if (id != UINT_MAX) break; } @@ -76,7 +73,7 @@ ipportnethash_id(struct ip_set *set, ip_set_ip_t *hash_ip, } static inline int -ipportnethash_test_cidr(struct ip_set *set, ip_set_ip_t *hash_ip, +ipportnethash_test_cidr(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1, uint8_t cidr) { @@ -85,12 +82,11 @@ ipportnethash_test_cidr(struct ip_set *set, ip_set_ip_t *hash_ip, if (ip < map->first_ip || ip > map->last_ip) return -ERANGE; - return (ipportnethash_id_cidr(set, hash_ip, ip, port, ip1, - cidr) != UINT_MAX); + return (ipportnethash_id_cidr(set, ip, port, ip1, cidr) != UINT_MAX); } static inline int -ipportnethash_test(struct ip_set *set, ip_set_ip_t *hash_ip, +ipportnethash_test(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1) { struct ip_set_ipportnethash *map = set->data; @@ -98,32 +94,30 @@ ipportnethash_test(struct ip_set *set, ip_set_ip_t *hash_ip, if (ip < map->first_ip || ip > map->last_ip) return -ERANGE; - return (ipportnethash_id(set, hash_ip, ip, port, ip1) != UINT_MAX); + return (ipportnethash_id(set, ip, port, ip1) != UINT_MAX); } static int -ipportnethash_utest(struct ip_set *set, const void *data, u_int32_t size, - ip_set_ip_t *hash_ip) +ipportnethash_utest(struct ip_set *set, const void *data, u_int32_t size) { const struct ip_set_req_ipportnethash *req = data; if (req->cidr <= 0 || req->cidr > 32) return -EINVAL; return (req->cidr == 32 - ? ipportnethash_test(set, hash_ip, req->ip, req->port, - req->ip1) - : ipportnethash_test_cidr(set, hash_ip, req->ip, req->port, + ? ipportnethash_test(set, req->ip, req->port, req->ip1) + : ipportnethash_test_cidr(set, req->ip, req->port, req->ip1, req->cidr)); } #define KADT_CONDITION \ ip_set_ip_t port, ip1; \ \ - if (flags[index+2] == 0) \ + if (flags[2] == 0) \ return 0; \ \ - port = get_port(skb, flags[index+1]); \ - ip1 = ipaddr(skb, flags[index+2]); \ + port = get_port(skb, flags++); \ + ip1 = ipaddr(skb, flags++); \ \ if (port == INVALID_PORT) \ return 0; @@ -132,23 +126,23 @@ KADT(ipportnethash, test, ipaddr, port, ip1) static inline int __ipportnet_add(struct ip_set_ipportnethash *map, - ip_set_ip_t hash_ip, ip_set_ip_t ip1) + ip_set_ip_t ip, ip_set_ip_t ip1) { __u32 probe; u_int16_t i; struct ipportip *elem, *slot = NULL; for (i = 0; i < map->probes; i++) { - probe = jhash_ip2(map, i, hash_ip, ip1) % map->hashsize; + probe = jhash_ip2(map, i, ip, ip1) % map->hashsize; elem = HARRAY_ELEM(map->members, struct ipportip *, probe); - if (elem->ip == hash_ip && elem->ip1 == ip1) + if (elem->ip == ip && elem->ip1 == ip1) return -EEXIST; if (!(slot || elem->ip || elem->ip1)) slot = elem; /* There can be deleted entries, must check all slots */ } if (slot) { - slot->ip = hash_ip; + slot->ip = ip; slot->ip1 = ip1; map->elements++; return 0; @@ -165,7 +159,7 @@ __ipportnethash_add(struct ip_set_ipportnethash *map, } static inline int -ipportnethash_add(struct ip_set *set, ip_set_ip_t *hash_ip, +ipportnethash_add(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1, uint8_t cidr) { @@ -182,12 +176,12 @@ ipportnethash_add(struct ip_set *set, ip_set_ip_t *hash_ip, if (map->nets[cidr-1] == UINT16_MAX) return -ERANGE; - *hash_ip = pack_ip_port(map, ip, port); + ip = pack_ip_port(map, ip, port); ip1 = pack_ip_cidr(ip1, cidr); - if (!(*hash_ip || ip1)) + if (!(ip || ip1)) return -ERANGE; - ret =__ipportnet_add(map, *hash_ip, ip1); + ret =__ipportnet_add(map, ip, ip1); if (ret == 0) { if (!map->nets[cidr-1]++) add_cidr_size(map->cidr, cidr); @@ -202,11 +196,11 @@ ipportnethash_add(struct ip_set *set, ip_set_ip_t *hash_ip, uint8_t cidr = map->cidr[0] ? map->cidr[0] : 31; \ ip_set_ip_t port, ip1; \ \ - if (flags[index+2] == 0) \ + if (flags[2] == 0) \ return 0; \ \ - port = get_port(skb, flags[index+1]); \ - ip1 = ipaddr(skb, flags[index+2]); \ + port = get_port(skb, flags++); \ + ip1 = ipaddr(skb, flags++); \ \ if (port == INVALID_PORT) \ return 0; @@ -227,7 +221,7 @@ __ipportnethash_retry(struct ip_set_ipportnethash *tmp, HASH_RETRY2(ipportnethash, struct ipportip) static inline int -ipportnethash_del(struct ip_set *set, ip_set_ip_t *hash_ip, +ipportnethash_del(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1, uint8_t cidr) { @@ -242,7 +236,7 @@ ipportnethash_del(struct ip_set *set, ip_set_ip_t *hash_ip, if (cidr <= 0 || cidr >= 32) return -EINVAL; - id = ipportnethash_id_cidr(set, hash_ip, ip, port, ip1, cidr); + id = ipportnethash_id_cidr(set, ip, port, ip1, cidr); if (id == UINT_MAX) return -EEXIST; diff --git a/kernel/ip_set_iptree.c b/kernel/ip_set_iptree.c index cdb3404..77eb180 100644 --- a/kernel/ip_set_iptree.c +++ b/kernel/ip_set_iptree.c @@ -62,7 +62,7 @@ static __KMEM_CACHE_T__ *leaf_cachep; } while (0) static inline int -iptree_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +iptree_test(struct ip_set *set, ip_set_ip_t ip) { struct ip_set_iptree *map = set->data; struct ip_set_iptreeb *btree; @@ -73,8 +73,7 @@ iptree_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) if (!ip) return -ERANGE; - *hash_ip = ip; - ABCD(a, b, c, d, hash_ip); + ABCD(a, b, c, d, &ip); DP("%u %u %u %u timeout %u", a, b, c, d, map->timeout); TESTIP_WALK(map, a, btree); TESTIP_WALK(btree, b, ctree); @@ -106,8 +105,7 @@ KADT(iptree, test, ipaddr) } while (0) static inline int -iptree_add(struct ip_set *set, ip_set_ip_t *hash_ip, - ip_set_ip_t ip, unsigned int timeout) +iptree_add(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout) { struct ip_set_iptree *map = set->data; struct ip_set_iptreeb *btree; @@ -121,8 +119,7 @@ iptree_add(struct ip_set *set, ip_set_ip_t *hash_ip, * but it's probably overkill */ return -ERANGE; - *hash_ip = ip; - ABCD(a, b, c, d, hash_ip); + ABCD(a, b, c, d, &ip); DP("%u %u %u %u timeout %u", a, b, c, d, timeout); ADDIP_WALK(map, a, btree, struct ip_set_iptreeb, branch_cachep); ADDIP_WALK(btree, b, ctree, struct ip_set_iptreec, branch_cachep); @@ -153,7 +150,7 @@ KADT(iptree, add, ipaddr, 0) } while (0) static inline int -iptree_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +iptree_del(struct ip_set *set, ip_set_ip_t ip) { struct ip_set_iptree *map = set->data; struct ip_set_iptreeb *btree; @@ -164,8 +161,7 @@ iptree_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) if (!ip) return -ERANGE; - *hash_ip = ip; - ABCD(a, b, c, d, hash_ip); + ABCD(a, b, c, d, &ip); DELIP_WALK(map, a, btree); DELIP_WALK(btree, b, ctree); DELIP_WALK(ctree, c, dtree); @@ -364,7 +360,7 @@ iptree_list_header(const struct ip_set *set, void *data) } static int -iptree_list_members_size(const struct ip_set *set) +iptree_list_members_size(const struct ip_set *set, char dont_align) { const struct ip_set_iptree *map = set->data; struct ip_set_iptreeb *btree; @@ -386,20 +382,21 @@ iptree_list_members_size(const struct ip_set *set) LOOP_WALK_END; DP("members %u", count); - return (count * sizeof(struct ip_set_req_iptree)); + return (count * IPSET_VALIGN(sizeof(struct ip_set_req_iptree), dont_align)); } static void -iptree_list_members(const struct ip_set *set, void *data) +iptree_list_members(const struct ip_set *set, void *data, char dont_align) { const struct ip_set_iptree *map = set->data; struct ip_set_iptreeb *btree; struct ip_set_iptreec *ctree; struct ip_set_iptreed *dtree; unsigned int a,b,c,d; - size_t offset = 0; + size_t offset = 0, datasize; struct ip_set_req_iptree *entry; + datasize = IPSET_VALIGN(sizeof(struct ip_set_req_iptree), dont_align); LOOP_WALK_BEGIN(map, a, btree); LOOP_WALK_BEGIN(btree, b, ctree); LOOP_WALK_BEGIN(ctree, c, dtree); @@ -410,7 +407,7 @@ iptree_list_members(const struct ip_set *set, void *data) entry->ip = ((a << 24) | (b << 16) | (c << 8) | d); entry->timeout = !map->timeout ? 0 : (dtree->expires[d] - jiffies)/HZ; - offset += sizeof(struct ip_set_req_iptree); + offset += datasize; } } LOOP_WALK_END; diff --git a/kernel/ip_set_iptreemap.c b/kernel/ip_set_iptreemap.c index 7c8c517..02f657e 100644 --- a/kernel/ip_set_iptreemap.c +++ b/kernel/ip_set_iptreemap.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -250,7 +251,7 @@ free_b(struct ip_set_iptreemap_b *map) } static inline int -iptreemap_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +iptreemap_test(struct ip_set *set, ip_set_ip_t ip) { struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap_b *btree; @@ -258,9 +259,7 @@ iptreemap_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) struct ip_set_iptreemap_d *dtree; unsigned char a, b, c, d; - *hash_ip = ip; - - ABCD(a, b, c, d, hash_ip); + ABCD(a, b, c, d, &ip); TESTIP_WALK(map, a, btree, fullbitmap_b); TESTIP_WALK(btree, b, ctree, fullbitmap_c); @@ -275,7 +274,7 @@ UADT(iptreemap, test) KADT(iptreemap, test, ipaddr) static inline int -__addip_single(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +__addip_single(struct ip_set *set, ip_set_ip_t ip) { struct ip_set_iptreemap *map = (struct ip_set_iptreemap *) set->data; struct ip_set_iptreemap_b *btree; @@ -283,9 +282,7 @@ __addip_single(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) struct ip_set_iptreemap_d *dtree; unsigned char a, b, c, d; - *hash_ip = ip; - - ABCD(a, b, c, d, hash_ip); + ABCD(a, b, c, d, &ip); ADDIP_WALK(map, a, btree, struct ip_set_iptreemap_b, cachep_b, fullbitmap_b); ADDIP_WALK(btree, b, ctree, struct ip_set_iptreemap_c, cachep_c, fullbitmap_c); @@ -300,8 +297,7 @@ __addip_single(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) } static inline int -iptreemap_add(struct ip_set *set, ip_set_ip_t *hash_ip, - ip_set_ip_t start, ip_set_ip_t end) +iptreemap_add(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end) { struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap_b *btree; @@ -312,9 +308,7 @@ iptreemap_add(struct ip_set *set, ip_set_ip_t *hash_ip, unsigned char a2, b2, c2, d2; if (start == end) - return __addip_single(set, hash_ip, start); - - *hash_ip = start; + return __addip_single(set, start); ABCD(a1, b1, c1, d1, &start); ABCD(a2, b2, c2, d2, &end); @@ -337,8 +331,7 @@ UADT0(iptreemap, add, min(req->ip, req->end), max(req->ip, req->end)) KADT(iptreemap, add, ipaddr, ip) static inline int -__delip_single(struct ip_set *set, ip_set_ip_t *hash_ip, - ip_set_ip_t ip, gfp_t flags) +__delip_single(struct ip_set *set, ip_set_ip_t ip, gfp_t flags) { struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap_b *btree; @@ -346,9 +339,7 @@ __delip_single(struct ip_set *set, ip_set_ip_t *hash_ip, struct ip_set_iptreemap_d *dtree; unsigned char a,b,c,d; - *hash_ip = ip; - - ABCD(a, b, c, d, hash_ip); + ABCD(a, b, c, d, &ip); DELIP_WALK(map, a, btree, cachep_b, fullbitmap_b, flags); DELIP_WALK(btree, b, ctree, cachep_c, fullbitmap_c, flags); @@ -363,7 +354,7 @@ __delip_single(struct ip_set *set, ip_set_ip_t *hash_ip, } static inline int -iptreemap_del(struct ip_set *set, ip_set_ip_t *hash_ip, +iptreemap_del(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, gfp_t flags) { struct ip_set_iptreemap *map = set->data; @@ -375,9 +366,7 @@ iptreemap_del(struct ip_set *set, ip_set_ip_t *hash_ip, unsigned char a2, b2, c2, d2; if (start == end) - return __delip_single(set, hash_ip, start, flags); - - *hash_ip = start; + return __delip_single(set, start, flags); ABCD(a1, b1, c1, d1, &start); ABCD(a2, b2, c2, d2, &end); @@ -517,6 +506,7 @@ static void iptreemap_flush(struct ip_set *set) { struct ip_set_iptreemap *map = set->data; + unsigned int gc_interval = map->gc_interval; while (!del_timer(&map->gc)) msleep(IPTREEMAP_DESTROY_SLEEP); @@ -524,6 +514,7 @@ iptreemap_flush(struct ip_set *set) __flush(map); memset(map, 0, sizeof(*map)); + map->gc_interval = gc_interval; init_gc_timer(set); } @@ -538,7 +529,7 @@ iptreemap_list_header(const struct ip_set *set, void *data) } static int -iptreemap_list_members_size(const struct ip_set *set) +iptreemap_list_members_size(const struct ip_set *set, char dont_align) { struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap_b *btree; @@ -564,31 +555,30 @@ iptreemap_list_members_size(const struct ip_set *set) if (inrange) count++; - return (count * sizeof(struct ip_set_req_iptreemap)); + return (count * IPSET_VALIGN(sizeof(struct ip_set_req_iptreemap), dont_align)); } -static inline u_int32_t +static inline void add_member(void *data, size_t offset, ip_set_ip_t start, ip_set_ip_t end) { struct ip_set_req_iptreemap *entry = data + offset; entry->ip = start; entry->end = end; - - return sizeof(*entry); } static void -iptreemap_list_members(const struct ip_set *set, void *data) +iptreemap_list_members(const struct ip_set *set, void *data, char dont_align) { struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap_b *btree; struct ip_set_iptreemap_c *ctree; struct ip_set_iptreemap_d *dtree; unsigned int a, b, c, d, inrange = 0; - size_t offset = 0; + size_t offset = 0, datasize; ip_set_ip_t start = 0, end = 0, ip; + datasize = IPSET_VALIGN(sizeof(struct ip_set_req_iptreemap), dont_align); LOOP_WALK_BEGIN(map, a, btree) { LOOP_WALK_BEGIN(btree, b, ctree) { LOOP_WALK_BEGIN(ctree, c, dtree) { @@ -599,12 +589,14 @@ iptreemap_list_members(const struct ip_set *set, void *data) inrange = 1; start = ip; } else if (end < ip - 1) { - offset += add_member(data, offset, start, end); + add_member(data, offset, start, end); + offset += datasize; start = ip; } end = ip; } else if (inrange) { - offset += add_member(data, offset, start, end); + add_member(data, offset, start, end); + offset += datasize; inrange = 0; } } diff --git a/kernel/ip_set_macipmap.c b/kernel/ip_set_macipmap.c index 464106e..89e907b 100644 --- a/kernel/ip_set_macipmap.c +++ b/kernel/ip_set_macipmap.c @@ -22,8 +22,7 @@ #include static int -macipmap_utest(struct ip_set *set, const void *data, u_int32_t size, - ip_set_ip_t *hash_ip) +macipmap_utest(struct ip_set *set, const void *data, u_int32_t size) { const struct ip_set_macipmap *map = set->data; const struct ip_set_macip *table = map->members; @@ -32,9 +31,7 @@ macipmap_utest(struct ip_set *set, const void *data, u_int32_t size, if (req->ip < map->first_ip || req->ip > map->last_ip) return -ERANGE; - *hash_ip = req->ip; - DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u", - set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip)); + DP("set: %s, ip:%u.%u.%u.%u", set->name, HIPQUAD(req->ip)); if (table[req->ip - map->first_ip].match) { return (memcmp(req->ethernet, &table[req->ip - map->first_ip].ethernet, @@ -47,22 +44,18 @@ macipmap_utest(struct ip_set *set, const void *data, u_int32_t size, static int macipmap_ktest(struct ip_set *set, const struct sk_buff *skb, - ip_set_ip_t *hash_ip, - const u_int32_t *flags, - unsigned char index) + const u_int32_t *flags) { const struct ip_set_macipmap *map = set->data; const struct ip_set_macip *table = map->members; ip_set_ip_t ip; - ip = ipaddr(skb, flags[index]); + ip = ipaddr(skb, flags); if (ip < map->first_ip || ip > map->last_ip) return 0; - *hash_ip = ip; - DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u", - set->name, HIPQUAD(ip), HIPQUAD(*hash_ip)); + DP("set: %s, ip:%u.%u.%u.%u", set->name, HIPQUAD(ip)); if (table[ip - map->first_ip].match) { /* Is mac pointer valid? * If so, compare... */ @@ -78,7 +71,7 @@ macipmap_ktest(struct ip_set *set, /* returns 0 on success */ static inline int -macipmap_add(struct ip_set *set, ip_set_ip_t *hash_ip, +macipmap_add(struct ip_set *set, ip_set_ip_t ip, const unsigned char *ethernet) { struct ip_set_macipmap *map = set->data; @@ -89,8 +82,7 @@ macipmap_add(struct ip_set *set, ip_set_ip_t *hash_ip, if (table[ip - map->first_ip].match) return -EEXIST; - *hash_ip = ip; - DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip)); + DP("set: %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip)); memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN); table[ip - map->first_ip].match = IPSET_MACIP_ISSET; return 0; @@ -105,7 +97,7 @@ UADT(macipmap, add, req->ethernet) KADT(macipmap, add, ipaddr, eth_hdr(skb)->h_source) static inline int -macipmap_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +macipmap_del(struct ip_set *set, ip_set_ip_t ip) { struct ip_set_macipmap *map = set->data; struct ip_set_macip *table = map->members; @@ -115,9 +107,8 @@ macipmap_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) if (!table[ip - map->first_ip].match) return -EEXIST; - *hash_ip = ip; table[ip - map->first_ip].match = 0; - DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip)); + DP("set: %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip)); return 0; } @@ -152,8 +143,32 @@ __macipmap_list_header(const struct ip_set_macipmap *map, } BITMAP_LIST_HEADER(macipmap) -BITMAP_LIST_MEMBERS_SIZE(macipmap) -BITMAP_LIST_MEMBERS(macipmap) +BITMAP_LIST_MEMBERS_SIZE(macipmap, struct ip_set_req_macipmap, + (map->last_ip - map->first_ip + 1), + ((const struct ip_set_macip *)map->members)[i].match) + + +static void +macipmap_list_members(const struct ip_set *set, void *data, char dont_align) +{ + const struct ip_set_macipmap *map = set->data; + const struct ip_set_macip *table = map->members; + uint32_t i, n = 0; + struct ip_set_req_macipmap *d; + + if (dont_align) { + memcpy(data, map->members, map->size); + return; + } + + for (i = 0; i < map->last_ip - map->first_ip + 1; i++) + if (table[i].match) { + d = data + n * IPSET_ALIGN(sizeof(struct ip_set_req_macipmap)); + d->ip = map->first_ip + i; + memcpy(d->ethernet, &table[i].ethernet, ETH_ALEN); + n++; + } +} IP_SET_TYPE(macipmap, IPSET_TYPE_IP | IPSET_DATA_SINGLE) diff --git a/kernel/ip_set_nethash.c b/kernel/ip_set_nethash.c index d68a015..bf87f5c 100644 --- a/kernel/ip_set_nethash.c +++ b/kernel/ip_set_nethash.c @@ -26,7 +26,6 @@ static int limit = MAX_RANGE; static inline __u32 nethash_id_cidr(const struct ip_set_nethash *map, - ip_set_ip_t *hash_ip, ip_set_ip_t ip, uint8_t cidr) { @@ -34,15 +33,15 @@ nethash_id_cidr(const struct ip_set_nethash *map, u_int16_t i; ip_set_ip_t *elem; - *hash_ip = pack_ip_cidr(ip, cidr); - if (!*hash_ip) + ip = pack_ip_cidr(ip, cidr); + if (!ip) return MAX_RANGE; for (i = 0; i < map->probes; i++) { - id = jhash_ip(map, i, *hash_ip) % map->hashsize; + id = jhash_ip(map, i, ip) % map->hashsize; DP("hash key: %u", id); elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id); - if (*elem == *hash_ip) + if (*elem == ip) return id; /* No shortcut - there can be deleted entries. */ } @@ -50,14 +49,14 @@ nethash_id_cidr(const struct ip_set_nethash *map, } static inline __u32 -nethash_id(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +nethash_id(struct ip_set *set, ip_set_ip_t ip) { const struct ip_set_nethash *map = set->data; __u32 id = UINT_MAX; int i; for (i = 0; i < 30 && map->cidr[i]; i++) { - id = nethash_id_cidr(map, hash_ip, ip, map->cidr[i]); + id = nethash_id_cidr(map, ip, map->cidr[i]); if (id != UINT_MAX) break; } @@ -65,30 +64,28 @@ nethash_id(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) } static inline int -nethash_test_cidr(struct ip_set *set, ip_set_ip_t *hash_ip, - ip_set_ip_t ip, uint8_t cidr) +nethash_test_cidr(struct ip_set *set, ip_set_ip_t ip, uint8_t cidr) { const struct ip_set_nethash *map = set->data; - return (nethash_id_cidr(map, hash_ip, ip, cidr) != UINT_MAX); + return (nethash_id_cidr(map, ip, cidr) != UINT_MAX); } static inline int -nethash_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip) +nethash_test(struct ip_set *set, ip_set_ip_t ip) { - return (nethash_id(set, hash_ip, ip) != UINT_MAX); + return (nethash_id(set, ip) != UINT_MAX); } static int -nethash_utest(struct ip_set *set, const void *data, u_int32_t size, - ip_set_ip_t *hash_ip) +nethash_utest(struct ip_set *set, const void *data, u_int32_t size) { const struct ip_set_req_nethash *req = data; if (req->cidr <= 0 || req->cidr > 32) return -EINVAL; - return (req->cidr == 32 ? nethash_test(set, hash_ip, req->ip) - : nethash_test_cidr(set, hash_ip, req->ip, req->cidr)); + return (req->cidr == 32 ? nethash_test(set, req->ip) + : nethash_test_cidr(set, req->ip, req->cidr)); } #define KADT_CONDITION @@ -121,8 +118,7 @@ __nethash_add(struct ip_set_nethash *map, ip_set_ip_t *ip) } static inline int -nethash_add(struct ip_set *set, ip_set_ip_t *hash_ip, - ip_set_ip_t ip, uint8_t cidr) +nethash_add(struct ip_set *set, ip_set_ip_t ip, uint8_t cidr) { struct ip_set_nethash *map = set->data; int ret; @@ -132,12 +128,11 @@ nethash_add(struct ip_set *set, ip_set_ip_t *hash_ip, if (cidr <= 0 || cidr >= 32) return -EINVAL; - *hash_ip = pack_ip_cidr(ip, cidr); - DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip)); - if (!*hash_ip) + ip = pack_ip_cidr(ip, cidr); + if (!ip) return -ERANGE; - ret = __nethash_add(map, hash_ip); + ret = __nethash_add(map, &ip); if (ret == 0) { if (!map->nets[cidr-1]++) add_cidr_size(map->cidr, cidr); @@ -165,8 +160,7 @@ __nethash_retry(struct ip_set_nethash *tmp, struct ip_set_nethash *map) HASH_RETRY(nethash, ip_set_ip_t) static inline int -nethash_del(struct ip_set *set, ip_set_ip_t *hash_ip, - ip_set_ip_t ip, uint8_t cidr) +nethash_del(struct ip_set *set, ip_set_ip_t ip, uint8_t cidr) { struct ip_set_nethash *map = set->data; ip_set_ip_t id, *elem; @@ -174,7 +168,7 @@ nethash_del(struct ip_set *set, ip_set_ip_t *hash_ip, if (cidr <= 0 || cidr >= 32) return -EINVAL; - id = nethash_id_cidr(map, hash_ip, ip, cidr); + id = nethash_id_cidr(map, ip, cidr); if (id == UINT_MAX) return -EEXIST; diff --git a/kernel/ip_set_portmap.c b/kernel/ip_set_portmap.c index 8b0ec0a..8bb6e76 100644 --- a/kernel/ip_set_portmap.c +++ b/kernel/ip_set_portmap.c @@ -23,16 +23,14 @@ #include static inline int -portmap_test(const struct ip_set *set, ip_set_ip_t *hash_port, - ip_set_ip_t port) +portmap_test(const struct ip_set *set, ip_set_ip_t port) { const struct ip_set_portmap *map = set->data; if (port < map->first_ip || port > map->last_ip) return -ERANGE; - *hash_port = port; - DP("set: %s, port:%u, %u", set->name, port, *hash_port); + DP("set: %s, port: %u", set->name, port); return !!test_bit(port - map->first_ip, map->members); } @@ -44,7 +42,7 @@ UADT(portmap, test) KADT(portmap, test, get_port) static inline int -portmap_add(struct ip_set *set, ip_set_ip_t *hash_port, ip_set_ip_t port) +portmap_add(struct ip_set *set, ip_set_ip_t port) { struct ip_set_portmap *map = set->data; @@ -52,9 +50,8 @@ portmap_add(struct ip_set *set, ip_set_ip_t *hash_port, ip_set_ip_t port) return -ERANGE; if (test_and_set_bit(port - map->first_ip, map->members)) return -EEXIST; - - *hash_port = port; - DP("port %u", port); + + DP("set: %s, port %u", set->name, port); return 0; } @@ -62,7 +59,7 @@ UADT(portmap, add) KADT(portmap, add, get_port) static inline int -portmap_del(struct ip_set *set, ip_set_ip_t *hash_port, ip_set_ip_t port) +portmap_del(struct ip_set *set, ip_set_ip_t port) { struct ip_set_portmap *map = set->data; @@ -70,9 +67,8 @@ portmap_del(struct ip_set *set, ip_set_ip_t *hash_port, ip_set_ip_t port) return -ERANGE; if (!test_and_clear_bit(port - map->first_ip, map->members)) return -EEXIST; - - *hash_port = port; - DP("port %u", port); + + DP("set: %s, port %u", set->name, port); return 0; } @@ -102,8 +98,28 @@ __portmap_list_header(const struct ip_set_portmap *map, } BITMAP_LIST_HEADER(portmap) -BITMAP_LIST_MEMBERS_SIZE(portmap) -BITMAP_LIST_MEMBERS(portmap) +BITMAP_LIST_MEMBERS_SIZE(portmap, ip_set_ip_t, (map->last_ip - map->first_ip + 1), + test_bit(i, map->members)) + +static void +portmap_list_members(const struct ip_set *set, void *data, char dont_align) +{ + const struct ip_set_portmap *map = set->data; + uint32_t i, n = 0; + ip_set_ip_t *d; + + if (dont_align) { + memcpy(data, map->members, map->size); + return; + } + + for (i = 0; i < map->last_ip - map->first_ip + 1; i++) + if (test_bit(i, map->members)) { + d = data + n * IPSET_ALIGN(sizeof(ip_set_ip_t)); + *d = map->first_ip + i; + n++; + } +} IP_SET_TYPE(portmap, IPSET_TYPE_PORT | IPSET_DATA_SINGLE) diff --git a/kernel/ip_set_setlist.c b/kernel/ip_set_setlist.c index 2b1c6b6..3cfdae8 100644 --- a/kernel/ip_set_setlist.c +++ b/kernel/ip_set_setlist.c @@ -28,8 +28,7 @@ next_index_eq(const struct ip_set_setlist *map, int i, ip_set_id_t index) } static int -setlist_utest(struct ip_set *set, const void *data, u_int32_t size, - ip_set_ip_t *hash_ip) +setlist_utest(struct ip_set *set, const void *data, u_int32_t size) { const struct ip_set_setlist *map = set->data; const struct ip_set_req_setlist *req = data; @@ -72,10 +71,8 @@ finish: static int setlist_ktest(struct ip_set *set, - const struct sk_buff *skb, - ip_set_ip_t *hash_ip, - const u_int32_t *flags, - unsigned char index) + const struct sk_buff *skb, + const u_int32_t *flags) { struct ip_set_setlist *map = set->data; int i, res = 0; @@ -107,8 +104,7 @@ insert_setlist(struct ip_set_setlist *map, int i, ip_set_id_t index) } static int -setlist_uadd(struct ip_set *set, const void *data, u_int32_t size, - ip_set_ip_t *hash_ip) +setlist_uadd(struct ip_set *set, const void *data, u_int32_t size) { struct ip_set_setlist *map = set->data; const struct ip_set_req_setlist *req = data; @@ -156,9 +152,7 @@ finish: static int setlist_kadd(struct ip_set *set, const struct sk_buff *skb, - ip_set_ip_t *hash_ip, - const u_int32_t *flags, - unsigned char index) + const u_int32_t *flags) { struct ip_set_setlist *map = set->data; int i, res = -EINVAL; @@ -182,8 +176,7 @@ unshift_setlist(struct ip_set_setlist *map, int i) } static int -setlist_udel(struct ip_set *set, const void *data, u_int32_t size, - ip_set_ip_t *hash_ip) +setlist_udel(struct ip_set *set, const void *data, u_int32_t size) { struct ip_set_setlist *map = set->data; const struct ip_set_req_setlist *req = data; @@ -234,9 +227,7 @@ finish: static int setlist_kdel(struct ip_set *set, const struct sk_buff *skb, - ip_set_ip_t *hash_ip, - const u_int32_t *flags, - unsigned char index) + const u_int32_t *flags) { struct ip_set_setlist *map = set->data; int i, res = -EINVAL; @@ -304,21 +295,24 @@ setlist_list_header(const struct ip_set *set, void *data) } static int -setlist_list_members_size(const struct ip_set *set) +setlist_list_members_size(const struct ip_set *set, char dont_align) { const struct ip_set_setlist *map = set->data; - return map->size * sizeof(ip_set_id_t); + return map->size * IPSET_VALIGN(sizeof(ip_set_id_t), dont_align); } static void -setlist_list_members(const struct ip_set *set, void *data) +setlist_list_members(const struct ip_set *set, void *data, char dont_align) { struct ip_set_setlist *map = set->data; + ip_set_id_t *d; int i; - for (i = 0; i < map->size; i++) - *((ip_set_id_t *)data + i) = ip_set_id(map->index[i]); + for (i = 0; i < map->size; i++) { + d = data + i * IPSET_VALIGN(sizeof(ip_set_id_t), dont_align); + *d = ip_set_id(map->index[i]); + } } IP_SET_TYPE(setlist, IPSET_TYPE_SETNAME | IPSET_DATA_SINGLE) -- cgit v1.2.3