summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/ChangeLog17
-rw-r--r--kernel/Config.in.ipset3
-rw-r--r--kernel/Kbuild6
-rw-r--r--kernel/Kconfig.ipset24
-rw-r--r--kernel/Makefile9
-rw-r--r--kernel/Makefile.ipset3
-rwxr-xr-xkernel/expand_macros.pl17
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set.h86
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_bitmaps.h119
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_getport.h48
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_hashes.h300
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_iphash.h3
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_ipmap.h6
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_ipporthash.h4
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_ipportiphash.h38
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_ipportnethash.h41
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_iptree.h1
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_iptreemap.h2
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_macipmap.h2
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_malloc.h8
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_nethash.h33
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_portmap.h9
-rw-r--r--kernel/include/linux/netfilter_ipv4/ip_set_setlist.h26
-rw-r--r--kernel/ip_set.c76
-rw-r--r--kernel/ip_set_iphash.c339
-rw-r--r--kernel/ip_set_ipmap.c240
-rw-r--r--kernel/ip_set_ipporthash.c455
-rw-r--r--kernel/ip_set_ipportiphash.c212
-rw-r--r--kernel/ip_set_ipportnethash.c299
-rw-r--r--kernel/ip_set_iptree.c170
-rw-r--r--kernel/ip_set_iptreemap.c152
-rw-r--r--kernel/ip_set_macipmap.c255
-rw-r--r--kernel/ip_set_nethash.c422
-rw-r--r--kernel/ip_set_portmap.c293
-rw-r--r--kernel/ip_set_setlist.c332
35 files changed, 2038 insertions, 2012 deletions
diff --git a/kernel/ChangeLog b/kernel/ChangeLog
index c020713..d034b34 100644
--- a/kernel/ChangeLog
+++ b/kernel/ChangeLog
@@ -1,4 +1,13 @@
-Tue, 02 Sep 2008
- - ChangeLog forked for kernel part
- - Compatibility fix for kernels >= 2.6.27:
- semaphore.h was moved from asm/ to linux/ (James King)
+2.4
+ - ipportiphash, ipportnethash and setlist types added
+ - set type modules reworked to avoid code duplication
+ as much as possible, code unification macros
+ - expand_macros Makefile target added to help debugging
+ code unification macros
+ - ip_set_addip_kernel and ip_set_delip_kernel
+ changed from void to int, __ip_set_get_byname and
+ __ip_set_put_byid added for the sake of setlist type
+ - unnecessary includes removed
+ - compatibility fix for kernels >= 2.6.27:
+ semaphore.h was moved from asm/ to linux/ (James King)
+ - ChangeLog forked for kernel part
diff --git a/kernel/Config.in.ipset b/kernel/Config.in.ipset
index 0758f0a..0f442e7 100644
--- a/kernel/Config.in.ipset
+++ b/kernel/Config.in.ipset
@@ -10,6 +10,9 @@
dep_tristate ' iphash set type support' CONFIG_IP_NF_SET_IPHASH $CONFIG_IP_NF_SET
dep_tristate ' nethash set type support' CONFIG_IP_NF_SET_NETHASH $CONFIG_IP_NF_SET
dep_tristate ' ipporthash set type support' CONFIG_IP_NF_SET_IPPORTHASH $CONFIG_IP_NF_SET
+ dep_tristate ' ipportiphash set type support' CONFIG_IP_NF_SET_IPPORTIPHASH $CONFIG_IP_NF_SET
+ dep_tristate ' ipportnethash set type support' CONFIG_IP_NF_SET_IPPORTNETHASH $CONFIG_IP_NF_SET
dep_tristate ' iptree set type support' CONFIG_IP_NF_SET_IPTREE $CONFIG_IP_NF_SET
dep_tristate ' iptreemap set type support' CONFIG_IP_NF_SET_IPTREEMAP $CONFIG_IP_NF_SET
+ dep_tristate ' setlist set type support' CONFIG_IP_NF_SET_SETLIST $CONFIG_IP_NF_SET
fi
diff --git a/kernel/Kbuild b/kernel/Kbuild
index c7cb727..9757a4a 100644
--- a/kernel/Kbuild
+++ b/kernel/Kbuild
@@ -4,9 +4,11 @@ EXTRA_CFLAGS := -I$(M)/include \
obj-m += ip_set.o ipt_set.o ipt_SET.o
obj-m += ip_set_ipmap.o ip_set_macipmap.o ip_set_portmap.o
-obj-m += ip_set_iphash.o ip_set_ipporthash.o ip_set_nethash.o
+obj-m += ip_set_iphash.o ip_set_nethash.o ip_set_ipporthash.o
+obj-m += ip_set_ipportiphash.o ip_set_ipportnethash.o
obj-m += ip_set_iptree.o ip_set_iptreemap.o
+obj-m += ip_set_setlist.o
# It's for me...
incdirs := $(M) $(M)/include/linux/netfilter_ipv4
-clean-files := $(foreach dir,$(incdirs),$(wildcard $(dir)/*~))
+clean-files := $(foreach dir,$(incdirs),$(wildcard $(dir)/*~)) *.m.c
diff --git a/kernel/Kconfig.ipset b/kernel/Kconfig.ipset
index 2c6022a..8b27517 100644
--- a/kernel/Kconfig.ipset
+++ b/kernel/Kconfig.ipset
@@ -79,6 +79,22 @@ config IP_NF_SET_IPPORTHASH
To compile it as a module, choose M here. If unsure, say N.
+config IP_NF_SET_IPPORTIPHASH
+ tristate "ipportiphash set support"
+ depends on IP_NF_SET
+ help
+ This option adds the ipportiphash set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_SET_IPPORTNETHASH
+ tristate "ipportnethash set support"
+ depends on IP_NF_SET
+ help
+ This option adds the ipportnethash set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP_NF_SET_IPTREE
tristate "iptree set support"
depends on IP_NF_SET
@@ -95,6 +111,14 @@ config IP_NF_SET_IPTREEMAP
To compile it as a module, choose M here. If unsure, say N.
+config IP_NF_SET_SETLIST
+ tristate "setlist set support"
+ depends on IP_NF_SET
+ help
+ This option adds the setlist set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP_NF_MATCH_SET
tristate "set match support"
depends on IP_NF_SET
diff --git a/kernel/Makefile b/kernel/Makefile
index 60e5362..9ec91f6 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -4,4 +4,13 @@ else
KERNELDIR := /lib/modules/`uname -r`/build
all::
$(MAKE) -C $KERNELDIR M=`pwd` $@
+
+expand_macros: $(patsubst %.c, %.m.c, $(filter-out %.mod.c %.m.c, $(wildcard ip_set_*.c)))
+
+%.m.c: %.c
+ ./expand_macros.pl < $< > $@
+
+clean:
+ rm -rf *.m.c
+
endif
diff --git a/kernel/Makefile.ipset b/kernel/Makefile.ipset
index bb3c131..fe42cc1 100644
--- a/kernel/Makefile.ipset
+++ b/kernel/Makefile.ipset
@@ -6,8 +6,11 @@ obj-$(CONFIG_IP_NF_SET_MACIPMAP) += ip_set_macipmap.o
obj-$(CONFIG_IP_NF_SET_IPHASH) += ip_set_iphash.o
obj-$(CONFIG_IP_NF_SET_NETHASH) += ip_set_nethash.o
obj-$(CONFIG_IP_NF_SET_IPPORTHASH) += ip_set_ipporthash.o
+obj-$(CONFIG_IP_NF_SET_IPPORTIPHASH) += ip_set_ipportiphash.o
+obj-$(CONFIG_IP_NF_SET_IPPORTNETHASH) += ip_set_ipportnethash.o
obj-$(CONFIG_IP_NF_SET_IPTREE) += ip_set_iptree.o
obj-$(CONFIG_IP_NF_SET_IPTREEMAP) += ip_set_iptreemap.o
+obj-$(CONFIG_IP_NF_SET_SETLIST) += ip_set_setlist.o
# match and target
obj-$(CONFIG_IP_NF_MATCH_SET) += ipt_set.o
diff --git a/kernel/expand_macros.pl b/kernel/expand_macros.pl
new file mode 100755
index 0000000..ea0f4b6
--- /dev/null
+++ b/kernel/expand_macros.pl
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+
+my $expand = 0;
+
+while (<STDIN>) {
+ if ($expand) {
+ print C;
+ } elsif (m,include \<(linux/netfilter_ipv4/ip_set\.h)\>,) {
+ $expand = 1;
+ open(C, "|gcc -D__KERNEL__ -Iinclude -E - 2>/dev/null| indent -kr -i8") || die "Can't run gcc: $!\n";
+ print C;
+ } else {
+ print;
+ }
+}
+close C;
+ \ No newline at end of file
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set.h b/kernel/include/linux/netfilter_ipv4/ip_set.h
index b8c7202..c29a460 100644
--- a/kernel/include/linux/netfilter_ipv4/ip_set.h
+++ b/kernel/include/linux/netfilter_ipv4/ip_set.h
@@ -87,6 +87,9 @@ typedef uint16_t ip_set_id_t;
#define IPSET_TYPE_PORT 0x02 /* Port type of set */
#define IPSET_DATA_SINGLE 0x04 /* Single data storage */
#define IPSET_DATA_DOUBLE 0x08 /* Double data storage */
+#define IPSET_DATA_TRIPLE 0x10 /* Triple data storage */
+#define IPSET_TYPE_IP1 0x20 /* IP address type of set */
+#define IPSET_TYPE_SETNAME 0x40 /* setname type of set */
/* Reserved keywords */
#define IPSET_TOKEN_DEFAULT ":default:"
@@ -296,8 +299,12 @@ static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b)
return 4 * ((((b - a + 8) / 8) + 3) / 4);
}
+/* General limit for the elements in a set */
+#define MAX_RANGE 0x0000FFFF
+
#ifdef __KERNEL__
#include <linux/netfilter_ipv4/ip_set_compat.h>
+#include <linux/netfilter_ipv4/ip_set_malloc.h>
#define ip_set_printk(format, args...) \
do { \
@@ -482,18 +489,85 @@ struct ip_set_hash {
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 id);
extern void ip_set_put(ip_set_id_t id);
+extern ip_set_id_t __ip_set_get_byname(const char name[IP_SET_MAXNAMELEN],
+ struct ip_set **set);
+extern void __ip_set_put_byid(ip_set_id_t id);
/* API for iptables set match, and SET target */
-extern void ip_set_addip_kernel(ip_set_id_t id,
- const struct sk_buff *skb,
- const u_int32_t *flags);
-extern void ip_set_delip_kernel(ip_set_id_t id,
- const struct sk_buff *skb,
- const u_int32_t *flags);
+extern int ip_set_addip_kernel(ip_set_id_t id,
+ const struct sk_buff *skb,
+ const u_int32_t *flags);
+extern int ip_set_delip_kernel(ip_set_id_t id,
+ const struct sk_buff *skb,
+ const u_int32_t *flags);
extern int ip_set_testip_kernel(ip_set_id_t id,
const struct sk_buff *skb,
const u_int32_t *flags);
+/* Macros to generate functions */
+
+#define STRUCT(pre, type) CONCAT2(pre, type)
+#define CONCAT2(pre, type) struct pre##type
+
+#define FNAME(pre, mid, post) CONCAT3(pre, mid, post)
+#define CONCAT3(pre, mid, post) pre##mid##post
+
+#define UADT0(type, adt, args...) \
+static int \
+FNAME(type,_u,adt)(struct ip_set *set, const void *data, size_t size, \
+ ip_set_ip_t *hash_ip) \
+{ \
+ const STRUCT(ip_set_req_,type) *req = data; \
+ \
+ return FNAME(type,_,adt)(set, hash_ip , ## args); \
+}
+
+#define UADT(type, adt, args...) \
+ UADT0(type, adt, req->ip , ## args)
+
+#define KADT(type, adt, getfn, args...) \
+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) \
+{ \
+ ip_set_ip_t ip = getfn(skb, flags[index]); \
+ \
+ KADT_CONDITION \
+ return FNAME(type,_,adt)(set, hash_ip, ip , ##args); \
+}
+
+#define REGISTER_MODULE(type) \
+static int __init ip_set_##type##_init(void) \
+{ \
+ init_max_page_size(); \
+ return ip_set_register_set_type(&ip_set_##type); \
+} \
+ \
+static void __exit ip_set_##type##_fini(void) \
+{ \
+ /* FIXME: possible race with ip_set_create() */ \
+ ip_set_unregister_set_type(&ip_set_##type); \
+} \
+ \
+module_init(ip_set_##type##_init); \
+module_exit(ip_set_##type##_fini);
+
+/* Common functions */
+
+static inline ip_set_ip_t
+ipaddr(const struct sk_buff *skb, u_int32_t flag)
+{
+ return ntohl(flag & IPSET_SRC ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr);
+}
+
+#define jhash_ip(map, i, ip) jhash_1word(ip, *(map->initval + i))
+
+#define pack_ip_port(map, ip, port) \
+ (port + ((ip - ((map)->first_ip)) << 16))
+
#endif /* __KERNEL__ */
#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
new file mode 100644
index 0000000..916cb80
--- /dev/null
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_bitmaps.h
@@ -0,0 +1,119 @@
+#ifndef __IP_SET_BITMAPS_H
+#define __IP_SET_BITMAPS_H
+
+/* Macros to generate functions */
+
+#define BITMAP_CREATE(type) \
+static int \
+type##_create(struct ip_set *set, const void *data, size_t size) \
+{ \
+ int newbytes; \
+ const struct ip_set_req_##type##_create *req = data; \
+ struct ip_set_##type *map; \
+ \
+ if (req->from > req->to) { \
+ DP("bad range"); \
+ return -ENOEXEC; \
+ } \
+ \
+ map = kmalloc(sizeof(struct ip_set_##type), GFP_KERNEL); \
+ if (!map) { \
+ DP("out of memory for %d bytes", \
+ sizeof(struct ip_set_#type)); \
+ return -ENOMEM; \
+ } \
+ map->first_ip = req->from; \
+ map->last_ip = req->to; \
+ \
+ newbytes = __##type##_create(req, map); \
+ if (newbytes < 0) { \
+ kfree(map); \
+ return newbytes; \
+ } \
+ \
+ map->size = newbytes; \
+ map->members = ip_set_malloc(newbytes); \
+ if (!map->members) { \
+ DP("out of memory for %d bytes", newbytes); \
+ kfree(map); \
+ return -ENOMEM; \
+ } \
+ memset(map->members, 0, newbytes); \
+ \
+ set->data = map; \
+ return 0; \
+}
+
+#define BITMAP_DESTROY(type) \
+static void \
+type##_destroy(struct ip_set *set) \
+{ \
+ struct ip_set_##type *map = set->data; \
+ \
+ ip_set_free(map->members, map->size); \
+ kfree(map); \
+ \
+ set->data = NULL; \
+}
+
+#define BITMAP_FLUSH(type) \
+static void \
+type##_flush(struct ip_set *set) \
+{ \
+ struct ip_set_##type *map = set->data; \
+ memset(map->members, 0, map->size); \
+}
+
+#define BITMAP_LIST_HEADER(type) \
+static void \
+type##_list_header(const struct ip_set *set, void *data) \
+{ \
+ const struct ip_set_##type *map = set->data; \
+ struct ip_set_req_##type##_create *header = data; \
+ \
+ header->from = map->first_ip; \
+ header->to = map->last_ip; \
+ __##type##_list_header(map, header); \
+}
+
+#define BITMAP_LIST_MEMBERS_SIZE(type) \
+static int \
+type##_list_members_size(const struct ip_set *set) \
+{ \
+ const struct ip_set_##type *map = set->data; \
+ \
+ 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; \
+ \
+ memcpy(data, map->members, map->size); \
+}
+
+#define IP_SET_TYPE(type, __features) \
+struct ip_set_type ip_set_##type = { \
+ .typename = #type, \
+ .features = __features, \
+ .protocol_version = IP_SET_PROTOCOL_VERSION, \
+ .create = &type##_create, \
+ .destroy = &type##_destroy, \
+ .flush = &type##_flush, \
+ .reqsize = sizeof(struct ip_set_req_##type), \
+ .addip = &type##_uadd, \
+ .addip_kernel = &type##_kadd, \
+ .delip = &type##_udel, \
+ .delip_kernel = &type##_kdel, \
+ .testip = &type##_utest, \
+ .testip_kernel = &type##_ktest, \
+ .header_size = sizeof(struct ip_set_req_##type##_create),\
+ .list_header = &type##_list_header, \
+ .list_members_size = &type##_list_members_size, \
+ .list_members = &type##_list_members, \
+ .me = THIS_MODULE, \
+};
+
+#endif /* __IP_SET_BITMAPS_H */
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_getport.h b/kernel/include/linux/netfilter_ipv4/ip_set_getport.h
new file mode 100644
index 0000000..9e322bf
--- /dev/null
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_getport.h
@@ -0,0 +1,48 @@
+#ifndef _IP_SET_GETPORT_H
+#define _IP_SET_GETPORT_H
+
+#ifdef __KERNEL__
+
+#define INVALID_PORT (MAX_RANGE + 1)
+
+/* We must handle non-linear skbs */
+static inline ip_set_ip_t
+get_port(const struct sk_buff *skb, u_int32_t flags)
+{
+ struct iphdr *iph = ip_hdr(skb);
+ u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
+ switch (iph->protocol) {
+ case IPPROTO_TCP: {
+ struct tcphdr tcph;
+
+ /* See comments at tcp_match in ip_tables.c */
+ if (offset)
+ return INVALID_PORT;
+
+ if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &tcph, sizeof(tcph)) < 0)
+ /* No choice either */
+ return INVALID_PORT;
+
+ return ntohs(flags & IPSET_SRC ?
+ tcph.source : tcph.dest);
+ }
+ case IPPROTO_UDP: {
+ struct udphdr udph;
+
+ if (offset)
+ return INVALID_PORT;
+
+ if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &udph, sizeof(udph)) < 0)
+ /* No choice either */
+ return INVALID_PORT;
+
+ return ntohs(flags & IPSET_SRC ?
+ udph.source : udph.dest);
+ }
+ default:
+ return INVALID_PORT;
+ }
+}
+#endif /* __KERNEL__ */
+
+#endif /*_IP_SET_GETPORT_H*/
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_hashes.h b/kernel/include/linux/netfilter_ipv4/ip_set_hashes.h
new file mode 100644
index 0000000..405784a
--- /dev/null
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_hashes.h
@@ -0,0 +1,300 @@
+#ifndef __IP_SET_HASHES_H
+#define __IP_SET_HASHES_H
+
+/* Macros to generate functions */
+
+#ifdef __KERNEL__
+#define HASH_RETRY0(type, dtype, cond) \
+static int \
+type##_retry(struct ip_set *set) \
+{ \
+ struct ip_set_##type *map = set->data, *tmp; \
+ dtype *elem; \
+ void *members; \
+ u_int32_t i, hashsize = map->hashsize; \
+ int res; \
+ \
+ if (map->resize == 0) \
+ return -ERANGE; \
+ \
+ again: \
+ res = 0; \
+ \
+ /* Calculate new hash size */ \
+ hashsize += (hashsize * map->resize)/100; \
+ if (hashsize == map->hashsize) \
+ hashsize++; \
+ \
+ ip_set_printk("rehashing of set %s triggered: " \
+ "hashsize grows from %u to %u", \
+ set->name, map->hashsize, hashsize); \
+ \
+ tmp = kmalloc(sizeof(struct ip_set_##type) \
+ + map->probes * sizeof(uint32_t), GFP_ATOMIC); \
+ if (!tmp) { \
+ DP("out of memory for %d bytes", \
+ sizeof(struct ip_set_##type) \
+ + map->probes * sizeof(uint32_t)); \
+ return -ENOMEM; \
+ } \
+ tmp->members = harray_malloc(hashsize, sizeof(dtype), GFP_ATOMIC);\
+ if (!tmp->members) { \
+ DP("out of memory for %d bytes", hashsize * sizeof(dtype));\
+ kfree(tmp); \
+ return -ENOMEM; \
+ } \
+ tmp->hashsize = hashsize; \
+ tmp->elements = 0; \
+ tmp->probes = map->probes; \
+ tmp->resize = map->resize; \
+ memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));\
+ __##type##_retry(tmp, map); \
+ \
+ write_lock_bh(&set->lock); \
+ map = set->data; /* Play safe */ \
+ for (i = 0; i < map->hashsize && res == 0; i++) { \
+ elem = HARRAY_ELEM(map->members, dtype *, i); \
+ if (cond) \
+ res = __##type##_add(tmp, elem); \
+ } \
+ if (res) { \
+ /* Failure, try again */ \
+ write_unlock_bh(&set->lock); \
+ harray_free(tmp->members); \
+ kfree(tmp); \
+ goto again; \
+ } \
+ \
+ /* Success at resizing! */ \
+ members = map->members; \
+ \
+ map->hashsize = tmp->hashsize; \
+ map->members = tmp->members; \
+ write_unlock_bh(&set->lock); \
+ \
+ harray_free(members); \
+ kfree(tmp); \
+ \
+ return 0; \
+}
+
+#define HASH_RETRY(type, dtype) \
+ HASH_RETRY0(type, dtype, *elem)
+
+#define HASH_RETRY2(type, dtype) \
+ HASH_RETRY0(type, dtype, elem->ip || elem->ip1)
+
+#define HASH_CREATE(type, dtype) \
+static int \
+type##_create(struct ip_set *set, const void *data, size_t size) \
+{ \
+ const struct ip_set_req_##type##_create *req = data; \
+ struct ip_set_##type *map; \
+ uint16_t i; \
+ \
+ if (req->hashsize < 1) { \
+ ip_set_printk("hashsize too small"); \
+ return -ENOEXEC; \
+ } \
+ \
+ if (req->probes < 1) { \
+ ip_set_printk("probes too small"); \
+ return -ENOEXEC; \
+ } \
+ \
+ map = kmalloc(sizeof(struct ip_set_##type) \
+ + req->probes * sizeof(uint32_t), GFP_KERNEL); \
+ if (!map) { \
+ DP("out of memory for %d bytes", \
+ sizeof(struct ip_set_##type) \
+ + req->probes * sizeof(uint32_t)); \
+ return -ENOMEM; \
+ } \
+ for (i = 0; i < req->probes; i++) \
+ get_random_bytes(((uint32_t *) map->initval)+i, 4); \
+ map->elements = 0; \
+ map->hashsize = req->hashsize; \
+ map->probes = req->probes; \
+ map->resize = req->resize; \
+ if (__##type##_create(req, map)) { \
+ kfree(map); \
+ return -ENOEXEC; \
+ } \
+ map->members = harray_malloc(map->hashsize, sizeof(dtype), GFP_KERNEL);\
+ if (!map->members) { \
+ DP("out of memory for %d bytes", map->hashsize * sizeof(dtype));\
+ kfree(map); \
+ return -ENOMEM; \
+ } \
+ \
+ set->data = map; \
+ return 0; \
+}
+
+#define HASH_DESTROY(type) \
+static void \
+type##_destroy(struct ip_set *set) \
+{ \
+ struct ip_set_##type *map = set->data; \
+ \
+ harray_free(map->members); \
+ kfree(map); \
+ \
+ set->data = NULL; \
+}
+
+#define HASH_FLUSH(type, dtype) \
+static void \
+type##_flush(struct ip_set *set) \
+{ \
+ struct ip_set_##type *map = set->data; \
+ harray_flush(map->members, map->hashsize, sizeof(dtype)); \
+ map->elements = 0; \
+}
+
+#define HASH_FLUSH_CIDR(type, dtype) \
+static void \
+type##_flush(struct ip_set *set) \
+{ \
+ struct ip_set_##type *map = set->data; \
+ harray_flush(map->members, map->hashsize, sizeof(dtype)); \
+ memset(map->cidr, 0, 30 * sizeof(uint8_t)); \
+ memset(map->nets, 0, 30 * sizeof(uint32_t)); \
+ map->elements = 0; \
+}
+
+#define HASH_LIST_HEADER(type) \
+static void \
+type##_list_header(const struct ip_set *set, void *data) \
+{ \
+ const struct ip_set_##type *map = set->data; \
+ struct ip_set_req_##type##_create *header = data; \
+ \
+ header->hashsize = map->hashsize; \
+ header->probes = map->probes; \
+ header->resize = map->resize; \
+ __##type##_list_header(map, header); \
+}
+
+#define HASH_LIST_MEMBERS_SIZE(type, dtype) \
+static int \
+type##_list_members_size(const struct ip_set *set) \
+{ \
+ const struct ip_set_##type *map = set->data; \
+ \
+ return (map->hashsize * sizeof(dtype)); \
+}
+
+#define HASH_LIST_MEMBERS(type, dtype) \
+static void \
+type##_list_members(const struct ip_set *set, void *data) \
+{ \
+ const struct ip_set_##type *map = set->data; \
+ dtype *elem; \
+ uint32_t i; \
+ \
+ for (i = 0; i < map->hashsize; i++) { \
+ elem = HARRAY_ELEM(map->members, dtype *, i); \
+ ((dtype *)data)[i] = *elem; \
+ } \
+}
+
+#define HASH_LIST_MEMBERS_MEMCPY(type, dtype) \
+static void \
+type##_list_members(const struct ip_set *set, void *data) \
+{ \
+ const struct ip_set_##type *map = set->data; \
+ dtype *elem; \
+ uint32_t i; \
+ \
+ for (i = 0; i < map->hashsize; i++) { \
+ elem = HARRAY_ELEM(map->members, dtype *, i); \
+ memcpy((((dtype *)data)+i), elem, sizeof(dtype)); \
+ } \
+}
+
+#define IP_SET_RTYPE(type, __features) \
+struct ip_set_type ip_set_##type = { \
+ .typename = #type, \
+ .features = __features, \
+ .protocol_version = IP_SET_PROTOCOL_VERSION, \
+ .create = &type##_create, \
+ .retry = &type##_retry, \
+ .destroy = &type##_destroy, \
+ .flush = &type##_flush, \
+ .reqsize = sizeof(struct ip_set_req_##type), \
+ .addip = &type##_uadd, \
+ .addip_kernel = &type##_kadd, \
+ .delip = &type##_udel, \
+ .delip_kernel = &type##_kdel, \
+ .testip = &type##_utest, \
+ .testip_kernel = &type##_ktest, \
+ .header_size = sizeof(struct ip_set_req_##type##_create),\
+ .list_header = &type##_list_header, \
+ .list_members_size = &type##_list_members_size, \
+ .list_members = &type##_list_members, \
+ .me = THIS_MODULE, \
+};
+
+/* Helper functions */
+static inline void
+add_cidr_size(uint8_t *cidr, uint8_t size)
+{
+ uint8_t next;
+ int i;
+
+ for (i = 0; i < 30 && cidr[i]; i++) {
+ if (cidr[i] < size) {
+ next = cidr[i];
+ cidr[i] = size;
+ size = next;
+ }
+ }
+ if (i < 30)
+ cidr[i] = size;
+}
+
+static inline void
+del_cidr_size(uint8_t *cidr, uint8_t size)
+{
+ int i;
+
+ for (i = 0; i < 29 && cidr[i]; i++) {
+ if (cidr[i] == size)
+ cidr[i] = size = cidr[i+1];
+ }
+ cidr[29] = 0;
+}
+#endif /* __KERNEL */
+
+#ifndef UINT16_MAX
+#define UINT16_MAX 65535
+#endif
+
+static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1};
+
+static inline ip_set_ip_t
+pack_ip_cidr(ip_set_ip_t ip, unsigned char cidr)
+{
+ ip_set_ip_t addr, *paddr = &addr;
+ unsigned char n, t, *a;
+
+ addr = htonl(ip & (0xFFFFFFFF << (32 - (cidr))));
+#ifdef __KERNEL__
+ DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
+#endif
+ n = cidr / 8;
+ t = cidr % 8;
+ a = &((unsigned char *)paddr)[n];
+ *a = *a /(1 << (8 - t)) + shifts[t];
+#ifdef __KERNEL__
+ DP("n: %u, t: %u, a: %u", n, t, *a);
+ DP("ip:%u.%u.%u.%u/%u, %u.%u.%u.%u",
+ HIPQUAD(ip), cidr, NIPQUAD(addr));
+#endif
+
+ return ntohl(addr);
+}
+
+
+#endif /* __IP_SET_HASHES_H */
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_iphash.h b/kernel/include/linux/netfilter_ipv4/ip_set_iphash.h
index 7de854b..7551cb2 100644
--- a/kernel/include/linux/netfilter_ipv4/ip_set_iphash.h
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_iphash.h
@@ -4,7 +4,6 @@
#include <linux/netfilter_ipv4/ip_set.h>
#define SETTYPE_NAME "iphash"
-#define MAX_RANGE 0x0000FFFF
struct ip_set_iphash {
ip_set_ip_t *members; /* the iphash proper */
@@ -13,7 +12,7 @@ struct ip_set_iphash {
uint16_t probes; /* max number of probes */
uint16_t resize; /* resize factor in percent */
ip_set_ip_t netmask; /* netmask */
- void *initval[0]; /* initvals for jhash_1word */
+ uint32_t initval[0]; /* initvals for jhash_1word */
};
struct ip_set_req_iphash_create {
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_ipmap.h b/kernel/include/linux/netfilter_ipv4/ip_set_ipmap.h
index e3390be..2f409d9 100644
--- a/kernel/include/linux/netfilter_ipv4/ip_set_ipmap.h
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_ipmap.h
@@ -4,7 +4,6 @@
#include <linux/netfilter_ipv4/ip_set.h>
#define SETTYPE_NAME "ipmap"
-#define MAX_RANGE 0x0000FFFF
struct ip_set_ipmap {
void *members; /* the ipmap proper */
@@ -13,6 +12,7 @@ struct ip_set_ipmap {
ip_set_ip_t netmask; /* subnet netmask */
ip_set_ip_t sizeid; /* size of set in IPs */
ip_set_ip_t hosts; /* number of hosts in a subnet */
+ size_t size; /* size of the ipmap proper */
};
struct ip_set_req_ipmap_create {
@@ -25,7 +25,7 @@ struct ip_set_req_ipmap {
ip_set_ip_t ip;
};
-static unsigned int
+static inline unsigned int
mask_to_bits(ip_set_ip_t mask)
{
unsigned int bits = 32;
@@ -41,7 +41,7 @@ mask_to_bits(ip_set_ip_t mask)
return bits;
}
-static ip_set_ip_t
+static inline ip_set_ip_t
range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits)
{
ip_set_ip_t mask = 0xFFFFFFFE;
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_ipporthash.h b/kernel/include/linux/netfilter_ipv4/ip_set_ipporthash.h
index b715c56..ccec14e 100644
--- a/kernel/include/linux/netfilter_ipv4/ip_set_ipporthash.h
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_ipporthash.h
@@ -4,8 +4,6 @@
#include <linux/netfilter_ipv4/ip_set.h>
#define SETTYPE_NAME "ipporthash"
-#define MAX_RANGE 0x0000FFFF
-#define INVALID_PORT (MAX_RANGE + 1)
struct ip_set_ipporthash {
ip_set_ip_t *members; /* the ipporthash proper */
@@ -15,7 +13,7 @@ struct ip_set_ipporthash {
uint16_t resize; /* resize factor in percent */
ip_set_ip_t first_ip; /* host byte order, included in range */
ip_set_ip_t last_ip; /* host byte order, included in range */
- void *initval[0]; /* initvals for jhash_1word */
+ uint32_t initval[0]; /* initvals for jhash_1word */
};
struct ip_set_req_ipporthash_create {
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_ipportiphash.h b/kernel/include/linux/netfilter_ipv4/ip_set_ipportiphash.h
new file mode 100644
index 0000000..4d794bf
--- /dev/null
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_ipportiphash.h
@@ -0,0 +1,38 @@
+#ifndef __IP_SET_IPPORTIPHASH_H
+#define __IP_SET_IPPORTIPHASH_H
+
+#include <linux/netfilter_ipv4/ip_set.h>
+
+#define SETTYPE_NAME "ipportiphash"
+
+struct ipportip {
+ ip_set_ip_t ip;
+ ip_set_ip_t ip1;
+};
+
+struct ip_set_ipportiphash {
+ struct ipportip *members; /* the ipportip proper */
+ uint32_t elements; /* number of elements */
+ uint32_t hashsize; /* hash size */
+ uint16_t probes; /* max number of probes */
+ uint16_t resize; /* resize factor in percent */
+ ip_set_ip_t first_ip; /* host byte order, included in range */
+ ip_set_ip_t last_ip; /* host byte order, included in range */
+ uint32_t initval[0]; /* initvals for jhash_1word */
+};
+
+struct ip_set_req_ipportiphash_create {
+ uint32_t hashsize;
+ uint16_t probes;
+ uint16_t resize;
+ ip_set_ip_t from;
+ ip_set_ip_t to;
+};
+
+struct ip_set_req_ipportiphash {
+ ip_set_ip_t ip;
+ ip_set_ip_t port;
+ ip_set_ip_t ip1;
+};
+
+#endif /* __IP_SET_IPPORTIPHASH_H */
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_ipportnethash.h b/kernel/include/linux/netfilter_ipv4/ip_set_ipportnethash.h
new file mode 100644
index 0000000..9c78a68
--- /dev/null
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_ipportnethash.h
@@ -0,0 +1,41 @@
+#ifndef __IP_SET_IPPORTNETHASH_H
+#define __IP_SET_IPPORTNETHASH_H
+
+#include <linux/netfilter_ipv4/ip_set.h>
+
+#define SETTYPE_NAME "ipportnethash"
+
+struct ipportip {
+ ip_set_ip_t ip;
+ ip_set_ip_t ip1;
+};
+
+struct ip_set_ipportnethash {
+ struct ipportip *members; /* the ipportip proper */
+ uint32_t elements; /* number of elements */
+ uint32_t hashsize; /* hash size */
+ uint16_t probes; /* max number of probes */
+ uint16_t resize; /* resize factor in percent */
+ ip_set_ip_t first_ip; /* host byte order, included in range */
+ ip_set_ip_t last_ip; /* host byte order, included in range */
+ uint8_t cidr[30]; /* CIDR sizes */
+ uint16_t nets[30]; /* nr of nets by CIDR sizes */
+ uint32_t initval[0]; /* initvals for jhash_1word */
+};
+
+struct ip_set_req_ipportnethash_create {
+ uint32_t hashsize;
+ uint16_t probes;
+ uint16_t resize;
+ ip_set_ip_t from;
+ ip_set_ip_t to;
+};
+
+struct ip_set_req_ipportnethash {
+ ip_set_ip_t ip;
+ ip_set_ip_t port;
+ ip_set_ip_t ip1;
+ uint8_t cidr;
+};
+
+#endif /* __IP_SET_IPPORTNETHASH_H */
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_iptree.h b/kernel/include/linux/netfilter_ipv4/ip_set_iptree.h
index 64e716b..de5cf47 100644
--- a/kernel/include/linux/netfilter_ipv4/ip_set_iptree.h
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_iptree.h
@@ -4,7 +4,6 @@
#include <linux/netfilter_ipv4/ip_set.h>
#define SETTYPE_NAME "iptree"
-#define MAX_RANGE 0x0000FFFF
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 bef576a..a58bc4e 100644
--- a/kernel/include/linux/netfilter_ipv4/ip_set_iptreemap.h
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_iptreemap.h
@@ -33,7 +33,7 @@ struct ip_set_req_iptreemap_create {
};
struct ip_set_req_iptreemap {
- ip_set_ip_t start;
+ ip_set_ip_t ip;
ip_set_ip_t end;
};
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_macipmap.h b/kernel/include/linux/netfilter_ipv4/ip_set_macipmap.h
index ee34c9b..82ea96d 100644
--- a/kernel/include/linux/netfilter_ipv4/ip_set_macipmap.h
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_macipmap.h
@@ -4,7 +4,6 @@
#include <linux/netfilter_ipv4/ip_set.h>
#define SETTYPE_NAME "macipmap"
-#define MAX_RANGE 0x0000FFFF
/* general flags */
#define IPSET_MACIP_MATCHUNSET 1
@@ -17,6 +16,7 @@ struct ip_set_macipmap {
ip_set_ip_t first_ip; /* host byte order, included in range */
ip_set_ip_t last_ip; /* host byte order, included in range */
u_int32_t flags;
+ size_t size; /* size of the ipmap proper */
};
struct ip_set_req_macipmap_create {
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_malloc.h b/kernel/include/linux/netfilter_ipv4/ip_set_malloc.h
index d22bed7..8bce667 100644
--- a/kernel/include/linux/netfilter_ipv4/ip_set_malloc.h
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_malloc.h
@@ -2,8 +2,10 @@
#define _IP_SET_MALLOC_H
#ifdef __KERNEL__
+#include <linux/vmalloc.h>
static size_t max_malloc_size = 0, max_page_size = 0;
+static size_t default_max_malloc_size = 131072; /* Guaranteed: slab.c */
static inline int init_max_page_size(void)
{
@@ -12,7 +14,7 @@ static inline int init_max_page_size(void)
#define __GFP_NOWARN 0
/* Guaranteed: slab.c */
- max_malloc_size = max_page_size = 131072;
+ max_malloc_size = max_page_size = default_max_malloc_size;
#else
size_t page_size = 0;
@@ -130,7 +132,7 @@ static inline void * ip_set_malloc(size_t bytes)
{
BUG_ON(max_malloc_size == 0);
- if (bytes > max_malloc_size)
+ if (bytes > default_max_malloc_size)
return vmalloc(bytes);
else
return kmalloc(bytes, GFP_KERNEL | __GFP_NOWARN);
@@ -140,7 +142,7 @@ static inline void ip_set_free(void * data, size_t bytes)
{
BUG_ON(max_malloc_size == 0);
- if (bytes > max_malloc_size)
+ if (bytes > default_max_malloc_size)
vfree(data);
else
kfree(data);
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_nethash.h b/kernel/include/linux/netfilter_ipv4/ip_set_nethash.h
index 172ef02..eecd68b 100644
--- a/kernel/include/linux/netfilter_ipv4/ip_set_nethash.h
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_nethash.h
@@ -4,7 +4,6 @@
#include <linux/netfilter_ipv4/ip_set.h>
#define SETTYPE_NAME "nethash"
-#define MAX_RANGE 0x0000FFFF
struct ip_set_nethash {
ip_set_ip_t *members; /* the nethash proper */
@@ -12,8 +11,9 @@ struct ip_set_nethash {
uint32_t hashsize; /* hash size */
uint16_t probes; /* max number of probes */
uint16_t resize; /* resize factor in percent */
- unsigned char cidr[30]; /* CIDR sizes */
- void *initval[0]; /* initvals for jhash_1word */
+ uint8_t cidr[30]; /* CIDR sizes */
+ uint16_t nets[30]; /* nr of nets by CIDR sizes */
+ uint32_t initval[0]; /* initvals for jhash_1word */
};
struct ip_set_req_nethash_create {
@@ -24,32 +24,7 @@ struct ip_set_req_nethash_create {
struct ip_set_req_nethash {
ip_set_ip_t ip;
- unsigned char cidr;
+ uint8_t cidr;
};
-static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1};
-
-static inline ip_set_ip_t
-pack(ip_set_ip_t ip, unsigned char cidr)
-{
- ip_set_ip_t addr, *paddr = &addr;
- unsigned char n, t, *a;
-
- addr = htonl(ip & (0xFFFFFFFF << (32 - (cidr))));
-#ifdef __KERNEL__
- DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
-#endif
- n = cidr / 8;
- t = cidr % 8;
- a = &((unsigned char *)paddr)[n];
- *a = *a /(1 << (8 - t)) + shifts[t];
-#ifdef __KERNEL__
- DP("n: %u, t: %u, a: %u", n, t, *a);
- DP("ip:%u.%u.%u.%u/%u, %u.%u.%u.%u",
- HIPQUAD(ip), cidr, NIPQUAD(addr));
-#endif
-
- return ntohl(addr);
-}
-
#endif /* __IP_SET_NETHASH_H */
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_portmap.h b/kernel/include/linux/netfilter_ipv4/ip_set_portmap.h
index c17165c..1a15380 100644
--- a/kernel/include/linux/netfilter_ipv4/ip_set_portmap.h
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_portmap.h
@@ -4,13 +4,12 @@
#include <linux/netfilter_ipv4/ip_set.h>
#define SETTYPE_NAME "portmap"
-#define MAX_RANGE 0x0000FFFF
-#define INVALID_PORT (MAX_RANGE + 1)
struct ip_set_portmap {
void *members; /* the portmap proper */
- ip_set_ip_t first_port; /* host byte order, included in range */
- ip_set_ip_t last_port; /* host byte order, included in range */
+ ip_set_ip_t first_ip; /* host byte order, included in range */
+ ip_set_ip_t last_ip; /* host byte order, included in range */
+ size_t size; /* size of the ipmap proper */
};
struct ip_set_req_portmap_create {
@@ -19,7 +18,7 @@ struct ip_set_req_portmap_create {
};
struct ip_set_req_portmap {
- ip_set_ip_t port;
+ ip_set_ip_t ip;
};
#endif /* __IP_SET_PORTMAP_H */
diff --git a/kernel/include/linux/netfilter_ipv4/ip_set_setlist.h b/kernel/include/linux/netfilter_ipv4/ip_set_setlist.h
new file mode 100644
index 0000000..55f0afb
--- /dev/null
+++ b/kernel/include/linux/netfilter_ipv4/ip_set_setlist.h
@@ -0,0 +1,26 @@
+#ifndef __IP_SET_SETLIST_H
+#define __IP_SET_SETLIST_H
+
+#include <linux/netfilter_ipv4/ip_set.h>
+
+#define SETTYPE_NAME "setlist"
+
+#define IP_SET_SETLIST_ADD_AFTER 0
+#define IP_SET_SETLIST_ADD_BEFORE 1
+
+struct ip_set_setlist {
+ uint8_t size;
+ ip_set_id_t id[0];
+};
+
+struct ip_set_req_setlist_create {
+ uint8_t size;
+};
+
+struct ip_set_req_setlist {
+ char name[IP_SET_MAXNAMELEN];
+ char ref[IP_SET_MAXNAMELEN];
+ uint8_t before;
+};
+
+#endif /* __IP_SET_SETLIST_H */
diff --git a/kernel/ip_set.c b/kernel/ip_set.c
index a525518..c4fcc69 100644
--- a/kernel/ip_set.c
+++ b/kernel/ip_set.c
@@ -20,7 +20,6 @@
#include <linux/skbuff.h>
#include <linux/random.h>
#include <linux/jhash.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
@@ -30,10 +29,10 @@
#include <linux/semaphore.h>
#endif
#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
#define ASSERT_READ_LOCK(x)
#define ASSERT_WRITE_LOCK(x)
+#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_set.h>
static struct list_head set_type_list; /* all registered sets */
@@ -235,10 +234,10 @@ ip_set_testip_kernel(ip_set_id_t index,
&& follow_bindings(index, set, ip));
read_unlock_bh(&ip_set_lock);
- return res;
+ return (res < 0 ? 0 : res);
}
-void
+int
ip_set_addip_kernel(ip_set_id_t index,
const struct sk_buff *skb,
const u_int32_t *flags)
@@ -268,9 +267,11 @@ ip_set_addip_kernel(ip_set_id_t index,
&& set->type->retry
&& (res = set->type->retry(set)) == 0)
goto retry;
+
+ return res;
}
-void
+int
ip_set_delip_kernel(ip_set_id_t index,
const struct sk_buff *skb,
const u_int32_t *flags)
@@ -294,6 +295,8 @@ ip_set_delip_kernel(ip_set_id_t index,
&& flags[i]
&& follow_bindings(index, set, ip));
read_unlock_bh(&ip_set_lock);
+
+ return res;
}
/* Register and deregister settype */
@@ -358,6 +361,29 @@ ip_set_unregister_set_type(struct ip_set_type *set_type)
}
+ip_set_id_t
+__ip_set_get_byname(const char *name, struct ip_set **set)
+{
+ ip_set_id_t i, index = IP_SET_INVALID_ID;
+
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+ && SETNAME_EQ(ip_set_list[i]->name, name)) {
+ __ip_set_get(i);
+ index = i;
+ *set = ip_set_list[i];
+ break;
+ }
+ }
+ return index;
+}
+
+void __ip_set_put_byid(ip_set_id_t index)
+{
+ if (ip_set_list[index])
+ __ip_set_put(index);
+}
+
/*
* Userspace routines
*/
@@ -490,7 +516,16 @@ ip_set_addip(ip_set_id_t index,
const void *data,
size_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 %zu, have %zu)",
+ 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));
@@ -506,6 +541,13 @@ ip_set_delip(ip_set_id_t index,
int res;
IP_SET_ASSERT(set);
+
+ if (size - sizeof(struct ip_set_req_adt) != set->type->reqsize) {
+ ip_set_printk("data length wrong (want %zu, have %zu)",
+ 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),
@@ -526,6 +568,13 @@ ip_set_testip(ip_set_id_t index,
int res;
IP_SET_ASSERT(set);
+
+ if (size - sizeof(struct ip_set_req_adt) != set->type->reqsize) {
+ ip_set_printk("data length wrong (want %zu, have %zu)",
+ 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),
@@ -805,6 +854,7 @@ ip_set_create(const char *name,
int res = 0;
DP("setname: %s, typename: %s, id: %u", name, typename, restore);
+
/*
* First, and without any locks, allocate and initialize
* a normal base set structure.
@@ -848,6 +898,14 @@ ip_set_create(const char *name,
}
read_unlock_bh(&ip_set_lock);
+ /* Check request size */
+ if (size != set->type->header_size) {
+ ip_set_printk("data length wrong (want %zu, have %zu)",
+ set->type->header_size,
+ size);
+ goto put_out;
+ }
+
/*
* Without holding any locks, create private part.
*/
@@ -1007,7 +1065,9 @@ ip_set_swap(ip_set_id_t from_index, ip_set_id_t to_index)
u_int32_t from_ref;
DP("set: %s to %s", from->name, to->name);
- /* Features must not change. Artifical restriction. */
+ /* Features must not change.
+ * Not an artifical restriction anymore, as we must prevent
+ * possible loops created by swapping in setlist type of sets. */
if (from->type->features != to->type->features)
return -ENOEXEC;
@@ -1916,6 +1976,7 @@ static struct nf_sockopt_ops so_set = {
};
static int max_sets, hash_size;
+
module_param(max_sets, int, 0600);
MODULE_PARM_DESC(max_sets, "maximal number of sets");
module_param(hash_size, int, 0600);
@@ -1958,6 +2019,7 @@ static int __init ip_set_init(void)
vfree(ip_set_hash);
return res;
}
+
return 0;
}
@@ -1976,6 +2038,8 @@ EXPORT_SYMBOL(ip_set_unregister_set_type);
EXPORT_SYMBOL(ip_set_get_byname);
EXPORT_SYMBOL(ip_set_get_byindex);
EXPORT_SYMBOL(ip_set_put);
+EXPORT_SYMBOL(__ip_set_get_byname);
+EXPORT_SYMBOL(__ip_set_put_byid);
EXPORT_SYMBOL(ip_set_addip_kernel);
EXPORT_SYMBOL(ip_set_delip_kernel);
diff --git a/kernel/ip_set_iphash.c b/kernel/ip_set_iphash.c
index 2ac6066..38b83ed 100644
--- a/kernel/ip_set_iphash.c
+++ b/kernel/ip_set_iphash.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -11,32 +11,23 @@
#include <linux/moduleparam.h>
#include <linux/ip.h>
#include <linux/skbuff.h>
-#include <linux/version.h>
#include <linux/jhash.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_set.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
#include <linux/random.h>
#include <net/ip.h>
-#include <linux/netfilter_ipv4/ip_set_malloc.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_hashes.h>
#include <linux/netfilter_ipv4/ip_set_iphash.h>
static int limit = MAX_RANGE;
static inline __u32
-jhash_ip(const struct ip_set_iphash *map, uint16_t i, ip_set_ip_t ip)
-{
- return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
-}
-
-static inline __u32
-hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+iphash_id(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_iphash *map = set->data;
__u32 id;
@@ -60,59 +51,30 @@ hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
}
static inline int
-__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+iphash_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
- return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
+ return (ip && iphash_id(set, hash_ip, ip) != UINT_MAX);
}
-static int
-testip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_iphash *req = data;
+#define KADT_CONDITION
- if (size != sizeof(struct ip_set_req_iphash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_iphash),
- size);
- return -EINVAL;
- }
- return __testip(set, req->ip, hash_ip);
-}
-
-static int
-testip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- return __testip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
+UADT(iphash, test)
+KADT(iphash, test, ipaddr)
static inline int
-__addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+__iphash_add(struct ip_set_iphash *map, ip_set_ip_t *ip)
{
__u32 probe;
u_int16_t i;
ip_set_ip_t *elem;
- if (!ip || map->elements >= limit)
- return -ERANGE;
-
- *hash_ip = ip & map->netmask;
-
for (i = 0; i < map->probes; i++) {
- probe = jhash_ip(map, i, *hash_ip) % map->hashsize;
+ probe = jhash_ip(map, i, *ip) % map->hashsize;
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
- if (*elem == *hash_ip)
+ if (*elem == *ip)
return -EEXIST;
if (!*elem) {
- *elem = *hash_ip;
+ *elem = *ip;
map->elements++;
return 0;
}
@@ -121,110 +83,32 @@ __addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return -EAGAIN;
}
-static int
-addip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_iphash *req = data;
-
- if (size != sizeof(struct ip_set_req_iphash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_iphash),
- size);
- return -EINVAL;
- }
- return __addip(set->data, req->ip, hash_ip);
-}
-
-static int
-addip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- return __addip((struct ip_set_iphash *) set->data,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
-
-static int retry(struct ip_set *set)
+static inline int
+iphash_add(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_iphash *map = set->data;
- ip_set_ip_t hash_ip, *elem;
- void *members;
- u_int32_t i, hashsize = map->hashsize;
- int res;
- struct ip_set_iphash *tmp;
- if (map->resize == 0)
+ if (!ip || map->elements >= limit)
return -ERANGE;
- again:
- res = 0;
-
- /* Calculate new hash size */
- hashsize += (hashsize * map->resize)/100;
- if (hashsize == map->hashsize)
- hashsize++;
-
- ip_set_printk("rehashing of set %s triggered: "
- "hashsize grows from %u to %u",
- set->name, map->hashsize, hashsize);
-
- tmp = kmalloc(sizeof(struct ip_set_iphash)
- + map->probes * sizeof(uint32_t), GFP_ATOMIC);
- if (!tmp) {
- DP("out of memory for %d bytes",
- sizeof(struct ip_set_iphash)
- + map->probes * sizeof(uint32_t));
- return -ENOMEM;
- }
- tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
- if (!tmp->members) {
- DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
- kfree(tmp);
- return -ENOMEM;
- }
- tmp->hashsize = hashsize;
- tmp->elements = 0;
- tmp->probes = map->probes;
- tmp->resize = map->resize;
- tmp->netmask = map->netmask;
- memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
-
- write_lock_bh(&set->lock);
- map = set->data; /* Play safe */
- for (i = 0; i < map->hashsize && res == 0; i++) {
- elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
- if (*elem)
- res = __addip(tmp, *elem, &hash_ip);
- }
- if (res) {
- /* Failure, try again */
- write_unlock_bh(&set->lock);
- harray_free(tmp->members);
- kfree(tmp);
- goto again;
- }
+ *hash_ip = ip & map->netmask;
- /* Success at resizing! */
- members = map->members;
-
- map->hashsize = tmp->hashsize;
- map->members = tmp->members;
- write_unlock_bh(&set->lock);
+ return __iphash_add(map, hash_ip);
+}
- harray_free(members);
- kfree(tmp);
+UADT(iphash, add)
+KADT(iphash, add, ipaddr)
- return 0;
+static inline void
+__iphash_retry(struct ip_set_iphash *tmp, struct ip_set_iphash *map)
+{
+ tmp->netmask = map->netmask;
}
+HASH_RETRY(iphash, ip_set_ip_t)
+
static inline int
-__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+iphash_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_iphash *map = set->data;
ip_set_ip_t id, *elem;
@@ -232,7 +116,7 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
if (!ip)
return -ERANGE;
- id = hash_id(set, ip, hash_ip);
+ id = iphash_id(set, hash_ip, ip);
if (id == UINT_MAX)
return -EEXIST;
@@ -243,151 +127,35 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return 0;
}
-static int
-delip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_iphash *req = data;
+UADT(iphash, del)
+KADT(iphash, del, ipaddr)
- if (size != sizeof(struct ip_set_req_iphash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_iphash),
- size);
- return -EINVAL;
- }
- return __delip(set, req->ip, hash_ip);
-}
-
-static int
-delip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- return __delip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
-
-static int create(struct ip_set *set, const void *data, size_t size)
+static inline int
+__iphash_create(const struct ip_set_req_iphash_create *req,
+ struct ip_set_iphash *map)
{
- const struct ip_set_req_iphash_create *req = data;
- struct ip_set_iphash *map;
- uint16_t i;
-
- if (size != sizeof(struct ip_set_req_iphash_create)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_iphash_create),
- size);
- return -EINVAL;
- }
-
- if (req->hashsize < 1) {
- ip_set_printk("hashsize too small");
- return -ENOEXEC;
- }
-
- if (req->probes < 1) {
- ip_set_printk("probes too small");
- return -ENOEXEC;
- }
-
- map = kmalloc(sizeof(struct ip_set_iphash)
- + req->probes * sizeof(uint32_t), GFP_KERNEL);
- if (!map) {
- DP("out of memory for %d bytes",
- sizeof(struct ip_set_iphash)
- + req->probes * sizeof(uint32_t));
- return -ENOMEM;
- }
- for (i = 0; i < req->probes; i++)
- get_random_bytes(((uint32_t *) map->initval)+i, 4);
- map->elements = 0;
- map->hashsize = req->hashsize;
- map->probes = req->probes;
- map->resize = req->resize;
map->netmask = req->netmask;
- map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
- if (!map->members) {
- DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
- kfree(map);
- return -ENOMEM;
- }
-
- set->data = map;
+
return 0;
}
-static void destroy(struct ip_set *set)
-{
- struct ip_set_iphash *map = set->data;
+HASH_CREATE(iphash, ip_set_ip_t)
+HASH_DESTROY(iphash)
- harray_free(map->members);
- kfree(map);
-
- set->data = NULL;
-}
+HASH_FLUSH(iphash, ip_set_ip_t)
-static void flush(struct ip_set *set)
-{
- struct ip_set_iphash *map = set->data;
- harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
- map->elements = 0;
-}
-
-static void list_header(const struct ip_set *set, void *data)
-{
- struct ip_set_iphash *map = set->data;
- struct ip_set_req_iphash_create *header = data;
-
- header->hashsize = map->hashsize;
- header->probes = map->probes;
- header->resize = map->resize;
+static inline void
+__iphash_list_header(const struct ip_set_iphash *map,
+ struct ip_set_req_iphash_create *header)
+{
header->netmask = map->netmask;
}
-static int list_members_size(const struct ip_set *set)
-{
- const struct ip_set_iphash *map = set->data;
+HASH_LIST_HEADER(iphash)
+HASH_LIST_MEMBERS_SIZE(iphash, ip_set_ip_t)
+HASH_LIST_MEMBERS(iphash, ip_set_ip_t)
- return (map->hashsize * sizeof(ip_set_ip_t));
-}
-
-static void list_members(const struct ip_set *set, void *data)
-{
- const struct ip_set_iphash *map = set->data;
- ip_set_ip_t i, *elem;
-
- for (i = 0; i < map->hashsize; i++) {
- elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
- ((ip_set_ip_t *)data)[i] = *elem;
- }
-}
-
-static struct ip_set_type ip_set_iphash = {
- .typename = SETTYPE_NAME,
- .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
- .protocol_version = IP_SET_PROTOCOL_VERSION,
- .create = &create,
- .destroy = &destroy,
- .flush = &flush,
- .reqsize = sizeof(struct ip_set_req_iphash),
- .addip = &addip,
- .addip_kernel = &addip_kernel,
- .retry = &retry,
- .delip = &delip,
- .delip_kernel = &delip_kernel,
- .testip = &testip,
- .testip_kernel = &testip_kernel,
- .header_size = sizeof(struct ip_set_req_iphash_create),
- .list_header = &list_header,
- .list_members_size = &list_members_size,
- .list_members = &list_members,
- .me = THIS_MODULE,
-};
+IP_SET_RTYPE(iphash, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -395,17 +163,4 @@ MODULE_DESCRIPTION("iphash type of IP sets");
module_param(limit, int, 0600);
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
-static int __init ip_set_iphash_init(void)
-{
- init_max_page_size();
- return ip_set_register_set_type(&ip_set_iphash);
-}
-
-static void __exit ip_set_iphash_fini(void)
-{
- /* FIXME: possible race with ip_set_create() */
- ip_set_unregister_set_type(&ip_set_iphash);
-}
-
-module_init(ip_set_iphash_init);
-module_exit(ip_set_iphash_fini);
+REGISTER_MODULE(iphash)
diff --git a/kernel/ip_set_ipmap.c b/kernel/ip_set_ipmap.c
index aeead3b..e1a1663 100644
--- a/kernel/ip_set_ipmap.c
+++ b/kernel/ip_set_ipmap.c
@@ -1,6 +1,6 @@
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de>
- * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,14 +12,13 @@
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/skbuff.h>
-#include <linux/version.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_set.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_bitmaps.h>
#include <linux/netfilter_ipv4/ip_set_ipmap.h>
static inline ip_set_ip_t
@@ -29,9 +28,9 @@ ip_to_id(const struct ip_set_ipmap *map, ip_set_ip_t ip)
}
static inline int
-__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+ipmap_test(const struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
- struct ip_set_ipmap *map = set->data;
+ const struct ip_set_ipmap *map = set->data;
if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE;
@@ -42,38 +41,13 @@ __testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return !!test_bit(ip_to_id(map, *hash_ip), map->members);
}
-static int
-testip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_ipmap *req = data;
+#define KADT_CONDITION
- if (size != sizeof(struct ip_set_req_ipmap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_ipmap),
- size);
- return -EINVAL;
- }
- return __testip(set, req->ip, hash_ip);
-}
-
-static int
-testip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- int res = __testip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
- return (res < 0 ? 0 : res);
-}
+UADT(ipmap, test)
+KADT(ipmap, test, ipaddr)
static inline int
-__addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+ipmap_add(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_ipmap *map = set->data;
@@ -88,38 +62,11 @@ __addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return 0;
}
-static int
-addip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_ipmap *req = data;
-
- if (size != sizeof(struct ip_set_req_ipmap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_ipmap),
- size);
- return -EINVAL;
- }
- DP("%u.%u.%u.%u", HIPQUAD(req->ip));
- return __addip(set, req->ip, hash_ip);
-}
-
-static int
-addip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- return __addip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
+UADT(ipmap, add)
+KADT(ipmap, add, ipaddr)
static inline int
-__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+ipmap_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_ipmap *map = set->data;
@@ -134,64 +81,13 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return 0;
}
-static int
-delip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_ipmap *req = data;
+UADT(ipmap, del)
+KADT(ipmap, del, ipaddr)
- if (size != sizeof(struct ip_set_req_ipmap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_ipmap),
- size);
- return -EINVAL;
- }
- return __delip(set, req->ip, hash_ip);
-}
-
-static int
-delip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- return __delip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
-
-static int create(struct ip_set *set, const void *data, size_t size)
+static inline int
+__ipmap_create(const struct ip_set_req_ipmap_create *req,
+ struct ip_set_ipmap *map)
{
- int newbytes;
- const struct ip_set_req_ipmap_create *req = data;
- struct ip_set_ipmap *map;
-
- if (size != sizeof(struct ip_set_req_ipmap_create)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_ipmap_create),
- size);
- return -EINVAL;
- }
-
- DP("from %u.%u.%u.%u to %u.%u.%u.%u",
- HIPQUAD(req->from), HIPQUAD(req->to));
-
- if (req->from > req->to) {
- DP("bad ip range");
- return -ENOEXEC;
- }
-
- map = kmalloc(sizeof(struct ip_set_ipmap), GFP_KERNEL);
- if (!map) {
- DP("out of memory for %d bytes",
- sizeof(struct ip_set_ipmap));
- return -ENOMEM;
- }
- map->first_ip = req->from;
- map->last_ip = req->to;
map->netmask = req->netmask;
if (req->netmask == 0xFFFFFFFF) {
@@ -200,12 +96,12 @@ static int create(struct ip_set *set, const void *data, size_t size)
} else {
unsigned int mask_bits, netmask_bits;
ip_set_ip_t mask;
-
+
map->first_ip &= map->netmask; /* Should we better bark? */
-
+
mask = range_to_mask(map->first_ip, map->last_ip, &mask_bits);
netmask_bits = mask_to_bits(map->netmask);
-
+
if ((!mask && (map->first_ip || map->last_ip != 0xFFFFFFFF))
|| netmask_bits <= mask_bits)
return -ENOEXEC;
@@ -216,101 +112,33 @@ static int create(struct ip_set *set, const void *data, size_t size)
map->sizeid = 2 << (netmask_bits - mask_bits - 1);
}
if (map->sizeid > MAX_RANGE + 1) {
- ip_set_printk("range too big (max %d addresses)",
- MAX_RANGE+1);
- kfree(map);
+ ip_set_printk("range too big, %d elements (max %d)",
+ map->sizeid, MAX_RANGE+1);
return -ENOEXEC;
}
DP("hosts %u, sizeid %u", map->hosts, map->sizeid);
- newbytes = bitmap_bytes(0, map->sizeid - 1);
- map->members = kmalloc(newbytes, GFP_KERNEL);
- if (!map->members) {
- DP("out of memory for %d bytes", newbytes);
- kfree(map);
- return -ENOMEM;
- }
- memset(map->members, 0, newbytes);
-
- set->data = map;
- return 0;
-}
-
-static void destroy(struct ip_set *set)
-{
- struct ip_set_ipmap *map = set->data;
-
- kfree(map->members);
- kfree(map);
-
- set->data = NULL;
+ return bitmap_bytes(0, map->sizeid - 1);
}
-static void flush(struct ip_set *set)
-{
- struct ip_set_ipmap *map = set->data;
- memset(map->members, 0, bitmap_bytes(0, map->sizeid - 1));
-}
+BITMAP_CREATE(ipmap)
+BITMAP_DESTROY(ipmap)
+BITMAP_FLUSH(ipmap)
-static void list_header(const struct ip_set *set, void *data)
+static inline void
+__ipmap_list_header(const struct ip_set_ipmap *map,
+ struct ip_set_req_ipmap_create *header)
{
- const struct ip_set_ipmap *map = set->data;
- struct ip_set_req_ipmap_create *header = data;
-
- header->from = map->first_ip;
- header->to = map->last_ip;
header->netmask = map->netmask;
}
-static int list_members_size(const struct ip_set *set)
-{
- const struct ip_set_ipmap *map = set->data;
-
- return bitmap_bytes(0, map->sizeid - 1);
-}
-
-static void list_members(const struct ip_set *set, void *data)
-{
- const struct ip_set_ipmap *map = set->data;
- int bytes = bitmap_bytes(0, map->sizeid - 1);
+BITMAP_LIST_HEADER(ipmap)
+BITMAP_LIST_MEMBERS_SIZE(ipmap)
+BITMAP_LIST_MEMBERS(ipmap)
- memcpy(data, map->members, bytes);
-}
-
-static struct ip_set_type ip_set_ipmap = {
- .typename = SETTYPE_NAME,
- .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
- .protocol_version = IP_SET_PROTOCOL_VERSION,
- .create = &create,
- .destroy = &destroy,
- .flush = &flush,
- .reqsize = sizeof(struct ip_set_req_ipmap),
- .addip = &addip,
- .addip_kernel = &addip_kernel,
- .delip = &delip,
- .delip_kernel = &delip_kernel,
- .testip = &testip,
- .testip_kernel = &testip_kernel,
- .header_size = sizeof(struct ip_set_req_ipmap_create),
- .list_header = &list_header,
- .list_members_size = &list_members_size,
- .list_members = &list_members,
- .me = THIS_MODULE,
-};
+IP_SET_TYPE(ipmap, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("ipmap type of IP sets");
-static int __init ip_set_ipmap_init(void)
-{
- return ip_set_register_set_type(&ip_set_ipmap);
-}
-
-static void __exit ip_set_ipmap_fini(void)
-{
- /* FIXME: possible race with ip_set_create() */
- ip_set_unregister_set_type(&ip_set_ipmap);
-}
-
-module_init(ip_set_ipmap_init);
-module_exit(ip_set_ipmap_fini);
+REGISTER_MODULE(ipmap)
diff --git a/kernel/ip_set_ipporthash.c b/kernel/ip_set_ipporthash.c
index 4e656cd..1dd39c3 100644
--- a/kernel/ip_set_ipporthash.c
+++ b/kernel/ip_set_ipporthash.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,82 +13,32 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/skbuff.h>
-#include <linux/version.h>
#include <linux/jhash.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_set.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
#include <linux/random.h>
#include <net/ip.h>
-#include <linux/netfilter_ipv4/ip_set_malloc.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_hashes.h>
#include <linux/netfilter_ipv4/ip_set_ipporthash.h>
+#include <linux/netfilter_ipv4/ip_set_getport.h>
static int limit = MAX_RANGE;
-/* We must handle non-linear skbs */
-static inline ip_set_ip_t
-get_port(const struct sk_buff *skb, u_int32_t flags)
-{
- struct iphdr *iph = ip_hdr(skb);
- u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
-
- switch (iph->protocol) {
- case IPPROTO_TCP: {
- struct tcphdr tcph;
-
- /* See comments at tcp_match in ip_tables.c */
- if (offset)
- return INVALID_PORT;
-
- if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &tcph, sizeof(tcph)) < 0)
- /* No choice either */
- return INVALID_PORT;
-
- return ntohs(flags & IPSET_SRC ?
- tcph.source : tcph.dest);
- }
- case IPPROTO_UDP: {
- struct udphdr udph;
-
- if (offset)
- return INVALID_PORT;
-
- if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &udph, sizeof(udph)) < 0)
- /* No choice either */
- return INVALID_PORT;
-
- return ntohs(flags & IPSET_SRC ?
- udph.source : udph.dest);
- }
- default:
- return INVALID_PORT;
- }
-}
-
-static inline __u32
-jhash_ip(const struct ip_set_ipporthash *map, uint16_t i, ip_set_ip_t ip)
-{
- return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
-}
-
-#define HASH_IP(map, ip, port) (port + ((ip - ((map)->first_ip)) << 16))
-
static inline __u32
-hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
- ip_set_ip_t *hash_ip)
+ipporthash_id(struct ip_set *set, ip_set_ip_t *hash_ip,
+ 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 = HASH_IP(map, ip, port);
+ *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));
@@ -105,81 +55,45 @@ hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
}
static inline int
-__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
- ip_set_ip_t *hash_ip)
+ipporthash_test(struct ip_set *set, ip_set_ip_t *hash_ip,
+ 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 (hash_id(set, ip, port, hash_ip) != UINT_MAX);
+ return (ipporthash_id(set, hash_ip, ip, port) != UINT_MAX);
}
-static int
-testip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_ipporthash *req = data;
-
- if (size != sizeof(struct ip_set_req_ipporthash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_ipporthash),
- size);
- return -EINVAL;
- }
- return __testip(set, req->ip, req->port, hash_ip);
-}
-
-static int
-testip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- ip_set_ip_t port;
- int res;
-
- if (flags[index+1] == 0)
+#define KADT_CONDITION \
+ ip_set_ip_t port; \
+ \
+ if (flags[index+1] == 0) \
+ return 0; \
+ \
+ port = get_port(skb, flags[index+1]); \
+ \
+ if (port == INVALID_PORT) \
return 0;
-
- port = get_port(skb, flags[index+1]);
-
- DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
- flags[index] & IPSET_SRC ? "SRC" : "DST",
- NIPQUAD(ip_hdr(skb)->saddr),
- NIPQUAD(ip_hdr(skb)->daddr));
- DP("flag %s port %u",
- flags[index+1] & IPSET_SRC ? "SRC" : "DST",
- port);
- if (port == INVALID_PORT)
- return 0;
- res = __testip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- port,
- hash_ip);
- return (res < 0 ? 0 : res);
-
-}
+UADT(ipporthash, test, req->port)
+KADT(ipporthash, test, ipaddr, port)
static inline int
-__add_haship(struct ip_set_ipporthash *map, ip_set_ip_t hash_ip)
+__ipporthash_add(struct ip_set_ipporthash *map, ip_set_ip_t *ip)
{
__u32 probe;
u_int16_t i;
ip_set_ip_t *elem;
for (i = 0; i < map->probes; i++) {
- probe = jhash_ip(map, i, hash_ip) % map->hashsize;
+ probe = jhash_ip(map, i, *ip) % map->hashsize;
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
- if (*elem == hash_ip)
+ if (*elem == *ip)
return -EEXIST;
if (!*elem) {
- *elem = hash_ip;
+ *elem = *ip;
map->elements++;
return 0;
}
@@ -189,143 +103,36 @@ __add_haship(struct ip_set_ipporthash *map, ip_set_ip_t hash_ip)
}
static inline int
-__addip(struct ip_set_ipporthash *map, ip_set_ip_t ip, ip_set_ip_t port,
- ip_set_ip_t *hash_ip)
+ipporthash_add(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port)
{
+ struct ip_set_ipporthash *map = set->data;
if (map->elements > limit)
return -ERANGE;
if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE;
- *hash_ip = HASH_IP(map, ip, port);
+ *hash_ip = pack_ip_port(map, ip, port);
- return __add_haship(map, *hash_ip);
-}
-
-static int
-addip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_ipporthash *req = data;
-
- if (size != sizeof(struct ip_set_req_ipporthash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_ipporthash),
- size);
- return -EINVAL;
- }
- return __addip(set->data, req->ip, req->port, hash_ip);
+ return __ipporthash_add(map, hash_ip);
}
-static int
-addip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- ip_set_ip_t port;
-
- if (flags[index+1] == 0)
- return -EINVAL;
-
- port = get_port(skb, flags[index+1]);
-
- DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
- flags[index] & IPSET_SRC ? "SRC" : "DST",
- NIPQUAD(ip_hdr(skb)->saddr),
- NIPQUAD(ip_hdr(skb)->daddr));
- DP("flag %s port %u",
- flags[index+1] & IPSET_SRC ? "SRC" : "DST",
- port);
- if (port == INVALID_PORT)
- return -EINVAL;
-
- return __addip(set->data,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- port,
- hash_ip);
-}
+UADT(ipporthash, add, req->port)
+KADT(ipporthash, add, ipaddr, port)
-static int retry(struct ip_set *set)
+static inline void
+__ipporthash_retry(struct ip_set_ipporthash *tmp,
+ struct ip_set_ipporthash *map)
{
- struct ip_set_ipporthash *map = set->data;
- ip_set_ip_t *elem;
- void *members;
- u_int32_t i, hashsize = map->hashsize;
- int res;
- struct ip_set_ipporthash *tmp;
-
- if (map->resize == 0)
- return -ERANGE;
-
- again:
- res = 0;
-
- /* Calculate new hash size */
- hashsize += (hashsize * map->resize)/100;
- if (hashsize == map->hashsize)
- hashsize++;
-
- ip_set_printk("rehashing of set %s triggered: "
- "hashsize grows from %u to %u",
- set->name, map->hashsize, hashsize);
-
- tmp = kmalloc(sizeof(struct ip_set_ipporthash)
- + map->probes * sizeof(uint32_t), GFP_ATOMIC);
- if (!tmp) {
- DP("out of memory for %d bytes",
- sizeof(struct ip_set_ipporthash)
- + map->probes * sizeof(uint32_t));
- return -ENOMEM;
- }
- tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
- if (!tmp->members) {
- DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
- kfree(tmp);
- return -ENOMEM;
- }
- tmp->hashsize = hashsize;
- tmp->elements = 0;
- tmp->probes = map->probes;
- tmp->resize = map->resize;
tmp->first_ip = map->first_ip;
tmp->last_ip = map->last_ip;
- memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
-
- write_lock_bh(&set->lock);
- map = set->data; /* Play safe */
- for (i = 0; i < map->hashsize && res == 0; i++) {
- elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
- if (*elem)
- res = __add_haship(tmp, *elem);
- }
- if (res) {
- /* Failure, try again */
- write_unlock_bh(&set->lock);
- harray_free(tmp->members);
- kfree(tmp);
- goto again;
- }
-
- /* Success at resizing! */
- members = map->members;
-
- map->hashsize = tmp->hashsize;
- map->members = tmp->members;
- write_unlock_bh(&set->lock);
-
- harray_free(members);
- kfree(tmp);
-
- return 0;
}
+HASH_RETRY(ipporthash, ip_set_ip_t)
+
static inline int
-__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
- ip_set_ip_t *hash_ip)
+ipporthash_del(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port)
{
struct ip_set_ipporthash *map = set->data;
ip_set_ip_t id;
@@ -334,7 +141,7 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE;
- id = hash_id(set, ip, port, hash_ip);
+ id = ipporthash_id(set, hash_ip, ip, port);
if (id == UINT_MAX)
return -EEXIST;
@@ -346,171 +153,40 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
return 0;
}
-static int
-delip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_ipporthash *req = data;
-
- if (size != sizeof(struct ip_set_req_ipporthash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_ipporthash),
- size);
- return -EINVAL;
- }
- return __delip(set, req->ip, req->port, hash_ip);
-}
-
-static int
-delip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- ip_set_ip_t port;
-
- if (flags[index+1] == 0)
- return -EINVAL;
-
- port = get_port(skb, flags[index+1]);
-
- DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
- flags[index] & IPSET_SRC ? "SRC" : "DST",
- NIPQUAD(ip_hdr(skb)->saddr),
- NIPQUAD(ip_hdr(skb)->daddr));
- DP("flag %s port %u",
- flags[index+1] & IPSET_SRC ? "SRC" : "DST",
- port);
- if (port == INVALID_PORT)
- return -EINVAL;
-
- return __delip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- port,
- hash_ip);
-}
+UADT(ipporthash, del, req->port)
+KADT(ipporthash, del, ipaddr, port)
-static int create(struct ip_set *set, const void *data, size_t size)
+static inline int
+__ipporthash_create(const struct ip_set_req_ipporthash_create *req,
+ struct ip_set_ipporthash *map)
{
- const struct ip_set_req_ipporthash_create *req = data;
- struct ip_set_ipporthash *map;
- uint16_t i;
-
- if (size != sizeof(struct ip_set_req_ipporthash_create)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_ipporthash_create),
- size);
- return -EINVAL;
- }
-
- if (req->hashsize < 1) {
- ip_set_printk("hashsize too small");
+ if (req->to - req->from > MAX_RANGE) {
+ ip_set_printk("range too big, %d elements (max %d)",
+ req->to - req->from + 1, MAX_RANGE+1);
return -ENOEXEC;
}
-
- if (req->probes < 1) {
- ip_set_printk("probes too small");
- return -ENOEXEC;
- }
-
- map = kmalloc(sizeof(struct ip_set_ipporthash)
- + req->probes * sizeof(uint32_t), GFP_KERNEL);
- if (!map) {
- DP("out of memory for %d bytes",
- sizeof(struct ip_set_ipporthash)
- + req->probes * sizeof(uint32_t));
- return -ENOMEM;
- }
- for (i = 0; i < req->probes; i++)
- get_random_bytes(((uint32_t *) map->initval)+i, 4);
- map->elements = 0;
- map->hashsize = req->hashsize;
- map->probes = req->probes;
- map->resize = req->resize;
map->first_ip = req->from;
map->last_ip = req->to;
- map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
- if (!map->members) {
- DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
- kfree(map);
- return -ENOMEM;
- }
-
- set->data = map;
return 0;
}
-static void destroy(struct ip_set *set)
-{
- struct ip_set_ipporthash *map = set->data;
-
- harray_free(map->members);
- kfree(map);
+HASH_CREATE(ipporthash, ip_set_ip_t)
+HASH_DESTROY(ipporthash)
+HASH_FLUSH(ipporthash, ip_set_ip_t)
- set->data = NULL;
-}
-
-static void flush(struct ip_set *set)
+static inline void
+__ipporthash_list_header(const struct ip_set_ipporthash *map,
+ struct ip_set_req_ipporthash_create *header)
{
- struct ip_set_ipporthash *map = set->data;
- harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
- map->elements = 0;
-}
-
-static void list_header(const struct ip_set *set, void *data)
-{
- const struct ip_set_ipporthash *map = set->data;
- struct ip_set_req_ipporthash_create *header = data;
-
- header->hashsize = map->hashsize;
- header->probes = map->probes;
- header->resize = map->resize;
header->from = map->first_ip;
header->to = map->last_ip;
}
-static int list_members_size(const struct ip_set *set)
-{
- const struct ip_set_ipporthash *map = set->data;
+HASH_LIST_HEADER(ipporthash)
+HASH_LIST_MEMBERS_SIZE(ipporthash, ip_set_ip_t)
+HASH_LIST_MEMBERS(ipporthash, ip_set_ip_t)
- return (map->hashsize * sizeof(ip_set_ip_t));
-}
-
-static void list_members(const struct ip_set *set, void *data)
-{
- const struct ip_set_ipporthash *map = set->data;
- ip_set_ip_t i, *elem;
-
- for (i = 0; i < map->hashsize; i++) {
- elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
- ((ip_set_ip_t *)data)[i] = *elem;
- }
-}
-
-static struct ip_set_type ip_set_ipporthash = {
- .typename = SETTYPE_NAME,
- .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_DATA_DOUBLE,
- .protocol_version = IP_SET_PROTOCOL_VERSION,
- .create = &create,
- .destroy = &destroy,
- .flush = &flush,
- .reqsize = sizeof(struct ip_set_req_ipporthash),
- .addip = &addip,
- .addip_kernel = &addip_kernel,
- .retry = &retry,
- .delip = &delip,
- .delip_kernel = &delip_kernel,
- .testip = &testip,
- .testip_kernel = &testip_kernel,
- .header_size = sizeof(struct ip_set_req_ipporthash_create),
- .list_header = &list_header,
- .list_members_size = &list_members_size,
- .list_members = &list_members,
- .me = THIS_MODULE,
-};
+IP_SET_RTYPE(ipporthash, IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_DATA_DOUBLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -518,17 +194,4 @@ MODULE_DESCRIPTION("ipporthash type of IP sets");
module_param(limit, int, 0600);
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
-static int __init ip_set_ipporthash_init(void)
-{
- init_max_page_size();
- return ip_set_register_set_type(&ip_set_ipporthash);
-}
-
-static void __exit ip_set_ipporthash_fini(void)
-{
- /* FIXME: possible race with ip_set_create() */
- ip_set_unregister_set_type(&ip_set_ipporthash);
-}
-
-module_init(ip_set_ipporthash_init);
-module_exit(ip_set_ipporthash_fini);
+REGISTER_MODULE(ipporthash)
diff --git a/kernel/ip_set_ipportiphash.c b/kernel/ip_set_ipportiphash.c
new file mode 100644
index 0000000..1755c57
--- /dev/null
+++ b/kernel/ip_set_ipportiphash.c
@@ -0,0 +1,212 @@
+/* Copyright (C) 2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an ip+port+ip hash set */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/skbuff.h>
+#include <linux/jhash.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+
+#include <net/ip.h>
+
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_hashes.h>
+#include <linux/netfilter_ipv4/ip_set_ipportiphash.h>
+#include <linux/netfilter_ipv4/ip_set_getport.h>
+
+static int limit = MAX_RANGE;
+
+#define jhash_ip2(map, i, ipport, ip1) \
+ jhash_2words(ipport, ip1, *(map->initval + i))
+
+static inline __u32
+ipportiphash_id(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+{
+ struct ip_set_ipportiphash *map = set->data;
+ __u32 id;
+ 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));
+
+ for (i = 0; i < map->probes; i++) {
+ id = jhash_ip2(map, i, *hash_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)
+ return id;
+ /* No shortcut at testing - there can be deleted
+ * entries. */
+ }
+ return UINT_MAX;
+}
+
+static inline int
+ipportiphash_test(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+{
+ struct ip_set_ipportiphash *map = set->data;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+
+ return (ipportiphash_id(set, hash_ip, ip, port, ip1) != UINT_MAX);
+}
+
+#define KADT_CONDITION \
+ ip_set_ip_t port, ip1; \
+ \
+ if (flags[index+2] == 0) \
+ return 0; \
+ \
+ port = get_port(skb, flags[index+1]); \
+ ip1 = ipaddr(skb, flags[index+2]); \
+ \
+ if (port == INVALID_PORT) \
+ return 0;
+
+UADT(ipportiphash, test, req->port, req->ip1)
+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)
+{
+ __u32 probe;
+ u_int16_t i;
+ struct ipportip *elem;
+
+ for (i = 0; i < map->probes; i++) {
+ probe = jhash_ip2(map, i, hash_ip, ip1) % map->hashsize;
+ elem = HARRAY_ELEM(map->members, struct ipportip *, probe);
+ if (elem->ip == hash_ip && elem->ip1 == ip1)
+ return -EEXIST;
+ if (!(elem->ip || elem->ip1)) {
+ elem->ip = hash_ip;
+ elem->ip1 = ip1;
+ map->elements++;
+ return 0;
+ }
+ }
+ /* Trigger rehashing */
+ return -EAGAIN;
+}
+
+static inline int
+__ipportiphash_add(struct ip_set_ipportiphash *map,
+ struct ipportip *elem)
+{
+ return __ipportip_add(map, elem->ip, elem->ip1);
+}
+
+static inline int
+ipportiphash_add(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+{
+ struct ip_set_ipportiphash *map = set->data;
+
+ if (map->elements > limit)
+ return -ERANGE;
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+
+ *hash_ip = pack_ip_port(map, ip, port);
+
+ return __ipportip_add(map, *hash_ip, ip1);
+}
+
+UADT(ipportiphash, add, req->port, req->ip1)
+KADT(ipportiphash, add, ipaddr, port, ip1)
+
+static inline void
+__ipportiphash_retry(struct ip_set_ipportiphash *tmp,
+ struct ip_set_ipportiphash *map)
+{
+ tmp->first_ip = map->first_ip;
+ tmp->last_ip = map->last_ip;
+}
+
+HASH_RETRY2(ipportiphash, struct ipportip)
+
+static inline int
+ipportiphash_del(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+{
+ struct ip_set_ipportiphash *map = set->data;
+ ip_set_ip_t id;
+ struct ipportip *elem;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+
+ id = ipportiphash_id(set, hash_ip, ip, port, ip1);
+
+ if (id == UINT_MAX)
+ return -EEXIST;
+
+ elem = HARRAY_ELEM(map->members, struct ipportip *, id);
+ elem->ip = elem->ip1 = 0;
+ map->elements--;
+
+ return 0;
+}
+
+UADT(ipportiphash, del, req->port, req->ip1)
+KADT(ipportiphash, del, ipaddr, port, ip1)
+
+static inline int
+__ipportiphash_create(const struct ip_set_req_ipportiphash_create *req,
+ struct ip_set_ipportiphash *map)
+{
+ if (req->to - req->from > MAX_RANGE) {
+ ip_set_printk("range too big, %d elements (max %d)",
+ req->to - req->from + 1, MAX_RANGE+1);
+ return -ENOEXEC;
+ }
+ map->first_ip = req->from;
+ map->last_ip = req->to;
+ return 0;
+}
+
+HASH_CREATE(ipportiphash, struct ipportip)
+HASH_DESTROY(ipportiphash)
+HASH_FLUSH(ipportiphash, struct ipportip)
+
+static inline void
+__ipportiphash_list_header(const struct ip_set_ipportiphash *map,
+ struct ip_set_req_ipportiphash_create *header)
+{
+ header->from = map->first_ip;
+ header->to = map->last_ip;
+}
+
+HASH_LIST_HEADER(ipportiphash)
+HASH_LIST_MEMBERS_SIZE(ipportiphash, struct ipportip)
+HASH_LIST_MEMBERS_MEMCPY(ipportiphash, struct ipportip)
+
+IP_SET_RTYPE(ipportiphash, IPSET_TYPE_IP | IPSET_TYPE_PORT
+ | IPSET_TYPE_IP1 | IPSET_DATA_TRIPLE)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("ipportiphash type of IP sets");
+module_param(limit, int, 0600);
+MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
+
+REGISTER_MODULE(ipportiphash)
diff --git a/kernel/ip_set_ipportnethash.c b/kernel/ip_set_ipportnethash.c
new file mode 100644
index 0000000..3783bb8
--- /dev/null
+++ b/kernel/ip_set_ipportnethash.c
@@ -0,0 +1,299 @@
+/* Copyright (C) 2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an ip+port+net hash set */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/skbuff.h>
+#include <linux/jhash.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+
+#include <net/ip.h>
+
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_hashes.h>
+#include <linux/netfilter_ipv4/ip_set_ipportnethash.h>
+#include <linux/netfilter_ipv4/ip_set_getport.h>
+
+static int limit = MAX_RANGE;
+
+#define jhash_ip2(map, i, ipport, ip1) \
+ jhash_2words(ipport, ip1, *(map->initval + i))
+
+static inline __u32
+ipportnethash_id_cidr(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port,
+ ip_set_ip_t ip1, uint8_t cidr)
+{
+ struct ip_set_ipportnethash *map = set->data;
+ __u32 id;
+ 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));
+ ip1 = pack_ip_cidr(ip1, cidr);
+
+ for (i = 0; i < map->probes; i++) {
+ id = jhash_ip2(map, i, *hash_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)
+ return id;
+ /* No shortcut at testing - there can be deleted
+ * entries. */
+ }
+ return UINT_MAX;
+}
+
+static inline __u32
+ipportnethash_id(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+{
+ struct ip_set_ipportnethash *map = set->data;
+ __u32 id = UINT_MAX;
+ int i;
+
+ for (i = 0; i < 30 && map->cidr[i]; i++) {
+ id = ipportnethash_id_cidr(set, hash_ip, ip, port, ip1,
+ map->cidr[i]);
+ if (id != UINT_MAX)
+ break;
+ }
+ return id;
+}
+
+static inline int
+ipportnethash_test_cidr(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port,
+ ip_set_ip_t ip1, uint8_t cidr)
+{
+ struct ip_set_ipportnethash *map = set->data;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+
+ return (ipportnethash_id_cidr(set, hash_ip, ip, port, ip1,
+ cidr) != UINT_MAX);
+}
+
+static inline int
+ipportnethash_test(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+{
+ struct ip_set_ipportnethash *map = set->data;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+
+ return (ipportnethash_id(set, hash_ip, ip, port, ip1) != UINT_MAX);
+}
+
+static int
+ipportnethash_utest(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ 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,
+ req->ip1, req->cidr));
+}
+
+#define KADT_CONDITION \
+ ip_set_ip_t port, ip1; \
+ \
+ if (flags[index+2] == 0) \
+ return 0; \
+ \
+ port = get_port(skb, flags[index+1]); \
+ ip1 = ipaddr(skb, flags[index+2]); \
+ \
+ if (port == INVALID_PORT) \
+ return 0;
+
+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)
+{
+ __u32 probe;
+ u_int16_t i;
+ struct ipportip *elem;
+
+ for (i = 0; i < map->probes; i++) {
+ probe = jhash_ip2(map, i, hash_ip, ip1) % map->hashsize;
+ elem = HARRAY_ELEM(map->members, struct ipportip *, probe);
+ if (elem->ip == hash_ip && elem->ip1 == ip1)
+ return -EEXIST;
+ if (!(elem->ip || elem->ip1)) {
+ elem->ip = hash_ip;
+ elem->ip1 = ip1;
+ map->elements++;
+ return 0;
+ }
+ }
+ /* Trigger rehashing */
+ return -EAGAIN;
+}
+
+static inline int
+__ipportnethash_add(struct ip_set_ipportnethash *map,
+ struct ipportip *elem)
+{
+ return __ipportnet_add(map, elem->ip, elem->ip1);
+}
+
+static inline int
+ipportnethash_add(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port,
+ ip_set_ip_t ip1, uint8_t cidr)
+{
+ struct ip_set_ipportnethash *map = set->data;
+ struct ipportip;
+ int ret;
+
+ if (map->elements > limit)
+ return -ERANGE;
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+ if (cidr <= 0 || cidr >= 32)
+ return -EINVAL;
+ if (map->nets[cidr-1] == UINT16_MAX)
+ return -ERANGE;
+
+ *hash_ip = pack_ip_port(map, ip, port);
+
+ ret =__ipportnet_add(map, *hash_ip, pack_ip_cidr(ip1, cidr));
+ if (ret == 0) {
+ if (!map->nets[cidr-1]++)
+ add_cidr_size(map->cidr, cidr);
+ map->elements++;
+ }
+ return ret;
+}
+
+#undef KADT_CONDITION
+#define KADT_CONDITION \
+ struct ip_set_ipportnethash *map = set->data; \
+ uint8_t cidr = map->cidr[0] ? map->cidr[0] : 31; \
+ ip_set_ip_t port, ip1; \
+ \
+ if (flags[index+2] == 0) \
+ return 0; \
+ \
+ port = get_port(skb, flags[index+1]); \
+ ip1 = ipaddr(skb, flags[index+2]); \
+ \
+ if (port == INVALID_PORT) \
+ return 0;
+
+UADT(ipportnethash, add, req->port, req->ip1, req->cidr)
+KADT(ipportnethash, add, ipaddr, port, ip1, cidr)
+
+static inline void
+__ipportnethash_retry(struct ip_set_ipportnethash *tmp,
+ struct ip_set_ipportnethash *map)
+{
+ tmp->first_ip = map->first_ip;
+ tmp->last_ip = map->last_ip;
+ memcpy(tmp->cidr, map->cidr, 30 * sizeof(uint8_t));
+ memcpy(tmp->nets, map->nets, 30 * sizeof(uint16_t));
+}
+
+HASH_RETRY2(ipportnethash, struct ipportip)
+
+static inline int
+ipportnethash_del(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, ip_set_ip_t port,
+ ip_set_ip_t ip1, uint8_t cidr)
+{
+ struct ip_set_ipportnethash *map = set->data;
+ ip_set_ip_t id;
+ struct ipportip *elem;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+ if (!ip)
+ return -ERANGE;
+ if (cidr <= 0 || cidr >= 32)
+ return -EINVAL;
+
+ id = ipportnethash_id_cidr(set, hash_ip, ip, port, ip1, cidr);
+
+ if (id == UINT_MAX)
+ return -EEXIST;
+
+ elem = HARRAY_ELEM(map->members, struct ipportip *, id);
+ elem->ip = elem->ip1 = 0;
+ map->elements--;
+ if (!map->nets[cidr-1]--)
+ del_cidr_size(map->cidr, cidr);
+
+ return 0;
+}
+
+UADT(ipportnethash, del, req->port, req->ip1, req->cidr)
+KADT(ipportnethash, del, ipaddr, port, ip1, cidr)
+
+static inline int
+__ipportnethash_create(const struct ip_set_req_ipportnethash_create *req,
+ struct ip_set_ipportnethash *map)
+{
+ if (req->to - req->from > MAX_RANGE) {
+ ip_set_printk("range too big, %d elements (max %d)",
+ req->to - req->from + 1, MAX_RANGE+1);
+ return -ENOEXEC;
+ }
+ map->first_ip = req->from;
+ map->last_ip = req->to;
+ memset(map->cidr, 0, 30 * sizeof(uint8_t));
+ memset(map->nets, 0, 30 * sizeof(uint16_t));
+ return 0;
+}
+
+HASH_CREATE(ipportnethash, struct ipportip)
+HASH_DESTROY(ipportnethash)
+HASH_FLUSH_CIDR(ipportnethash, struct ipportip);
+
+static inline void
+__ipportnethash_list_header(const struct ip_set_ipportnethash *map,
+ struct ip_set_req_ipportnethash_create *header)
+{
+ header->from = map->first_ip;
+ header->to = map->last_ip;
+}
+
+HASH_LIST_HEADER(ipportnethash)
+
+HASH_LIST_MEMBERS_SIZE(ipportnethash, struct ipportip)
+HASH_LIST_MEMBERS_MEMCPY(ipportnethash, struct ipportip)
+
+IP_SET_RTYPE(ipportnethash, IPSET_TYPE_IP | IPSET_TYPE_PORT
+ | IPSET_TYPE_IP1 | IPSET_DATA_TRIPLE)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("ipportnethash type of IP sets");
+module_param(limit, int, 0600);
+MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
+
+REGISTER_MODULE(ipportnethash)
diff --git a/kernel/ip_set_iptree.c b/kernel/ip_set_iptree.c
index 2e0a406..22a94d1 100644
--- a/kernel/ip_set_iptree.c
+++ b/kernel/ip_set_iptree.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2005-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -7,20 +7,19 @@
/* Kernel module implementing an IP set type: the iptree type */
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_set.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_bitmaps.h>
#include <linux/netfilter_ipv4/ip_set_iptree.h>
static int limit = MAX_RANGE;
@@ -61,7 +60,7 @@ static __KMEM_CACHE_T__ *leaf_cachep;
} while (0)
static inline int
-__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+iptree_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_iptree *map = set->data;
struct ip_set_iptreeb *btree;
@@ -84,42 +83,10 @@ __testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|| time_after(dtree->expires[d], jiffies));
}
-static int
-testip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_iptree *req = data;
+#define KADT_CONDITION
- if (size != sizeof(struct ip_set_req_iptree)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_iptree),
- size);
- return -EINVAL;
- }
- return __testip(set, req->ip, hash_ip);
-}
-
-static int
-testip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- int res;
-
- DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
- flags[index] & IPSET_SRC ? "SRC" : "DST",
- NIPQUAD(ip_hdr(skb)->saddr),
- NIPQUAD(ip_hdr(skb)->daddr));
-
- res = __testip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
- return (res < 0 ? 0 : res);
-}
+UADT(iptree, test)
+KADT(iptree, test, ipaddr)
#define ADDIP_WALK(map, elem, branch, type, cachep) do { \
if ((map)->tree[elem]) { \
@@ -137,8 +104,8 @@ testip_kernel(struct ip_set *set,
} while (0)
static inline int
-__addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
- ip_set_ip_t *hash_ip)
+iptree_add(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, unsigned int timeout)
{
struct ip_set_iptree *map = set->data;
struct ip_set_iptreeb *btree;
@@ -161,6 +128,8 @@ __addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
if (dtree->expires[d]
&& (!map->timeout || time_after(dtree->expires[d], jiffies)))
ret = -EEXIST;
+ if (map->timeout && timeout == 0)
+ timeout = map->timeout;
dtree->expires[d] = map->timeout ? (timeout * HZ + jiffies) : 1;
/* Lottery: I won! */
if (dtree->expires[d] == 0)
@@ -171,41 +140,8 @@ __addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
return ret;
}
-static int
-addip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- struct ip_set_iptree *map = set->data;
- const struct ip_set_req_iptree *req = data;
-
- if (size != sizeof(struct ip_set_req_iptree)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_iptree),
- size);
- return -EINVAL;
- }
- DP("%u.%u.%u.%u %u", HIPQUAD(req->ip), req->timeout);
- return __addip(set, req->ip,
- req->timeout ? req->timeout : map->timeout,
- hash_ip);
-}
-
-static int
-addip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- struct ip_set_iptree *map = set->data;
-
- return __addip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- map->timeout,
- hash_ip);
-}
+UADT(iptree, add, req->timeout)
+KADT(iptree, add, ipaddr, 0)
#define DELIP_WALK(map, elem, branch) do { \
if ((map)->tree[elem]) { \
@@ -215,7 +151,7 @@ addip_kernel(struct ip_set *set,
} while (0)
static inline int
-__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+iptree_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_iptree *map = set->data;
struct ip_set_iptreeb *btree;
@@ -240,34 +176,8 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return -EEXIST;
}
-static int
-delip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_iptree *req = data;
-
- if (size != sizeof(struct ip_set_req_iptree)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_iptree),
- size);
- return -EINVAL;
- }
- return __delip(set, req->ip, hash_ip);
-}
-
-static int
-delip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- return __delip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
+UADT(iptree, del)
+KADT(iptree, del, ipaddr)
#define LOOP_WALK_BEGIN(map, i, branch) \
for (i = 0; i < 256; i++) { \
@@ -277,7 +187,8 @@ delip_kernel(struct ip_set *set,
#define LOOP_WALK_END }
-static void ip_tree_gc(unsigned long ul_set)
+static void
+ip_tree_gc(unsigned long ul_set)
{
struct ip_set *set = (struct ip_set *) ul_set;
struct ip_set_iptree *map = set->data;
@@ -347,7 +258,8 @@ static void ip_tree_gc(unsigned long ul_set)
add_timer(&map->gc);
}
-static inline void init_gc_timer(struct ip_set *set)
+static inline void
+init_gc_timer(struct ip_set *set)
{
struct ip_set_iptree *map = set->data;
@@ -362,7 +274,8 @@ static inline void init_gc_timer(struct ip_set *set)
add_timer(&map->gc);
}
-static int create(struct ip_set *set, const void *data, size_t size)
+static int
+iptree_create(struct ip_set *set, const void *data, size_t size)
{
const struct ip_set_req_iptree_create *req = data;
struct ip_set_iptree *map;
@@ -390,7 +303,8 @@ static int create(struct ip_set *set, const void *data, size_t size)
return 0;
}
-static void __flush(struct ip_set_iptree *map)
+static inline void
+__flush(struct ip_set_iptree *map)
{
struct ip_set_iptreeb *btree;
struct ip_set_iptreec *ctree;
@@ -409,7 +323,8 @@ static void __flush(struct ip_set_iptree *map)
map->elements = 0;
}
-static void destroy(struct ip_set *set)
+static void
+iptree_destroy(struct ip_set *set)
{
struct ip_set_iptree *map = set->data;
@@ -421,7 +336,8 @@ static void destroy(struct ip_set *set)
set->data = NULL;
}
-static void flush(struct ip_set *set)
+static void
+iptree_flush(struct ip_set *set)
{
struct ip_set_iptree *map = set->data;
unsigned int timeout = map->timeout;
@@ -436,7 +352,8 @@ static void flush(struct ip_set *set)
init_gc_timer(set);
}
-static void list_header(const struct ip_set *set, void *data)
+static void
+iptree_list_header(const struct ip_set *set, void *data)
{
const struct ip_set_iptree *map = set->data;
struct ip_set_req_iptree_create *header = data;
@@ -444,7 +361,8 @@ static void list_header(const struct ip_set *set, void *data)
header->timeout = map->timeout;
}
-static int list_members_size(const struct ip_set *set)
+static int
+iptree_list_members_size(const struct ip_set *set)
{
const struct ip_set_iptree *map = set->data;
struct ip_set_iptreeb *btree;
@@ -469,7 +387,8 @@ static int list_members_size(const struct ip_set *set)
return (count * sizeof(struct ip_set_req_iptree));
}
-static void list_members(const struct ip_set *set, void *data)
+static void
+iptree_list_members(const struct ip_set *set, void *data)
{
const struct ip_set_iptree *map = set->data;
struct ip_set_iptreeb *btree;
@@ -497,26 +416,7 @@ static void list_members(const struct ip_set *set, void *data)
LOOP_WALK_END;
}
-static struct ip_set_type ip_set_iptree = {
- .typename = SETTYPE_NAME,
- .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
- .protocol_version = IP_SET_PROTOCOL_VERSION,
- .create = &create,
- .destroy = &destroy,
- .flush = &flush,
- .reqsize = sizeof(struct ip_set_req_iptree),
- .addip = &addip,
- .addip_kernel = &addip_kernel,
- .delip = &delip,
- .delip_kernel = &delip_kernel,
- .testip = &testip,
- .testip_kernel = &testip_kernel,
- .header_size = sizeof(struct ip_set_req_iptree_create),
- .list_header = &list_header,
- .list_members_size = &list_members_size,
- .list_members = &list_members,
- .me = THIS_MODULE,
-};
+IP_SET_TYPE(iptree, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
diff --git a/kernel/ip_set_iptreemap.c b/kernel/ip_set_iptreemap.c
index dedf8a4..4a13e4f 100644
--- a/kernel/ip_set_iptreemap.c
+++ b/kernel/ip_set_iptreemap.c
@@ -11,20 +11,19 @@
* index to find the bitmap and the last octet is used as the bit number.
*/
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_set.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_bitmaps.h>
#include <linux/netfilter_ipv4/ip_set_iptreemap.h>
#define IPTREEMAP_DEFAULT_GC_TIME (5 * 60)
@@ -250,7 +249,7 @@ free_b(struct ip_set_iptreemap_b *map)
}
static inline int
-__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+iptreemap_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree;
@@ -269,35 +268,13 @@ __testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return !!test_bit(d, (void *) dtree->bitmap);
}
-static int
-testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_iptreemap *req = data;
-
- if (size != sizeof(struct ip_set_req_iptreemap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
- return -EINVAL;
- }
-
- return __testip(set, req->start, hash_ip);
-}
-
-static int
-testip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
-{
- int res;
-
- res = __testip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
+#define KADT_CONDITION
- return (res < 0 ? 0 : res);
-}
+UADT(iptreemap, test)
+KADT(iptreemap, test, ipaddr)
static inline int
-__addip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+__addip_single(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_iptreemap *map = (struct ip_set_iptreemap *) set->data;
struct ip_set_iptreemap_b *btree;
@@ -322,7 +299,8 @@ __addip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
}
static inline int
-__addip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_t *hash_ip)
+iptreemap_add(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t start, ip_set_ip_t end)
{
struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree;
@@ -333,7 +311,7 @@ __addip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_
unsigned char a2, b2, c2, d2;
if (start == end)
- return __addip_single(set, start, hash_ip);
+ return __addip_single(set, hash_ip, start);
*hash_ip = start;
@@ -354,32 +332,12 @@ __addip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_
return 0;
}
-static int
-addip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_iptreemap *req = data;
-
- if (size != sizeof(struct ip_set_req_iptreemap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
- return -EINVAL;
- }
-
- return __addip_range(set, min(req->start, req->end), max(req->start, req->end), hash_ip);
-}
-
-static int
-addip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
-{
-
- return __addip_single(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
+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 ip, ip_set_ip_t *hash_ip, unsigned int __nocast flags)
+__delip_single(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, unsigned int __nocast flags)
{
struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree;
@@ -404,7 +362,8 @@ __delip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip, unsigne
}
static inline int
-__delip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_t *hash_ip, unsigned int __nocast flags)
+iptreemap_del(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t start, ip_set_ip_t end, unsigned int __nocast flags)
{
struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree;
@@ -415,7 +374,7 @@ __delip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_
unsigned char a2, b2, c2, d2;
if (start == end)
- return __delip_single(set, start, hash_ip, flags);
+ return __delip_single(set, hash_ip, start, flags);
*hash_ip = start;
@@ -436,29 +395,8 @@ __delip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_
return 0;
}
-static int
-delip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_iptreemap *req = data;
-
- if (size != sizeof(struct ip_set_req_iptreemap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
- return -EINVAL;
- }
-
- return __delip_range(set, min(req->start, req->end), max(req->start, req->end), hash_ip, GFP_KERNEL);
-}
-
-static int
-delip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
-{
- return __delip_single(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip,
- GFP_ATOMIC);
-}
+UADT0(iptreemap, del, min(req->ip, req->end), max(req->ip, req->end), GFP_KERNEL)
+KADT(iptreemap, del, ipaddr, ip, GFP_ATOMIC)
/* Check the status of the bitmap
* -1 == all bits cleared
@@ -530,16 +468,12 @@ init_gc_timer(struct ip_set *set)
add_timer(&map->gc);
}
-static int create(struct ip_set *set, const void *data, size_t size)
+static int
+iptreemap_create(struct ip_set *set, const void *data, size_t size)
{
const struct ip_set_req_iptreemap_create *req = data;
struct ip_set_iptreemap *map;
- if (size != sizeof(struct ip_set_req_iptreemap_create)) {
- ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap_create), size);
- return -EINVAL;
- }
-
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map)
return -ENOMEM;
@@ -552,7 +486,8 @@ static int create(struct ip_set *set, const void *data, size_t size)
return 0;
}
-static inline void __flush(struct ip_set_iptreemap *map)
+static inline void
+__flush(struct ip_set_iptreemap *map)
{
struct ip_set_iptreemap_b *btree;
unsigned int a;
@@ -563,7 +498,8 @@ static inline void __flush(struct ip_set_iptreemap *map)
LOOP_WALK_END();
}
-static void destroy(struct ip_set *set)
+static void
+iptreemap_destroy(struct ip_set *set)
{
struct ip_set_iptreemap *map = set->data;
@@ -576,7 +512,8 @@ static void destroy(struct ip_set *set)
set->data = NULL;
}
-static void flush(struct ip_set *set)
+static void
+iptreemap_flush(struct ip_set *set)
{
struct ip_set_iptreemap *map = set->data;
@@ -590,7 +527,8 @@ static void flush(struct ip_set *set)
init_gc_timer(set);
}
-static void list_header(const struct ip_set *set, void *data)
+static void
+iptreemap_list_header(const struct ip_set *set, void *data)
{
struct ip_set_iptreemap *map = set->data;
struct ip_set_req_iptreemap_create *header = data;
@@ -598,7 +536,8 @@ static void list_header(const struct ip_set *set, void *data)
header->gc_interval = map->gc_interval;
}
-static int list_members_size(const struct ip_set *set)
+static int
+iptreemap_list_members_size(const struct ip_set *set)
{
struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree;
@@ -627,17 +566,19 @@ static int list_members_size(const struct ip_set *set)
return (count * sizeof(struct ip_set_req_iptreemap));
}
-static inline size_t add_member(void *data, size_t offset, ip_set_ip_t start, ip_set_ip_t end)
+static inline size_t
+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->start = start;
+ entry->ip = start;
entry->end = end;
return sizeof(*entry);
}
-static void list_members(const struct ip_set *set, void *data)
+static void
+iptreemap_list_members(const struct ip_set *set, void *data)
{
struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree;
@@ -674,26 +615,7 @@ static void list_members(const struct ip_set *set, void *data)
add_member(data, offset, start, end);
}
-static struct ip_set_type ip_set_iptreemap = {
- .typename = SETTYPE_NAME,
- .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
- .protocol_version = IP_SET_PROTOCOL_VERSION,
- .create = create,
- .destroy = destroy,
- .flush = flush,
- .reqsize = sizeof(struct ip_set_req_iptreemap),
- .addip = addip,
- .addip_kernel = addip_kernel,
- .delip = delip,
- .delip_kernel = delip_kernel,
- .testip = testip,
- .testip_kernel = testip_kernel,
- .header_size = sizeof(struct ip_set_req_iptreemap_create),
- .list_header = list_header,
- .list_members_size = list_members_size,
- .list_members = list_members,
- .me = THIS_MODULE,
-};
+IP_SET_TYPE(iptreemap, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sven Wegener <sven.wegener@stealer.net>");
diff --git a/kernel/ip_set_macipmap.c b/kernel/ip_set_macipmap.c
index 33e2808..4b2b1de 100644
--- a/kernel/ip_set_macipmap.c
+++ b/kernel/ip_set_macipmap.c
@@ -1,7 +1,7 @@
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se>
- * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,33 +13,24 @@
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/skbuff.h>
-#include <linux/version.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_set.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
#include <linux/if_ether.h>
-#include <linux/vmalloc.h>
-#include <linux/netfilter_ipv4/ip_set_malloc.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_bitmaps.h>
#include <linux/netfilter_ipv4/ip_set_macipmap.h>
static int
-testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
+macipmap_utest(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
{
- struct ip_set_macipmap *map = set->data;
- struct ip_set_macip *table = map->members;
+ const struct ip_set_macipmap *map = set->data;
+ const struct ip_set_macip *table = map->members;
const struct ip_set_req_macipmap *req = data;
- if (size != sizeof(struct ip_set_req_macipmap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_macipmap),
- size);
- return -EINVAL;
- }
-
if (req->ip < map->first_ip || req->ip > map->last_ip)
return -ERANGE;
@@ -57,19 +48,17 @@ testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
}
static int
-testip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
+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)
{
- struct ip_set_macipmap *map = set->data;
- struct ip_set_macip *table = map->members;
+ const struct ip_set_macipmap *map = set->data;
+ const struct ip_set_macip *table = map->members;
ip_set_ip_t ip;
- ip = ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr);
+ ip = ipaddr(skb, flags[index]);
if (ip < map->first_ip || ip > map->last_ip)
return 0;
@@ -93,8 +82,8 @@ testip_kernel(struct ip_set *set,
/* returns 0 on success */
static inline int
-__addip(struct ip_set *set,
- ip_set_ip_t ip, const unsigned char *ethernet, ip_set_ip_t *hash_ip)
+macipmap_add(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, const unsigned char *ethernet)
{
struct ip_set_macipmap *map = set->data;
struct ip_set_macip *table = map->members;
@@ -111,43 +100,16 @@ __addip(struct ip_set *set,
return 0;
}
-static int
-addip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_macipmap *req = data;
-
- if (size != sizeof(struct ip_set_req_macipmap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_macipmap),
- size);
- return -EINVAL;
- }
- return __addip(set, req->ip, req->ethernet, hash_ip);
-}
-
-static int
-addip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- ip_set_ip_t ip;
-
- ip = ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr);
-
- if (!(skb_mac_header(skb) >= skb->head
- && (skb_mac_header(skb) + ETH_HLEN) <= skb->data))
+#define KADT_CONDITION \
+ if (!(skb_mac_header(skb) >= skb->head \
+ && (skb_mac_header(skb) + ETH_HLEN) <= skb->data))\
return -EINVAL;
- return __addip(set, ip, eth_hdr(skb)->h_source, hash_ip);
-}
+UADT(macipmap, add, req->ethernet)
+KADT(macipmap, add, ipaddr, eth_hdr(skb)->h_source)
static inline int
-__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+macipmap_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_macipmap *map = set->data;
struct ip_set_macip *table = map->members;
@@ -163,173 +125,44 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return 0;
}
-static int
-delip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_macipmap *req = data;
-
- if (size != sizeof(struct ip_set_req_macipmap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_macipmap),
- size);
- return -EINVAL;
- }
- return __delip(set, req->ip, hash_ip);
-}
-
-static int
-delip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- return __delip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
+#undef KADT_CONDITION
+#define KADT_CONDITION
-static inline size_t members_size(ip_set_ip_t from, ip_set_ip_t to)
-{
- return (size_t)((to - from + 1) * sizeof(struct ip_set_macip));
-}
+UADT(macipmap, del)
+KADT(macipmap, del, ipaddr)
-static int create(struct ip_set *set, const void *data, size_t size)
+static inline int
+__macipmap_create(const struct ip_set_req_macipmap_create *req,
+ struct ip_set_macipmap *map)
{
- size_t newbytes;
- const struct ip_set_req_macipmap_create *req = data;
- struct ip_set_macipmap *map;
-
- if (size != sizeof(struct ip_set_req_macipmap_create)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_macipmap_create),
- size);
- return -EINVAL;
- }
-
- DP("from %u.%u.%u.%u to %u.%u.%u.%u",
- HIPQUAD(req->from), HIPQUAD(req->to));
-
- if (req->from > req->to) {
- DP("bad ip range");
- return -ENOEXEC;
- }
-
if (req->to - req->from > MAX_RANGE) {
- ip_set_printk("range too big (max %d addresses)",
- MAX_RANGE+1);
+ ip_set_printk("range too big, %d elements (max %d)",
+ req->to - req->from + 1, MAX_RANGE+1);
return -ENOEXEC;
}
-
- map = kmalloc(sizeof(struct ip_set_macipmap), GFP_KERNEL);
- if (!map) {
- DP("out of memory for %d bytes",
- sizeof(struct ip_set_macipmap));
- return -ENOMEM;
- }
map->flags = req->flags;
- map->first_ip = req->from;
- map->last_ip = req->to;
- newbytes = members_size(map->first_ip, map->last_ip);
- map->members = ip_set_malloc(newbytes);
- DP("members: %u %p", newbytes, map->members);
- if (!map->members) {
- DP("out of memory for %d bytes", newbytes);
- kfree(map);
- return -ENOMEM;
- }
- memset(map->members, 0, newbytes);
-
- set->data = map;
- return 0;
-}
-
-static void destroy(struct ip_set *set)
-{
- struct ip_set_macipmap *map = set->data;
-
- ip_set_free(map->members, members_size(map->first_ip, map->last_ip));
- kfree(map);
-
- set->data = NULL;
+ return (req->to - req->from + 1) * sizeof(struct ip_set_macip);
}
-static void flush(struct ip_set *set)
-{
- struct ip_set_macipmap *map = set->data;
- memset(map->members, 0, members_size(map->first_ip, map->last_ip));
-}
+BITMAP_CREATE(macipmap)
+BITMAP_DESTROY(macipmap)
+BITMAP_FLUSH(macipmap)
-static void list_header(const struct ip_set *set, void *data)
+static inline void
+__macipmap_list_header(const struct ip_set_macipmap *map,
+ struct ip_set_req_macipmap_create *header)
{
- const struct ip_set_macipmap *map = set->data;
- struct ip_set_req_macipmap_create *header = data;
-
- DP("list_header %x %x %u", map->first_ip, map->last_ip,
- map->flags);
-
- header->from = map->first_ip;
- header->to = map->last_ip;
header->flags = map->flags;
}
-static int list_members_size(const struct ip_set *set)
-{
- const struct ip_set_macipmap *map = set->data;
-
- DP("%u", members_size(map->first_ip, map->last_ip));
- return members_size(map->first_ip, map->last_ip);
-}
-
-static void list_members(const struct ip_set *set, void *data)
-{
- const struct ip_set_macipmap *map = set->data;
+BITMAP_LIST_HEADER(macipmap)
+BITMAP_LIST_MEMBERS_SIZE(macipmap)
+BITMAP_LIST_MEMBERS(macipmap)
- int bytes = members_size(map->first_ip, map->last_ip);
-
- DP("members: %u %p", bytes, map->members);
- memcpy(data, map->members, bytes);
-}
-
-static struct ip_set_type ip_set_macipmap = {
- .typename = SETTYPE_NAME,
- .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
- .protocol_version = IP_SET_PROTOCOL_VERSION,
- .create = &create,
- .destroy = &destroy,
- .flush = &flush,
- .reqsize = sizeof(struct ip_set_req_macipmap),
- .addip = &addip,
- .addip_kernel = &addip_kernel,
- .delip = &delip,
- .delip_kernel = &delip_kernel,
- .testip = &testip,
- .testip_kernel = &testip_kernel,
- .header_size = sizeof(struct ip_set_req_macipmap_create),
- .list_header = &list_header,
- .list_members_size = &list_members_size,
- .list_members = &list_members,
- .me = THIS_MODULE,
-};
+IP_SET_TYPE(macipmap, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("macipmap type of IP sets");
-static int __init ip_set_macipmap_init(void)
-{
- init_max_page_size();
- return ip_set_register_set_type(&ip_set_macipmap);
-}
-
-static void __exit ip_set_macipmap_fini(void)
-{
- /* FIXME: possible race with ip_set_create() */
- ip_set_unregister_set_type(&ip_set_macipmap);
-}
-
-module_init(ip_set_macipmap_init);
-module_exit(ip_set_macipmap_fini);
+REGISTER_MODULE(macipmap)
diff --git a/kernel/ip_set_nethash.c b/kernel/ip_set_nethash.c
index ecdf369..a04857c 100644
--- a/kernel/ip_set_nethash.c
+++ b/kernel/ip_set_nethash.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -11,41 +11,32 @@
#include <linux/moduleparam.h>
#include <linux/ip.h>
#include <linux/skbuff.h>
-#include <linux/version.h>
#include <linux/jhash.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_set.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
#include <linux/random.h>
#include <net/ip.h>
-#include <linux/netfilter_ipv4/ip_set_malloc.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_hashes.h>
#include <linux/netfilter_ipv4/ip_set_nethash.h>
static int limit = MAX_RANGE;
static inline __u32
-jhash_ip(const struct ip_set_nethash *map, uint16_t i, ip_set_ip_t ip)
-{
- return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
-}
-
-static inline __u32
-hash_id_cidr(struct ip_set_nethash *map,
- ip_set_ip_t ip,
- unsigned char cidr,
- ip_set_ip_t *hash_ip)
+nethash_id_cidr(const struct ip_set_nethash *map,
+ ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip,
+ uint8_t cidr)
{
__u32 id;
u_int16_t i;
ip_set_ip_t *elem;
- *hash_ip = pack(ip, cidr);
+ *hash_ip = pack_ip_cidr(ip, cidr);
for (i = 0; i < map->probes; i++) {
id = jhash_ip(map, i, *hash_ip) % map->hashsize;
@@ -58,14 +49,14 @@ hash_id_cidr(struct ip_set_nethash *map,
}
static inline __u32
-hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+nethash_id(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
- struct ip_set_nethash *map = set->data;
+ const struct ip_set_nethash *map = set->data;
__u32 id = UINT_MAX;
int i;
for (i = 0; i < 30 && map->cidr[i]; i++) {
- id = hash_id_cidr(map, ip, map->cidr[i], hash_ip);
+ id = nethash_id_cidr(map, hash_ip, ip, map->cidr[i]);
if (id != UINT_MAX)
break;
}
@@ -73,65 +64,50 @@ hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
}
static inline int
-__testip_cidr(struct ip_set *set, ip_set_ip_t ip, unsigned char cidr,
- ip_set_ip_t *hash_ip)
+nethash_test_cidr(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, uint8_t cidr)
{
- struct ip_set_nethash *map = set->data;
+ const struct ip_set_nethash *map = set->data;
- return (ip && hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX);
+ return (ip && nethash_id_cidr(map, hash_ip, ip, cidr) != UINT_MAX);
}
static inline int
-__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+nethash_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
- return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
+ return (ip && nethash_id(set, hash_ip, ip) != UINT_MAX);
}
static int
-testip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
+nethash_utest(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
{
const struct ip_set_req_nethash *req = data;
- if (size != sizeof(struct ip_set_req_nethash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_nethash),
- size);
+ if (req->cidr <= 0 || req->cidr > 32)
return -EINVAL;
- }
- return (req->cidr == 32 ? __testip(set, req->ip, hash_ip)
- : __testip_cidr(set, req->ip, req->cidr, hash_ip));
+ return (req->cidr == 32 ? nethash_test(set, hash_ip, req->ip)
+ : nethash_test_cidr(set, hash_ip, req->ip, req->cidr));
}
-static int
-testip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- return __testip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
+#define KADT_CONDITION
+
+KADT(nethash, test, ipaddr)
static inline int
-__addip_base(struct ip_set_nethash *map, ip_set_ip_t ip)
+__nethash_add(struct ip_set_nethash *map, ip_set_ip_t *ip)
{
__u32 probe;
u_int16_t i;
ip_set_ip_t *elem;
for (i = 0; i < map->probes; i++) {
- probe = jhash_ip(map, i, ip) % map->hashsize;
+ probe = jhash_ip(map, i, *ip) % map->hashsize;
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
- if (*elem == ip)
+ if (*elem == *ip)
return -EEXIST;
if (!*elem) {
- *elem = ip;
- map->elements++;
+ *elem = *ip;
return 0;
}
}
@@ -140,319 +116,102 @@ __addip_base(struct ip_set_nethash *map, ip_set_ip_t ip)
}
static inline int
-__addip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
- ip_set_ip_t *hash_ip)
+nethash_add(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, uint8_t cidr)
{
+ struct ip_set_nethash *map = set->data;
+ int ret;
+
if (!ip || map->elements >= limit)
return -ERANGE;
+ if (cidr <= 0 || cidr >= 32)
+ return -EINVAL;
+ if (map->nets[cidr-1] == UINT16_MAX)
+ return -ERANGE;
- *hash_ip = pack(ip, cidr);
+ *hash_ip = pack_ip_cidr(ip, cidr);
DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip));
- return __addip_base(map, *hash_ip);
-}
-
-static void
-update_cidr_sizes(struct ip_set_nethash *map, unsigned char cidr)
-{
- unsigned char next;
- int i;
-
- for (i = 0; i < 30 && map->cidr[i]; i++) {
- if (map->cidr[i] == cidr) {
- return;
- } else if (map->cidr[i] < cidr) {
- next = map->cidr[i];
- map->cidr[i] = cidr;
- cidr = next;
- }
+ ret = __nethash_add(map, hash_ip);
+ if (ret == 0) {
+ if (!map->nets[cidr-1]++)
+ add_cidr_size(map->cidr, cidr);
+ map->elements++;
}
- if (i < 30)
- map->cidr[i] = cidr;
-}
-
-static int
-addip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_nethash *req = data;
- int ret;
-
- if (size != sizeof(struct ip_set_req_nethash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_nethash),
- size);
- return -EINVAL;
- }
- ret = __addip(set->data, req->ip, req->cidr, hash_ip);
-
- if (ret == 0)
- update_cidr_sizes(set->data, req->cidr);
return ret;
}
-static int
-addip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- struct ip_set_nethash *map = set->data;
- int ret = -ERANGE;
- ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr);
-
- if (map->cidr[0])
- ret = __addip(map, ip, map->cidr[0], hash_ip);
-
- return ret;
-}
-
-static int retry(struct ip_set *set)
-{
- struct ip_set_nethash *map = set->data;
- ip_set_ip_t *elem;
- void *members;
- u_int32_t i, hashsize = map->hashsize;
- int res;
- struct ip_set_nethash *tmp;
-
- if (map->resize == 0)
- return -ERANGE;
-
- again:
- res = 0;
-
- /* Calculate new parameters */
- hashsize += (hashsize * map->resize)/100;
- if (hashsize == map->hashsize)
- hashsize++;
-
- ip_set_printk("rehashing of set %s triggered: "
- "hashsize grows from %u to %u",
- set->name, map->hashsize, hashsize);
-
- tmp = kmalloc(sizeof(struct ip_set_nethash)
- + map->probes * sizeof(uint32_t), GFP_ATOMIC);
- if (!tmp) {
- DP("out of memory for %d bytes",
- sizeof(struct ip_set_nethash)
- + map->probes * sizeof(uint32_t));
- return -ENOMEM;
- }
- tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
- if (!tmp->members) {
- DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
- kfree(tmp);
- return -ENOMEM;
- }
- tmp->hashsize = hashsize;
- tmp->elements = 0;
- tmp->probes = map->probes;
- tmp->resize = map->resize;
- memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
- memcpy(tmp->cidr, map->cidr, 30 * sizeof(unsigned char));
-
- write_lock_bh(&set->lock);
- map = set->data; /* Play safe */
- for (i = 0; i < map->hashsize && res == 0; i++) {
- elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
- if (*elem)
- res = __addip_base(tmp, *elem);
- }
- if (res) {
- /* Failure, try again */
- write_unlock_bh(&set->lock);
- harray_free(tmp->members);
- kfree(tmp);
- goto again;
- }
-
- /* Success at resizing! */
- members = map->members;
-
- map->hashsize = tmp->hashsize;
- map->members = tmp->members;
- write_unlock_bh(&set->lock);
+#undef KADT_CONDITION
+#define KADT_CONDITION \
+ struct ip_set_nethash *map = set->data; \
+ uint8_t cidr = map->cidr[0] ? map->cidr[0] : 31;
- harray_free(members);
- kfree(tmp);
+UADT(nethash, add, req->cidr)
+KADT(nethash, add, ipaddr, cidr)
- return 0;
+static inline void
+__nethash_retry(struct ip_set_nethash *tmp, struct ip_set_nethash *map)
+{
+ memcpy(tmp->cidr, map->cidr, 30 * sizeof(uint8_t));
+ memcpy(tmp->nets, map->nets, 30 * sizeof(uint16_t));
}
+HASH_RETRY(nethash, ip_set_ip_t)
+
static inline int
-__delip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
- ip_set_ip_t *hash_ip)
+nethash_del(struct ip_set *set, ip_set_ip_t *hash_ip,
+ ip_set_ip_t ip, uint8_t cidr)
{
+ struct ip_set_nethash *map = set->data;
ip_set_ip_t id, *elem;
if (!ip)
return -ERANGE;
+ if (cidr <= 0 || cidr >= 32)
+ return -EINVAL;
- id = hash_id_cidr(map, ip, cidr, hash_ip);
+ id = nethash_id_cidr(map, hash_ip, ip, cidr);
if (id == UINT_MAX)
return -EEXIST;
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
*elem = 0;
map->elements--;
+ if (!map->nets[cidr-1]--)
+ del_cidr_size(map->cidr, cidr);
return 0;
}
-static int
-delip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_nethash *req = data;
+UADT(nethash, del, req->cidr)
+KADT(nethash, del, ipaddr, cidr)
- if (size != sizeof(struct ip_set_req_nethash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_nethash),
- size);
- return -EINVAL;
- }
- /* TODO: no garbage collection in map->cidr */
- return __delip(set->data, req->ip, req->cidr, hash_ip);
-}
-
-static int
-delip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- struct ip_set_nethash *map = set->data;
- int ret = -ERANGE;
- ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr);
-
- if (map->cidr[0])
- ret = __delip(map, ip, map->cidr[0], hash_ip);
-
- return ret;
-}
-
-static int create(struct ip_set *set, const void *data, size_t size)
+static inline int
+__nethash_create(const struct ip_set_req_nethash_create *req,
+ struct ip_set_nethash *map)
{
- const struct ip_set_req_nethash_create *req = data;
- struct ip_set_nethash *map;
- uint16_t i;
-
- if (size != sizeof(struct ip_set_req_nethash_create)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_nethash_create),
- size);
- return -EINVAL;
- }
-
- if (req->hashsize < 1) {
- ip_set_printk("hashsize too small");
- return -ENOEXEC;
- }
- if (req->probes < 1) {
- ip_set_printk("probes too small");
- return -ENOEXEC;
- }
-
- map = kmalloc(sizeof(struct ip_set_nethash)
- + req->probes * sizeof(uint32_t), GFP_KERNEL);
- if (!map) {
- DP("out of memory for %d bytes",
- sizeof(struct ip_set_nethash)
- + req->probes * sizeof(uint32_t));
- return -ENOMEM;
- }
- for (i = 0; i < req->probes; i++)
- get_random_bytes(((uint32_t *) map->initval)+i, 4);
- map->elements = 0;
- map->hashsize = req->hashsize;
- map->probes = req->probes;
- map->resize = req->resize;
- memset(map->cidr, 0, 30 * sizeof(unsigned char));
- map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
- if (!map->members) {
- DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
- kfree(map);
- return -ENOMEM;
- }
+ memset(map->cidr, 0, 30 * sizeof(uint8_t));
+ memset(map->nets, 0, 30 * sizeof(uint16_t));
- set->data = map;
return 0;
}
-static void destroy(struct ip_set *set)
-{
- struct ip_set_nethash *map = set->data;
+HASH_CREATE(nethash, ip_set_ip_t)
+HASH_DESTROY(nethash)
- harray_free(map->members);
- kfree(map);
+HASH_FLUSH_CIDR(nethash, ip_set_ip_t)
- set->data = NULL;
+static inline void
+__nethash_list_header(const struct ip_set_nethash *map,
+ struct ip_set_req_nethash_create *header)
+{
}
-static void flush(struct ip_set *set)
-{
- struct ip_set_nethash *map = set->data;
- harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
- memset(map->cidr, 0, 30 * sizeof(unsigned char));
- map->elements = 0;
-}
+HASH_LIST_HEADER(nethash)
+HASH_LIST_MEMBERS_SIZE(nethash, ip_set_ip_t)
+HASH_LIST_MEMBERS(nethash, ip_set_ip_t)
-static void list_header(const struct ip_set *set, void *data)
-{
- const struct ip_set_nethash *map = set->data;
- struct ip_set_req_nethash_create *header = data;
-
- header->hashsize = map->hashsize;
- header->probes = map->probes;
- header->resize = map->resize;
-}
-
-static int list_members_size(const struct ip_set *set)
-{
- struct ip_set_nethash *map = set->data;
-
- return (map->hashsize * sizeof(ip_set_ip_t));
-}
-
-static void list_members(const struct ip_set *set, void *data)
-{
- const struct ip_set_nethash *map = set->data;
- ip_set_ip_t i, *elem;
-
- for (i = 0; i < map->hashsize; i++) {
- elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
- ((ip_set_ip_t *)data)[i] = *elem;
- }
-}
-
-static struct ip_set_type ip_set_nethash = {
- .typename = SETTYPE_NAME,
- .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
- .protocol_version = IP_SET_PROTOCOL_VERSION,
- .create = &create,
- .destroy = &destroy,
- .flush = &flush,
- .reqsize = sizeof(struct ip_set_req_nethash),
- .addip = &addip,
- .addip_kernel = &addip_kernel,
- .retry = &retry,
- .delip = &delip,
- .delip_kernel = &delip_kernel,
- .testip = &testip,
- .testip_kernel = &testip_kernel,
- .header_size = sizeof(struct ip_set_req_nethash_create),
- .list_header = &list_header,
- .list_members_size = &list_members_size,
- .list_members = &list_members,
- .me = THIS_MODULE,
-};
+IP_SET_RTYPE(nethash, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -460,17 +219,4 @@ MODULE_DESCRIPTION("nethash type of IP sets");
module_param(limit, int, 0600);
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
-static int __init ip_set_nethash_init(void)
-{
- init_max_page_size();
- return ip_set_register_set_type(&ip_set_nethash);
-}
-
-static void __exit ip_set_nethash_fini(void)
-{
- /* FIXME: possible race with ip_set_create() */
- ip_set_unregister_set_type(&ip_set_nethash);
-}
-
-module_init(ip_set_nethash_init);
-module_exit(ip_set_nethash_fini);
+REGISTER_MODULE(nethash)
diff --git a/kernel/ip_set_portmap.c b/kernel/ip_set_portmap.c
index aeaabcd..79cc511 100644
--- a/kernel/ip_set_portmap.c
+++ b/kernel/ip_set_portmap.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,6 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/skbuff.h>
-#include <linux/version.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_set.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
@@ -22,102 +19,40 @@
#include <net/ip.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_bitmaps.h>
#include <linux/netfilter_ipv4/ip_set_portmap.h>
-
-/* We must handle non-linear skbs */
-static inline ip_set_ip_t
-get_port(const struct sk_buff *skb, u_int32_t flags)
-{
- struct iphdr *iph = ip_hdr(skb);
- u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
- switch (iph->protocol) {
- case IPPROTO_TCP: {
- struct tcphdr tcph;
-
- /* See comments at tcp_match in ip_tables.c */
- if (offset)
- return INVALID_PORT;
-
- if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &tcph, sizeof(tcph)) < 0)
- /* No choice either */
- return INVALID_PORT;
-
- return ntohs(flags & IPSET_SRC ?
- tcph.source : tcph.dest);
- }
- case IPPROTO_UDP: {
- struct udphdr udph;
-
- if (offset)
- return INVALID_PORT;
-
- if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &udph, sizeof(udph)) < 0)
- /* No choice either */
- return INVALID_PORT;
-
- return ntohs(flags & IPSET_SRC ?
- udph.source : udph.dest);
- }
- default:
- return INVALID_PORT;
- }
-}
+#include <linux/netfilter_ipv4/ip_set_getport.h>
static inline int
-__testport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
+portmap_test(const struct ip_set *set, ip_set_ip_t *hash_port,
+ ip_set_ip_t port)
{
- struct ip_set_portmap *map = set->data;
+ const struct ip_set_portmap *map = set->data;
- if (port < map->first_port || port > map->last_port)
+ 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);
- return !!test_bit(port - map->first_port, map->members);
+ return !!test_bit(port - map->first_ip, map->members);
}
-static int
-testport(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_port)
-{
- const struct ip_set_req_portmap *req = data;
-
- if (size != sizeof(struct ip_set_req_portmap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_portmap),
- size);
- return -EINVAL;
- }
- return __testport(set, req->port, hash_port);
-}
-
-static int
-testport_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_port,
- const u_int32_t *flags,
- unsigned char index)
-{
- int res;
- ip_set_ip_t port = get_port(skb, flags[index]);
-
- DP("flag %s port %u", flags[index] & IPSET_SRC ? "SRC" : "DST", port);
- if (port == INVALID_PORT)
+#define KADT_CONDITION \
+ if (ip == INVALID_PORT) \
return 0;
- res = __testport(set, port, hash_port);
-
- return (res < 0 ? 0 : res);
-}
+UADT(portmap, test)
+KADT(portmap, test, get_port)
static inline int
-__addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
+portmap_add(struct ip_set *set, ip_set_ip_t *hash_port, ip_set_ip_t port)
{
struct ip_set_portmap *map = set->data;
- if (port < map->first_port || port > map->last_port)
+ if (port < map->first_ip || port > map->last_ip)
return -ERANGE;
- if (test_and_set_bit(port - map->first_port, map->members))
+ if (test_and_set_bit(port - map->first_ip, map->members))
return -EEXIST;
*hash_port = port;
@@ -125,44 +60,17 @@ __addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
return 0;
}
-static int
-addport(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_port)
-{
- const struct ip_set_req_portmap *req = data;
-
- if (size != sizeof(struct ip_set_req_portmap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_portmap),
- size);
- return -EINVAL;
- }
- return __addport(set, req->port, hash_port);
-}
-
-static int
-addport_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_port,
- const u_int32_t *flags,
- unsigned char index)
-{
- ip_set_ip_t port = get_port(skb, flags[index]);
-
- if (port == INVALID_PORT)
- return -EINVAL;
-
- return __addport(set, port, hash_port);
-}
+UADT(portmap, add)
+KADT(portmap, add, get_port)
static inline int
-__delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
+portmap_del(struct ip_set *set, ip_set_ip_t *hash_port, ip_set_ip_t port)
{
struct ip_set_portmap *map = set->data;
- if (port < map->first_port || port > map->last_port)
+ if (port < map->first_ip || port > map->last_ip)
return -ERANGE;
- if (!test_and_clear_bit(port - map->first_port, map->members))
+ if (!test_and_clear_bit(port - map->first_ip, map->members))
return -EEXIST;
*hash_port = port;
@@ -170,160 +78,39 @@ __delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
return 0;
}
-static int
-delport(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_port)
-{
- const struct ip_set_req_portmap *req = data;
+UADT(portmap, del)
+KADT(portmap, del, get_port)
- if (size != sizeof(struct ip_set_req_portmap)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_portmap),
- size);
- return -EINVAL;
- }
- return __delport(set, req->port, hash_port);
-}
-
-static int
-delport_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_port,
- const u_int32_t *flags,
- unsigned char index)
-{
- ip_set_ip_t port = get_port(skb, flags[index]);
-
- if (port == INVALID_PORT)
- return -EINVAL;
-
- return __delport(set, port, hash_port);
-}
-
-static int create(struct ip_set *set, const void *data, size_t size)
+static inline int
+__portmap_create(const struct ip_set_req_portmap_create *req,
+ struct ip_set_portmap *map)
{
- int newbytes;
- const struct ip_set_req_portmap_create *req = data;
- struct ip_set_portmap *map;
-
- if (size != sizeof(struct ip_set_req_portmap_create)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_portmap_create),
- size);
- return -EINVAL;
- }
-
- DP("from %u to %u", req->from, req->to);
-
- if (req->from > req->to) {
- DP("bad port range");
- return -ENOEXEC;
- }
-
if (req->to - req->from > MAX_RANGE) {
- ip_set_printk("range too big (max %d ports)",
- MAX_RANGE+1);
+ ip_set_printk("range too big, %d elements (max %d)",
+ req->to - req->from + 1, MAX_RANGE+1);
return -ENOEXEC;
}
-
- map = kmalloc(sizeof(struct ip_set_portmap), GFP_KERNEL);
- if (!map) {
- DP("out of memory for %d bytes",
- sizeof(struct ip_set_portmap));
- return -ENOMEM;
- }
- map->first_port = req->from;
- map->last_port = req->to;
- newbytes = bitmap_bytes(req->from, req->to);
- map->members = kmalloc(newbytes, GFP_KERNEL);
- if (!map->members) {
- DP("out of memory for %d bytes", newbytes);
- kfree(map);
- return -ENOMEM;
- }
- memset(map->members, 0, newbytes);
-
- set->data = map;
- return 0;
-}
-
-static void destroy(struct ip_set *set)
-{
- struct ip_set_portmap *map = set->data;
-
- kfree(map->members);
- kfree(map);
-
- set->data = NULL;
-}
-
-static void flush(struct ip_set *set)
-{
- struct ip_set_portmap *map = set->data;
- memset(map->members, 0, bitmap_bytes(map->first_port, map->last_port));
+ return bitmap_bytes(req->from, req->to);
}
-static void list_header(const struct ip_set *set, void *data)
-{
- const struct ip_set_portmap *map = set->data;
- struct ip_set_req_portmap_create *header = data;
-
- DP("list_header %u %u", map->first_port, map->last_port);
+BITMAP_CREATE(portmap)
+BITMAP_DESTROY(portmap)
+BITMAP_FLUSH(portmap)
- header->from = map->first_port;
- header->to = map->last_port;
-}
-
-static int list_members_size(const struct ip_set *set)
+static inline void
+__portmap_list_header(const struct ip_set_portmap *map,
+ struct ip_set_req_portmap_create *header)
{
- const struct ip_set_portmap *map = set->data;
-
- return bitmap_bytes(map->first_port, map->last_port);
}
-static void list_members(const struct ip_set *set, void *data)
-{
- const struct ip_set_portmap *map = set->data;
- int bytes = bitmap_bytes(map->first_port, map->last_port);
-
- memcpy(data, map->members, bytes);
-}
+BITMAP_LIST_HEADER(portmap)
+BITMAP_LIST_MEMBERS_SIZE(portmap)
+BITMAP_LIST_MEMBERS(portmap)
-static struct ip_set_type ip_set_portmap = {
- .typename = SETTYPE_NAME,
- .features = IPSET_TYPE_PORT | IPSET_DATA_SINGLE,
- .protocol_version = IP_SET_PROTOCOL_VERSION,
- .create = &create,
- .destroy = &destroy,
- .flush = &flush,
- .reqsize = sizeof(struct ip_set_req_portmap),
- .addip = &addport,
- .addip_kernel = &addport_kernel,
- .delip = &delport,
- .delip_kernel = &delport_kernel,
- .testip = &testport,
- .testip_kernel = &testport_kernel,
- .header_size = sizeof(struct ip_set_req_portmap_create),
- .list_header = &list_header,
- .list_members_size = &list_members_size,
- .list_members = &list_members,
- .me = THIS_MODULE,
-};
+IP_SET_TYPE(portmap, IPSET_TYPE_PORT | IPSET_DATA_SINGLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("portmap type of IP sets");
-static int __init ip_set_portmap_init(void)
-{
- return ip_set_register_set_type(&ip_set_portmap);
-}
-
-static void __exit ip_set_portmap_fini(void)
-{
- /* FIXME: possible race with ip_set_create() */
- ip_set_unregister_set_type(&ip_set_portmap);
-}
-
-module_init(ip_set_portmap_init);
-module_exit(ip_set_portmap_fini);
+REGISTER_MODULE(portmap)
diff --git a/kernel/ip_set_setlist.c b/kernel/ip_set_setlist.c
new file mode 100644
index 0000000..50bc368
--- /dev/null
+++ b/kernel/ip_set_setlist.c
@@ -0,0 +1,332 @@
+/* Copyright (C) 2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an IP set type: the setlist type */
+
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_bitmaps.h>
+#include <linux/netfilter_ipv4/ip_set_setlist.h>
+
+/*
+ * before ==> id, ref
+ * after ==> ref, id
+ */
+
+static inline bool
+next_id_eq(const struct ip_set_setlist *map, int i, ip_set_id_t id)
+{
+ return i < map->size && map->id[i] == id;
+}
+
+static int
+setlist_utest(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ const struct ip_set_setlist *map = set->data;
+ const struct ip_set_req_setlist *req = data;
+ ip_set_id_t id, ref = IP_SET_INVALID_ID;
+ int i, res = 0;
+ struct ip_set *s;
+
+ if (req->before && req->ref[0] == '\0')
+ return -EINVAL;
+
+ id = __ip_set_get_byname(req->name, &s);
+ if (id == IP_SET_INVALID_ID)
+ return -EEXIST;
+ if (req->ref[0] != '\0') {
+ ref = __ip_set_get_byname(req->ref, &s);
+ if (ref == IP_SET_INVALID_ID) {
+ res = -EEXIST;
+ goto finish;
+ }
+ }
+ for (i = 0; i < map->size
+ && map->id[i] != IP_SET_INVALID_ID; i++) {
+ if (req->before && map->id[i] == id) {
+ res = next_id_eq(map, i + 1, ref);
+ break;
+ } else if (!req->before) {
+ if ((ref == IP_SET_INVALID_ID
+ && map->id[i] == id)
+ || (map->id[i] == ref
+ && next_id_eq(map, i + 1, id))) {
+ res = 1;
+ break;
+ }
+ }
+ }
+ if (ref != IP_SET_INVALID_ID)
+ __ip_set_put_byid(ref);
+finish:
+ __ip_set_put_byid(id);
+ return res;
+}
+
+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)
+{
+ struct ip_set_setlist *map = set->data;
+ int i, res = 0;
+
+ for (i = 0; i < map->size
+ && map->id[i] != IP_SET_INVALID_ID
+ && res == 0; i++)
+ res = ip_set_testip_kernel(map->id[i], skb, flags);
+ return res;
+}
+
+static inline int
+insert_setlist(struct ip_set_setlist *map, int i, ip_set_id_t id)
+{
+ ip_set_id_t tmp;
+ int j;
+
+ printk("i: %u, last %u\n", i, map->id[map->size - 1]);
+ if (i >= map->size || map->id[map->size - 1] != IP_SET_INVALID_ID)
+ return -ERANGE;
+
+ for (j = i; j < map->size
+ && id != IP_SET_INVALID_ID; j++) {
+ tmp = map->id[j];
+ map->id[j] = id;
+ id = tmp;
+ }
+ return 0;
+}
+
+static int
+setlist_uadd(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_setlist *map = set->data;
+ const struct ip_set_req_setlist *req = data;
+ ip_set_id_t id, ref = IP_SET_INVALID_ID;
+ int i, res = -ERANGE;
+ struct ip_set *s;
+
+ if (req->before && req->ref[0] == '\0')
+ return -EINVAL;
+
+ id = __ip_set_get_byname(req->name, &s);
+ if (id == IP_SET_INVALID_ID)
+ return -EEXIST;
+ /* "Loop detection" */
+ if (strcmp(s->type->typename, "setlist") == 0)
+ goto finish;
+
+ if (req->ref[0] != '\0') {
+ ref = __ip_set_get_byname(req->ref, &s);
+ if (ref == IP_SET_INVALID_ID) {
+ res = -EEXIST;
+ goto finish;
+ }
+ }
+ for (i = 0; i < map->size; i++) {
+ if (map->id[i] != ref)
+ continue;
+ if (req->before)
+ res = insert_setlist(map, i, id);
+ else
+ res = insert_setlist(map,
+ ref == IP_SET_INVALID_ID ? i : i + 1,
+ id);
+ break;
+ }
+ if (ref != IP_SET_INVALID_ID)
+ __ip_set_put_byid(ref);
+ /* In case of success, we keep the reference to the id */
+finish:
+ if (res != 0)
+ __ip_set_put_byid(id);
+ return res;
+}
+
+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)
+{
+ struct ip_set_setlist *map = set->data;
+ int i, res = -EINVAL;
+
+ for (i = 0; i < map->size
+ && map->id[i] != IP_SET_INVALID_ID
+ && res != 0; i++)
+ res = ip_set_addip_kernel(map->id[i], skb, flags);
+ return res;
+}
+
+static inline bool
+unshift_setlist(struct ip_set_setlist *map, int i)
+{
+ int j;
+
+ for (j = i; j < map->size - 1; j++)
+ map->id[j] = map->id[j+1];
+ map->id[map->size-1] = IP_SET_INVALID_ID;
+ return 0;
+}
+
+static int
+setlist_udel(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_setlist *map = set->data;
+ const struct ip_set_req_setlist *req = data;
+ ip_set_id_t id, ref = IP_SET_INVALID_ID;
+ int i, res = -EEXIST;
+ struct ip_set *s;
+
+ if (req->before && req->ref[0] == '\0')
+ return -EINVAL;
+
+ id = __ip_set_get_byname(req->name, &s);
+ if (id == IP_SET_INVALID_ID)
+ return -EEXIST;
+ if (req->ref[0] != '\0') {
+ ref = __ip_set_get_byname(req->ref, &s);
+ if (ref == IP_SET_INVALID_ID)
+ goto finish;
+ }
+ for (i = 0; i < map->size
+ && map->id[i] != IP_SET_INVALID_ID; i++) {
+ if (req->before) {
+ if (map->id[i] == id
+ && next_id_eq(map, i + 1, ref)) {
+ res = unshift_setlist(map, i);
+ break;
+ }
+ } else if (ref == IP_SET_INVALID_ID) {
+ if (map->id[i] == id) {
+ res = unshift_setlist(map, i);
+ break;
+ }
+ } else if (map->id[i] == ref
+ && next_id_eq(map, i + 1, id)) {
+ res = unshift_setlist(map, i + 1);
+ break;
+ }
+ }
+ if (ref != IP_SET_INVALID_ID)
+ __ip_set_put_byid(ref);
+finish:
+ __ip_set_put_byid(id);
+ /* In case of success, release the reference to the id */
+ if (res == 0)
+ __ip_set_put_byid(id);
+ return res;
+}
+
+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)
+{
+ struct ip_set_setlist *map = set->data;
+ int i, res = -EINVAL;
+
+ for (i = 0; i < map->size
+ && map->id[i] != IP_SET_INVALID_ID
+ && res != 0; i++)
+ res = ip_set_delip_kernel(map->id[i], skb, flags);
+ return res;
+}
+
+static int
+setlist_create(struct ip_set *set, const void *data, size_t size)
+{
+ struct ip_set_setlist *map;
+ const struct ip_set_req_setlist_create *req = data;
+ int i;
+
+ map = kmalloc(sizeof(struct ip_set_setlist) +
+ req->size * sizeof(ip_set_id_t), GFP_KERNEL);
+ if (!map)
+ return -ENOMEM;
+ map->size = req->size;
+ for (i = 0; i < map->size; i++)
+ map->id[i] = IP_SET_INVALID_ID;
+
+ set->data = map;
+ return 0;
+}
+
+static void
+setlist_destroy(struct ip_set *set)
+{
+ struct ip_set_setlist *map = set->data;
+ int i;
+
+ for (i = 0; i < map->size
+ && map->id[i] != IP_SET_INVALID_ID; i++)
+ __ip_set_put_byid(map->id[i]);
+
+ kfree(map);
+ set->data = NULL;
+}
+
+static void
+setlist_flush(struct ip_set *set)
+{
+ struct ip_set_setlist *map = set->data;
+ int i;
+
+ for (i = 0; i < map->size
+ && map->id[i] != IP_SET_INVALID_ID; i++) {
+ __ip_set_put_byid(map->id[i]);
+ map->id[i] = IP_SET_INVALID_ID;
+ }
+}
+
+static void
+setlist_list_header(const struct ip_set *set, void *data)
+{
+ const struct ip_set_setlist *map = set->data;
+ struct ip_set_req_setlist_create *header = data;
+
+ header->size = map->size;
+}
+
+static int
+setlist_list_members_size(const struct ip_set *set)
+{
+ const struct ip_set_setlist *map = set->data;
+
+ return map->size * sizeof(ip_set_id_t);
+}
+
+static void
+setlist_list_members(const struct ip_set *set, void *data)
+{
+ struct ip_set_setlist *map = set->data;
+ int i;
+
+ for (i = 0; i < map->size; i++)
+ *((ip_set_id_t *)data + i) = map->id[i];
+}
+
+IP_SET_TYPE(setlist, IPSET_TYPE_SETNAME | IPSET_DATA_SINGLE)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("setlist type of IP sets");
+
+REGISTER_MODULE(setlist)