]> granicus.if.org Git - ipset/commitdiff
ipset 5 in an almost ready state - milestone v5.0-pre1
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Tue, 15 Jun 2010 11:30:55 +0000 (13:30 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Tue, 15 Jun 2010 11:30:55 +0000 (13:30 +0200)
Reworked protocol and internal interfaces, missing set types added,
backward compatibility verified, lots of tests added (and thanks to the tests,
bugs fixed), even the manpage is rewritten ;-). Countless changes everywhere...
The missing bits before announcing ipset 5:

- net namespace support
- new iptables/ip6tables extension library
- iptables/ip6tables match and target tests (backward/forward compatibility)
- tests on catching syntax errors

145 files changed:
Make_global.am
Makefile.am
include/libipset/data.h
include/libipset/debug.h [new file with mode: 0644]
include/libipset/linux_ip_set.h
include/libipset/linux_ip_set_list.h [new file with mode: 0644]
include/libipset/parse.h
include/libipset/print.h
include/libipset/session.h
include/libipset/types.h
include/libipset/ui.h
include/libipset/utils.h
kernel/Kbuild
kernel/include/linux/netfilter/ip_set.h
kernel/include/linux/netfilter/ip_set_bitmap.h
kernel/include/linux/netfilter/ip_set_chash.h [new file with mode: 0644]
kernel/include/linux/netfilter/ip_set_getport.h
kernel/include/linux/netfilter/ip_set_hash.h
kernel/include/linux/netfilter/ip_set_jhash.h
kernel/include/linux/netfilter/ip_set_kernel.h [new file with mode: 0644]
kernel/include/linux/netfilter/ip_set_list.h [new file with mode: 0644]
kernel/include/linux/netfilter/ip_set_slist.h [new file with mode: 0644]
kernel/include/linux/netfilter/ip_set_timeout.h
kernel/include/linux/netfilter/ipt_set.h [deleted file]
kernel/include/linux/netfilter/xt_set.h [new file with mode: 0644]
kernel/ip_set.c
kernel/ip_set_bitmap_ip.c
kernel/ip_set_bitmap_ipmac.c
kernel/ip_set_bitmap_port.c
kernel/ip_set_hash_ip.c
kernel/ip_set_hash_ip_src.c [deleted file]
kernel/ip_set_hash_ipport.c
kernel/ip_set_hash_ipportip.c
kernel/ip_set_hash_ipportnet.c
kernel/ip_set_hash_net.c
kernel/ip_set_iptreemap.c [deleted file]
kernel/ip_set_list_set.c
kernel/ip_set_tree_ip.c [deleted file]
kernel/ipt_SET.c [deleted file]
kernel/ipt_set.c [deleted file]
kernel/xt_set.c [new file with mode: 0644]
lib/Makefile.am
lib/PROTOCOL
lib/data.c
lib/mnl.c
lib/parse.c
lib/print.c
lib/session.c
lib/types.c
lib/utils.c [deleted file]
netlink.patch
src/Makefile.am
src/errcode.c
src/ipset.8
src/ipset.c
src/ipset_bitmap_ip.c
src/ipset_bitmap_ipmac.c
src/ipset_bitmap_port.c
src/ipset_hash_ip.c
src/ipset_hash_ipport.c
src/ipset_hash_ipportip.c
src/ipset_hash_ipportnet.c
src/ipset_hash_net.c
src/ipset_iptreemap.c [deleted file]
src/ipset_list_set.c
src/ipset_tree_ip.c [deleted file]
src/ui.c
tests/Makefile [new file with mode: 0644]
tests/Makefile.am [new file with mode: 0644]
tests/Makefile.in [new file with mode: 0644]
tests/bitmap:ip.t
tests/bitmap:ip.t.list0
tests/bitmap:ip.t.list1
tests/bitmap:ip.t.list2
tests/bitmap:ip.t.list3
tests/bitmap:ip.t.list4 [new file with mode: 0644]
tests/bitmap:ip.t.list5 [new file with mode: 0644]
tests/bitmap:ip.t.list6 [new file with mode: 0644]
tests/hash:ip,port,ip.t [new file with mode: 0644]
tests/hash:ip,port,ip.t.list0 [new file with mode: 0644]
tests/hash:ip,port,ip.t.list1 [new file with mode: 0644]
tests/hash:ip,port.t [new file with mode: 0644]
tests/hash:ip,port.t.list0 [new file with mode: 0644]
tests/hash:ip,port.t.list1 [new file with mode: 0644]
tests/hash:ip.t
tests/hash:ip.t.list0
tests/hash:ip.t.list1
tests/hash:ip.t.list2 [new file with mode: 0644]
tests/hash:ip.t.list3 [new file with mode: 0644]
tests/hash:ip6,port,ip6.t [new file with mode: 0644]
tests/hash:ip6,port,ip6.t.list0 [new file with mode: 0644]
tests/hash:ip6,port,ip6.t.list1 [new file with mode: 0644]
tests/hash:ip6,port,net6.t [new file with mode: 0644]
tests/hash:ip6,port,net6.t.list0 [new file with mode: 0644]
tests/hash:ip6,port.t [new file with mode: 0644]
tests/hash:ip6,port.t.list0 [new file with mode: 0644]
tests/hash:ip6,port.t.list1 [new file with mode: 0644]
tests/hash:ip6.t [new file with mode: 0644]
tests/hash:ip6.t.list0 [new file with mode: 0644]
tests/hash:ip6.t.list1 [new file with mode: 0644]
tests/hash:ip6.t.list2 [new file with mode: 0644]
tests/hash:ip6.t.list3 [new file with mode: 0644]
tests/hash:net.t [new file with mode: 0644]
tests/hash:net.t.list0 [new file with mode: 0644]
tests/hash:net.t.list1 [new file with mode: 0644]
tests/hash:net6.t [new file with mode: 0644]
tests/hash:net6.t.list0 [new file with mode: 0644]
tests/hash:net6.t.list1 [new file with mode: 0644]
tests/iphash.t
tests/iphash.t.list0
tests/iphash.t.list1
tests/ipmap.t
tests/ipmap.t.list0
tests/ipmap.t.list1
tests/ipmap.t.list2
tests/ipmap.t.list3
tests/ipmap.t.list4
tests/ipporthash.t
tests/ipporthash.t.list0
tests/ipporthash.t.list1
tests/ipportiphash.t
tests/ipportiphash.t.list0
tests/ipportiphash.t.list1
tests/ipportnethash.t
tests/ipportnethash.t.list0
tests/ipportnethash.t.list1
tests/iptree.t
tests/iptree.t.list0
tests/iptreemap.t
tests/iptreemap.t.list0
tests/macipmap.t
tests/macipmap.t.list0
tests/macipmap.t.list1
tests/macipmap.t.list2
tests/macipmap.t.list3 [new file with mode: 0644]
tests/nethash.t
tests/nethash.t.list0
tests/portmap.t
tests/portmap.t.list0
tests/portmap.t.list1
tests/portmap.t.list3 [new file with mode: 0644]
tests/runtest.sh
tests/setlist.t
tests/setlist.t.list0
tests/sort.sh

index 5c65103b4da5d175797e1f35755fc587c8558d56..ac9a2ca8c4a01a8a9558c8290b39279a4556790f 100644 (file)
@@ -39,7 +39,7 @@ AM_CFLAGS = -std=gnu99 \
        -Wwrite-strings \
        -Wno-missing-field-initializers \
        -Werror \
-       -g -ggdb
+       -g -ggdb -gdwarf-2 -g3
 endif
 
 if ! ENABLE_VERBOSE
index 2eb7a00e5e1d18e61c4088619d7b58d4c51e0a39..e5c1c838326036d296bc52dc8524127fb37e94e7 100644 (file)
@@ -33,6 +33,7 @@ update_includes:
        ./update ip_set.h
        ./update ip_set_bitmap.h
        ./update ip_set_hash.h
+       ./update ip_set_list.h
 
 tests:
        cd tests; ./runtest.sh
index 0ebc1ebc7bfc1f9d761f70f6b995fbb7c1997aa3..936b807c52b4b6dbaa9bd6b4cc6fd7466d9c8f3b 100644 (file)
@@ -50,7 +50,8 @@ enum ipset_opt {
        IPSET_OPT_EXIST,
        IPSET_OPT_BEFORE,
        /* Internal options */
-       IPSET_OPT_FLAGS = 48,
+       IPSET_OPT_FLAGS = 48,   /* IPSET_FLAG_EXIST| */
+       IPSET_OPT_CADT_FLAGS,   /* IPSET_FLAG_BEFORE| */
        IPSET_OPT_ELEM,
        IPSET_OPT_TYPE,
        IPSET_OPT_LINENO,
@@ -63,7 +64,10 @@ enum ipset_opt {
 #define IPSET_FLAGS_ALL                (~0LL)
 
 #define IPSET_CREATE_FLAGS             \
-       ( IPSET_FLAG(IPSET_OPT_IP)      \
+       ( IPSET_FLAG(IPSET_OPT_FAMILY)  \
+       | IPSET_FLAG(IPSET_OPT_TYPENAME)\
+       | IPSET_FLAG(IPSET_OPT_TYPE)    \
+       | IPSET_FLAG(IPSET_OPT_IP)      \
        | IPSET_FLAG(IPSET_OPT_IP_TO)   \
        | IPSET_FLAG(IPSET_OPT_CIDR)    \
        | IPSET_FLAG(IPSET_OPT_PORT)    \
@@ -89,14 +93,17 @@ enum ipset_opt {
        | IPSET_FLAG(IPSET_OPT_NAMEREF) \
        | IPSET_FLAG(IPSET_OPT_IP2)     \
        | IPSET_FLAG(IPSET_OPT_CIDR2)   \
+       | IPSET_FLAG(IPSET_OPT_CADT_FLAGS)\
        | IPSET_FLAG(IPSET_OPT_BEFORE))
 
 struct ipset_data;
 
+extern void ipset_strncpy(char *dst, const char *src, size_t len);
 extern bool ipset_data_flags_test(const struct ipset_data *data,
                                  uint64_t flags);
 extern void ipset_data_flags_set(struct ipset_data *data, uint64_t flags);
 extern void ipset_data_flags_unset(struct ipset_data *data, uint64_t flags);
+extern bool ipset_data_ignored(struct ipset_data *data, enum ipset_opt opt);
 
 extern int ipset_data_set(struct ipset_data *data, enum ipset_opt opt,
                          const void *value);
diff --git a/include/libipset/debug.h b/include/libipset/debug.h
new file mode 100644 (file)
index 0000000..1e32ce2
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright 2007-2010 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.
+ */
+#ifndef LIBIPSET_DEBUG_H
+#define LIBIPSET_DEBUG_H
+
+#define IPSET_DEBUG
+
+#ifdef IPSET_DEBUG
+#include <stdio.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#define D(fmt, args...) \
+       fprintf(stderr, "%s: %s: " fmt "\n", __FILE__, __FUNCTION__ , ## args)
+#define IF_D(test, fmt, args...) \
+       if (test)                \
+               D(fmt , ## args)
+
+static inline void
+dump_nla(struct  nlattr *nla[], int maxlen)
+{
+       int i;
+       for (i = 0; i < maxlen; i++)
+               D("nla[%u] does%s exist", i, nla[i] ? "" : " NOT");
+}
+#else
+#define D(fmt, args...)
+#define IF_D(test, fmt, args...)
+#define dump_nla(nla, maxlen)
+#endif
+
+#endif /* LIBIPSET_DEBUG_H */
index 254fb2146b85b648bb364c89a8a363cf045b8e3f..4af75baa3afbb9aee2592b1f93c924aec523b484 100644 (file)
  * published by the Free Software Foundation.  
  */
 
-#if 1
-#define IP_SET_DEBUG
-#endif
-
 /* The protocol version */
 #define IPSET_PROTOCOL         5
 
-/* The max length of strings: set and type identifiers */
+/* The max length of strings including NUL: set and type identifiers */
 #define IPSET_MAXNAMELEN       32
 
 /* Message types and commands */
@@ -43,6 +39,7 @@ enum ipset_cmd {
        IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* Enter restore mode */     
        IPSET_CMD_HELP,         /* Get help */
        IPSET_CMD_VERSION,      /* Get program version */
+       IPSET_CMD_QUIT,         /* Quit from interactive mode */
 
        IPSET_CMD_MAX,
 
@@ -58,6 +55,7 @@ enum {
        IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* rename/swap */
        IPSET_ATTR_REVISION,    /* Settype revision */
        IPSET_ATTR_FAMILY,      /* Settype family */
+       IPSET_ATTR_FLAGS,       /* Flags at command level */
        IPSET_ATTR_DATA,        /* Nested attributes */
        IPSET_ATTR_ADT,         /* Multiple data containers */
        IPSET_ATTR_LINENO,      /* Restore lineno */
@@ -77,8 +75,8 @@ enum {
        IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT,
        IPSET_ATTR_PORT_TO,
        IPSET_ATTR_TIMEOUT,
-       IPSET_ATTR_FLAGS,
-       /* IPSET_ATTR_LINENO */
+       IPSET_ATTR_CADT_FLAGS,
+       IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO,
        /* Reserve empty slots */
        IPSET_ATTR_CADT_MAX = 16,
        /* Create-only specific attributes */
@@ -123,15 +121,19 @@ enum ipset_errno {
        IPSET_ERR_INVALID_NETMASK,
        IPSET_ERR_INVALID_FAMILY,
        IPSET_ERR_TIMEOUT,
+       IPSET_ERR_REFERENCED,
 
+       /* Type specific error codes */
        IPSET_ERR_TYPE_SPECIFIC = 160,
 };
-                                       
-enum ipset_data_flags {
+
+enum ipset_cmd_flags {
        IPSET_FLAG_BIT_EXIST    = 0,
        IPSET_FLAG_EXIST        = (1 << IPSET_FLAG_BIT_EXIST),
-       
-       IPSET_FLAG_BIT_BEFORE   = 2,
+};
+
+enum ipset_cadt_flags {
+       IPSET_FLAG_BIT_BEFORE   = 0,
        IPSET_FLAG_BEFORE       = (1 << IPSET_FLAG_BIT_BEFORE),
 };
 
@@ -140,32 +142,9 @@ enum ipset_adt {
        IPSET_ADD,
        IPSET_DEL,
        IPSET_TEST,
-       IPSET_CREATE,
+       IPSET_ADT_MAX,
+       IPSET_CREATE = IPSET_ADT_MAX,
        IPSET_CADT_MAX,
 };
 
-#ifndef __KERNEL__
-#ifdef IP_SET_DEBUG
-#include <stdio.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#define D(format, args...)     do {                            \
-       fprintf(stderr, "%s: %s: ", __FILE__, __FUNCTION__);    \
-       fprintf(stderr, format "\n" , ## args);                 \
-} while (0)
-static inline void
-dump_nla(struct  nlattr *nla[], int maxlen)
-{
-       int i;
-       
-       for (i = 0; i < maxlen; i++)
-               D("nla[%u] does%s exist", i, !nla[i] ? " NOT" : "");
-}
-
-#else
-#define D(format, args...)
-#define dump_nla(nla, maxlen)
-#endif
-#endif /* !__KERNEL__ */
-
 #endif /* __IP_SET_H */
diff --git a/include/libipset/linux_ip_set_list.h b/include/libipset/linux_ip_set_list.h
new file mode 100644 (file)
index 0000000..cf282c5
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __IP_SET_LIST_H
+#define __IP_SET_LIST_H
+
+/* List type specific error codes */
+enum {
+       IPSET_ERR_NAME = IPSET_ERR_TYPE_SPECIFIC,
+       IPSET_ERR_LOOP,
+       IPSET_ERR_BEFORE,
+       IPSET_ERR_NAMEREF,
+       IPSET_ERR_LIST_FULL,
+       IPSET_ERR_REF_EXIST,
+};
+
+#endif /* __IP_SET_LIST_H */
index 09c1db45eb440218916225c095b3c1f5ee15c3f2..143e2b37784f69587a03c01f4ab8e85a58ef49cc 100644 (file)
@@ -17,6 +17,9 @@
 
 struct ipset_session;
 
+typedef int (*ipset_parsefn)(struct ipset_session *s,
+                            enum ipset_opt opt, const char *str);
+
 extern int ipset_parse_ether(struct ipset_session *session,
                              enum ipset_opt opt, const char *str);
 extern int ipset_parse_single_port(struct ipset_session *session,
@@ -24,7 +27,7 @@ extern int ipset_parse_single_port(struct ipset_session *session,
 extern int ipset_parse_port(struct ipset_session *session,
                             enum ipset_opt opt, const char *str);
 extern int ipset_parse_family(struct ipset_session *session,
-                              int opt, const char *str);
+                              enum ipset_opt opt, const char *str);
 extern int ipset_parse_ip(struct ipset_session *session,
                           enum ipset_opt opt, const char *str);
 extern int ipset_parse_single_ip(struct ipset_session *session,
@@ -35,8 +38,16 @@ extern int ipset_parse_range(struct ipset_session *session,
                              enum ipset_opt opt, const char *str);
 extern int ipset_parse_netrange(struct ipset_session *session,
                                enum ipset_opt opt, const char *str);
+extern int ipset_parse_iprange(struct ipset_session *session,
+                              enum ipset_opt opt, const char *str);
+extern int ipset_parse_ipnet(struct ipset_session *session,
+                            enum ipset_opt opt, const char *str);
 extern int ipset_parse_name(struct ipset_session *session,
                             enum ipset_opt opt, const char *str);
+extern int ipset_parse_before(struct ipset_session *session,
+                              enum ipset_opt opt, const char *str);
+extern int ipset_parse_after(struct ipset_session *session,
+                             enum ipset_opt opt, const char *str);
 extern int ipset_parse_setname(struct ipset_session *session,
                                enum ipset_opt opt, const char *str);
 extern int ipset_parse_uint32(struct ipset_session *session,
@@ -51,7 +62,18 @@ extern int ipset_parse_typename(struct ipset_session *session,
                                enum ipset_opt opt, const char *str);
 extern int ipset_parse_output(struct ipset_session *session,
                               int opt, const char *str);
+extern int ipset_parse_ignored(struct ipset_session *session,
+                               enum ipset_opt opt, const char *str);
 extern int ipset_parse_elem(struct ipset_session *session,
                             enum ipset_opt opt, const char *str);
+extern int ipset_call_parser(struct ipset_session *session,
+                            ipset_parsefn parse, const char *optstr,
+                            enum ipset_opt optional, const char *str);
+
+/* Compatibility parser functions */
+extern int ipset_parse_iptimeout(struct ipset_session *session,
+                                enum ipset_opt opt, const char *str);
+extern int ipset_parse_name_compat(struct ipset_session *session,
+                                  enum ipset_opt opt, const char *str);
 
 #endif /* LIBIPSET_PARSE_H */
index 343386bc7380d0e4dcd7f9e9e88061737b0738fe..dbb70f3796cd1956696929f03010f809c5e968ba 100644 (file)
@@ -9,11 +9,15 @@
 
 #include <libipset/data.h>                     /* enum ipset_opt */
 
+typedef int (*ipset_printfn)(char *buf, unsigned int len,
+                            const struct ipset_data *data, enum ipset_opt opt,
+                            uint8_t env);
+
 extern int ipset_print_ether(char *buf, unsigned int len,
                             const struct ipset_data *data, enum ipset_opt opt,
                             uint8_t env);
 extern int ipset_print_family(char *buf, unsigned int len,
-                             const struct ipset_data *data, int opt,
+                             const struct ipset_data *data, enum ipset_opt opt,
                              uint8_t env);
 extern int ipset_print_type(char *buf, unsigned int len,
                            const struct ipset_data *data, enum ipset_opt opt,
index 71b8e02bca986ff9e9bf2dfea8f4747c27defe52..cc0940e2a19c803cb1e69c429a31a27babcccc84 100644 (file)
@@ -12,7 +12,6 @@
 #include <stdio.h>                             /* printf */
 
 #include <libipset/linux_ip_set.h>             /* enum ipset_cmd */
-#include <libipset/ui.h>                       /* enum ipset_envopt */
 
 /* Report and output buffer sizes */
 #define IPSET_ERRORBUFLEN              1024
@@ -54,6 +53,23 @@ extern const char * ipset_session_warning(const struct ipset_session *session);
 #define ipset_session_data_get(session, opt)           \
        ipset_data_get(ipset_session_data(session), opt)
 
+/* Environment option flags */
+enum ipset_envopt {
+       IPSET_ENV_BIT_SORTED    = 0,
+       IPSET_ENV_SORTED        = (1 << IPSET_ENV_BIT_SORTED),
+       IPSET_ENV_BIT_QUIET     = 1,
+       IPSET_ENV_QUIET         = (1 << IPSET_ENV_BIT_QUIET),
+       IPSET_ENV_BIT_RESOLVE   = 2,
+       IPSET_ENV_RESOLVE       = (1 << IPSET_ENV_BIT_RESOLVE),
+       IPSET_ENV_BIT_EXIST     = 3,
+       IPSET_ENV_EXIST         = (1 << IPSET_ENV_BIT_EXIST),
+};
+
+extern int ipset_envopt_parse(struct ipset_session *session,
+                             int env, const char *str);
+extern bool ipset_envopt_test(struct ipset_session *session,
+                             enum ipset_envopt env);
+
 enum ipset_output_mode {
        IPSET_LIST_NONE,
        IPSET_LIST_PLAIN,
@@ -61,10 +77,6 @@ enum ipset_output_mode {
        IPSET_LIST_XML,
 };
 
-extern int ipset_envopt_parse(struct ipset_session *session,
-                             int env, const char *str);
-extern bool ipset_envopt_test(struct ipset_session *session,
-                             enum ipset_envopt env);
 extern int ipset_session_output(struct ipset_session *session,
                                enum ipset_output_mode mode);
 
index 461931a3cc3bedda0e2fc729d03cd849b5374d97..45d5e3d767fe94958d282f3e6900a8f8c3e10eb6 100644 (file)
@@ -10,6 +10,8 @@
 #include <stdint.h>                            /* uintxx_t */
 
 #include <libipset/data.h>                     /* enum ipset_opt */
+#include <libipset/parse.h>                    /* ipset_parsefn */
+#include <libipset/print.h>                    /* ipset_printfn */
 #include <libipset/linux_ip_set.h>             /* IPSET_MAXNAMELEN */
 
 #define AF_INET46              255
@@ -39,15 +41,9 @@ enum {
 
 struct ipset_session;
 
-typedef int (*ipset_parsefn)(struct ipset_session *s,
-                            enum ipset_opt opt, const char *str);
-typedef int (*ipset_printfn)(char *buf, unsigned int len,
-                            const struct ipset_data *data, enum ipset_opt opt,
-                            uint8_t env);
-
 /* Parse and print type-specific arguments */
 struct ipset_arg {
-       const char *name[3];            /* option names */
+       const char *name[2];            /* option names */
        int has_arg;                    /* mandatory/optional/no arg */
        enum ipset_opt opt;             /* argumentum type */
        ipset_parsefn parse;            /* parser function */
@@ -81,13 +77,13 @@ struct ipset_elem {
   */
 struct ipset_type {
        char name[IPSET_MAXNAMELEN];                    /* type name */
-       char alias[IPSET_MAXNAMELEN];                   /* name alias */
        uint8_t revision;                               /* revision number */
        uint8_t family;                                 /* supported family */
        uint8_t dimension;                              /* elem dimension */
        int8_t kernel_check;                            /* kernel check */
        bool last_elem_optional;                        /* last element optional */
        struct ipset_elem elem[IPSET_DIM_MAX];          /* parse elem */
+       ipset_parsefn compat_parse_elem;                /* compatibility parser */
        const struct ipset_arg *args[IPSET_CADT_MAX];   /* create/ADT args except elem */
        uint64_t mandatory[IPSET_CADT_MAX];             /* create/ADT mandatory flags */
        uint64_t full[IPSET_CADT_MAX];                  /* full args flags */
@@ -95,13 +91,18 @@ struct ipset_type {
        const char *usage;                              /* terse usage */
 
        struct ipset_type *next;
+       const char *alias[];                                    /* name alias(es) */
 };
 
-extern int ipset_cache_add(const char *name, const struct ipset_type *type);
+extern int ipset_cache_add(const char *name, const struct ipset_type *type,
+                          uint8_t family);
 extern int ipset_cache_del(const char *name);
 extern int ipset_cache_rename(const char *from, const char *to);
 extern int ipset_cache_swap(const char *from, const char *to);
 
+extern int ipset_cache_init(void);
+extern void ipset_cache_fini(void);
+
 extern const struct ipset_type * ipset_type_get(struct ipset_session *session,
                                                enum ipset_cmd cmd);
 extern const struct ipset_type * ipset_type_check(struct ipset_session *session);
@@ -109,20 +110,7 @@ extern const struct ipset_type * ipset_type_check(struct ipset_session *session)
 extern int ipset_type_add(struct ipset_type *type);
 extern const struct ipset_type * ipset_types(void);
 extern const char * ipset_typename_resolve(const char *str);
-
-extern int ipset_types_init(void);
-extern void ipset_types_fini(void);
-
-/* The known set types: (typename, revision, family) is unique */
-extern struct ipset_type ipset_bitmap_ip0;
-extern struct ipset_type ipset_bitmap_ipmac0;
-extern struct ipset_type ipset_bitmap_port0;
-extern struct ipset_type ipset_hash_ip0;
-extern struct ipset_type ipset_hash_net0;
-extern struct ipset_type ipset_hash_ipport0;
-extern struct ipset_type ipset_hash_ipportip0;
-extern struct ipset_type ipset_hash_ipportnet0;
-extern struct ipset_type ipset_tree_ip0;
-extern struct ipset_type ipset_list_set0;
+extern bool ipset_match_typename(const char *str,
+                                const struct ipset_type *t);
 
 #endif /* LIBIPSET_TYPES_H */
index 044e58633eb74040500c12a61769febdeccdb6df..f8eeae0563d7e03bf722879c7db2d29d5e4f8f51 100644 (file)
@@ -9,25 +9,14 @@
 
 /* Commands in userspace */
 struct ipset_commands {
-       const char *name[6];
-       const char *help;
+       enum ipset_cmd cmd;
        int has_arg;
+       const char *name[2];
+       const char *help;
 };
 
 extern const struct ipset_commands ipset_commands[];
 
-/* Environment option flags */
-enum ipset_envopt {
-       IPSET_ENV_BIT_SORTED    = 0,
-       IPSET_ENV_SORTED        = (1 << IPSET_ENV_BIT_SORTED),
-       IPSET_ENV_BIT_QUIET     = 1,
-       IPSET_ENV_QUIET         = (1 << IPSET_ENV_BIT_QUIET),
-       IPSET_ENV_BIT_RESOLVE   = 2,
-       IPSET_ENV_RESOLVE       = (1 << IPSET_ENV_BIT_RESOLVE),
-       IPSET_ENV_BIT_EXIST     = 3,
-       IPSET_ENV_EXIST         = (1 << IPSET_ENV_BIT_EXIST),
-};
-
 struct ipset_session;
 struct ipset_data;
 
@@ -35,7 +24,7 @@ struct ipset_data;
 struct ipset_envopts {
        int flag;
        int has_arg;
-       const char *name[3];
+       const char *name[2];
        const char *help;
        int (*parse)(struct ipset_session *s, int flag, const char *str);
        int (*print)(char *buf, unsigned int len,
@@ -44,4 +33,9 @@ struct ipset_envopts {
 
 extern const struct ipset_envopts ipset_envopts[];
 
+extern bool ipset_match_cmd(const char *arg, const char * const name[]);
+extern bool ipset_match_option(const char *arg, const char * const name[]);
+extern bool ipset_match_envopt(const char *arg, const char * const name[]);
+extern void ipset_shift_argv(int *argc, char *argv[], int from);
+
 #endif /* LIBIPSET_UI_H */
index 2d12e91a723fb63083bc4d9c85863d41d9af9037..672bfa9dd2f645596a2bbad1ee77f5287ad5b31e 100644 (file)
@@ -7,7 +7,6 @@
 #ifndef LIBIPSET_UTILS_H
 #define LIBIPSET_UTILS_H
 
-#include <stdbool.h>                           /* bool */
 #include <string.h>                            /* strcmp */
 #include <netinet/in.h>                                /* struct in[6]_addr */
 
@@ -37,9 +36,4 @@ in6cpy(struct in6_addr *dest, const struct in6_addr *src)
        memcpy(dest, src, sizeof(struct in6_addr));
 }
 
-extern char * ipset_strchr(const char *str, const char *sep);
-extern bool ipset_name_match(const char *arg, const char * const name[]);
-extern void ipset_shift_argv(int *argc, char *argv[], int from);
-extern void ipset_strncpy(char *dst, const char *src, size_t len);
-
 #endif /* LIBIPSET_UTILS_H */
index c17171166bf770ceebec51f2b8511a50eca3c16c..9c7771a96ef8bf689d06bf47e92f38d88b795b44 100644 (file)
@@ -1,14 +1,11 @@
 EXTRA_CFLAGS := -I$(M)/include \
        -DCONFIG_IP_SET_MAX=$(IP_SET_MAX)
 
-obj-m += ip_set.o
-#ipt_set.o ipt_SET.o
+obj-m += ip_set.o xt_set.o
 obj-m += ip_set_bitmap_ip.o ip_set_bitmap_ipmac.o ip_set_bitmap_port.o
-obj-m += ip_set_hash_ip.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
+obj-m += ip_set_hash_ip.o ip_set_hash_ipport.o ip_set_hash_ipportip.o
+obj-m += ip_set_hash_net.o ip_set_hash_ipportnet.o
+obj-m += ip_set_list_set.o
 
 # It's for me...
 incdirs := $(M) $(M)/include/linux/netfilter
index d0b47a0a620be5f5a1539b9419318981b6050383..e7005039a7b01be1700e8c9f4981bc50cbc9167f 100644 (file)
  * published by the Free Software Foundation.  
  */
 
-#if 1
-#define IP_SET_DEBUG
-#endif
-
 /* The protocol version */
 #define IPSET_PROTOCOL         5
 
-/* The max length of strings: set and type identifiers */
+/* The max length of strings including NUL: set and type identifiers */
 #define IPSET_MAXNAMELEN       32
 
 /* Message types and commands */
@@ -43,6 +39,7 @@ enum ipset_cmd {
        IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* Enter restore mode */     
        IPSET_CMD_HELP,         /* Get help */
        IPSET_CMD_VERSION,      /* Get program version */
+       IPSET_CMD_QUIT,         /* Quit from interactive mode */
 
        IPSET_CMD_MAX,
 
@@ -58,6 +55,7 @@ enum {
        IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* rename/swap */
        IPSET_ATTR_REVISION,    /* Settype revision */
        IPSET_ATTR_FAMILY,      /* Settype family */
+       IPSET_ATTR_FLAGS,       /* Flags at command level */
        IPSET_ATTR_DATA,        /* Nested attributes */
        IPSET_ATTR_ADT,         /* Multiple data containers */
        IPSET_ATTR_LINENO,      /* Restore lineno */
@@ -77,8 +75,8 @@ enum {
        IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT,
        IPSET_ATTR_PORT_TO,
        IPSET_ATTR_TIMEOUT,
-       IPSET_ATTR_FLAGS,
-       /* IPSET_ATTR_LINENO */
+       IPSET_ATTR_CADT_FLAGS,
+       IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO,
        /* Reserve empty slots */
        IPSET_ATTR_CADT_MAX = 16,
        /* Create-only specific attributes */
@@ -123,15 +121,19 @@ enum ipset_errno {
        IPSET_ERR_INVALID_NETMASK,
        IPSET_ERR_INVALID_FAMILY,
        IPSET_ERR_TIMEOUT,
+       IPSET_ERR_REFERENCED,
 
+       /* Type specific error codes */
        IPSET_ERR_TYPE_SPECIFIC = 160,
 };
-                                       
-enum ipset_data_flags {
+
+enum ipset_cmd_flags {
        IPSET_FLAG_BIT_EXIST    = 0,
        IPSET_FLAG_EXIST        = (1 << IPSET_FLAG_BIT_EXIST),
-       
-       IPSET_FLAG_BIT_BEFORE   = 2,
+};
+
+enum ipset_cadt_flags {
+       IPSET_FLAG_BIT_BEFORE   = 0,
        IPSET_FLAG_BEFORE       = (1 << IPSET_FLAG_BIT_BEFORE),
 };
 
@@ -140,35 +142,13 @@ enum ipset_adt {
        IPSET_ADD,
        IPSET_DEL,
        IPSET_TEST,
-       IPSET_CREATE,
+       IPSET_ADT_MAX,
+       IPSET_CREATE = IPSET_ADT_MAX,
        IPSET_CADT_MAX,
 };
 
-#ifndef __KERNEL__
-#ifdef IP_SET_DEBUG
-#include <stdio.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#define D(format, args...)     do {                            \
-       fprintf(stderr, "%s: %s: ", __FILE__, __FUNCTION__);    \
-       fprintf(stderr, format "\n" , ## args);                 \
-} while (0)
-static inline void
-dump_nla(struct  nlattr *nla[], int maxlen)
-{
-       int i;
-       
-       for (i = 0; i < maxlen; i++)
-               D("nla[%u] does%s exist", i, !nla[i] ? " NOT" : "");
-}
-
-#else
-#define D(format, args...)
-#define dump_nla(nla, maxlen)
-#endif
-#endif /* !__KERNEL__ */
-
 #ifdef __KERNEL__
+#include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/netlink.h>
 #include <net/netlink.h>
@@ -176,19 +156,27 @@ dump_nla(struct  nlattr *nla[], int maxlen)
 /* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
  * and IPSET_INVALID_ID if you want to increase the max number of sets.
  */
-typedef uint16_t ip_set_id_t;
+typedef u16 ip_set_id_t;
 
 #define IPSET_INVALID_ID               65535
 
+enum ip_set_dim {
+       IPSET_DIM_ZERO = 0,
+       IPSET_DIM_ONE,
+       IPSET_DIM_TWO,
+       IPSET_DIM_THREE,
+       /* Max dimension in elements.
+        * If changed, new revision of iptables match/target is required.
+        */
+       IPSET_DIM_MAX = 6,
+};
+
 /* Option flags for kernel operations */
 enum ip_set_kopt {
-       /* Bit 0 is reserved */
-       IPSET_SRC_FLAG = 1,
-       IPSET_SRC = (1 << IPSET_SRC_FLAG),
-       IPSET_DST_FLAG = 2,
-       IPSET_DST = (1 << IPSET_DST_FLAG),
-       IPSET_INV_FLAG = 3,
-       IPSET_INV = (1 << IPSET_INV_FLAG),
+       IPSET_INV_MATCH = (1 << IPSET_DIM_ZERO),
+       IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE),
+       IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO),
+       IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
 };
 
 /* Set features */
@@ -203,72 +191,60 @@ enum ip_set_feature {
        IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG),
        IPSET_TYPE_NAME_FLAG = 4,
        IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG),
+       /* Actually just a flag for dumping */
+       IPSET_DUMP_LAST_FLAG = 7,
+       IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG),
 };
 
+/* Calculate the bytes required to store the inclusive range of a-b */
 static inline int
-bitmap_bytes(uint32_t a, uint32_t b)
+bitmap_bytes(u32 a, u32 b)
 {
        return 4 * ((((b - a + 8) / 8) + 3) / 4);
 }
 
-#define ip_set_printk(format, args...)                                 \
-       do {                                                    \
-               printk("%s: %s: ", __FILE__, __FUNCTION__);     \
-               printk(format "\n" , ## args);                  \
-       } while (0)
-
-#if defined(IP_SET_DEBUG)
-#define D(format, args...)                                     \
-       do {                                                    \
-               printk("%s: %s (DBG): ", __FILE__, __FUNCTION__);\
-               printk(format "\n" , ## args);                  \
-       } while (0)
-
-static inline void
-dump_nla(const struct nlattr * const nla[], int maxlen)
-{
-       int i;
-       
-       for (i = 0; i < maxlen; i++)
-               printk("nlattr[%u] does%s exist\n", i, nla[i] ? "" : " NOT");
-}
-#else
-#define D(format, args...)
-#define dump_nla(nla, maxlen)
-#endif
-
 struct ip_set;
 
+typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
+                          gfp_t gfp_flags, u32 timeout);
+
 /* Set type, variant-specific part */
 struct ip_set_type_variant {
        /* Kernelspace: test/add/del entries */
        int (*kadt)(struct ip_set *set, const struct sk_buff * skb,
-                   enum ipset_adt adt, uint8_t pf, const uint8_t *flags);
+                   enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
 
        /* Userspace: test/add/del entries */
        int (*uadt)(struct ip_set *set, struct nlattr *head, int len,
-                   enum ipset_adt adt, uint32_t *lineno, uint32_t flags);
+                   enum ipset_adt adt, u32 *lineno, u32 flags);
+
+       /* Low level add/del/test entries */
+       ipset_adtfn adt[IPSET_ADT_MAX];
 
        /* When adding entries and set is full, try to resize the set */
-       int (*resize)(struct ip_set *set, uint8_t retried);
+       int (*resize)(struct ip_set *set, gfp_t gfp_flags, bool retried);
        /* Destroy the set */
        void (*destroy)(struct ip_set *set);
        /* Flush the elements */
        void (*flush)(struct ip_set *set);
-
+       /* Expire entries before listing */
+       void (*expire)(struct ip_set *set);
        /* List set header data */
        int (*head)(struct ip_set *set, struct sk_buff *skb);
        /* List elements */
        int (*list)(struct ip_set *set, struct sk_buff *skb,
                    struct netlink_callback *cb);
+
+       /* Return true if "b" set is the same as "a"
+        * according to the set parameters */
+       bool (*same_set)(const struct ip_set *a, const struct ip_set *b);
 };
 
 /* Flags for the set type variants */
 enum ip_set_type_flags {
-       IP_SET_FLAG_VMALLOC_BIT = 0,
-       IP_SET_FLAG_VMALLOC = (1 << IP_SET_FLAG_VMALLOC_BIT),
-       IP_SET_FLAG_TIMEOUT_BIT = 1,
-       IP_SET_FLAG_TIMEOUT = (1 << IP_SET_FLAG_TIMEOUT_BIT),
+       /* Set members created by kmalloc */
+       IP_SET_FLAG_KMALLOC_BIT = 0,
+       IP_SET_FLAG_KMALLOC = (1 << IP_SET_FLAG_KMALLOC_BIT),
 };
 
 /* The core set type structure */
@@ -278,17 +254,19 @@ struct ip_set_type {
        /* Typename */
        char name[IPSET_MAXNAMELEN];
        /* Protocol version */
-       uint8_t protocol;
+       u8 protocol;
        /* Set features to control swapping */
-       uint8_t features;
+       u8 features;
+       /* Set type dimension */
+       u8 dimension;
        /* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */
-       uint8_t family;
+       u8 family;
        /* Type revision */
-       uint8_t revision;
+       u8 revision;
 
        /* Create set */
        int (*create)(struct ip_set *set,
-                     struct nlattr *head, int len, uint32_t flags);
+                     struct nlattr *head, int len, u32 flags);
 
        /* Set this to THIS_MODULE if you are a module, otherwise NULL */
        struct module *me;
@@ -310,86 +288,90 @@ struct ip_set {
        /* The type variant doing the real job */
        const struct ip_set_type_variant *variant;
        /* The actual INET family */
-       uint8_t family;
+       u8 family;
        /* Set type flags, filled/modified by create/resize */
-       uint8_t flags;
+       u8 flags;
        /* The type specific data */
        void *data;
 };
 
 /* register and unregister set references */
-extern ip_set_id_t ip_set_get_byname(const char name[IPSET_MAXNAMELEN]);
+extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set);
 extern void ip_set_put_byindex(ip_set_id_t index);
+extern const char * ip_set_name_byindex(ip_set_id_t index);
+extern ip_set_id_t ip_set_nfnl_get(const char *name);
+extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index);
+extern void ip_set_nfnl_put(ip_set_id_t index);
 
 /* API for iptables set match, and SET target */
 extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb,
-                     uint8_t family, const uint8_t *flags);
+                     u8 family, u8 dim, u8 flags);
 extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb,
-                     uint8_t family, const uint8_t *flags);
+                     u8 family, u8 dim, u8 flags);
 extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
-                      uint8_t family, const uint8_t *flags);
+                      u8 family, u8 dim, u8 flags);
 
 /* Allocate members */
 static inline void *
-ip_set_alloc(size_t size, gfp_t gfp_mask, uint8_t *flags)
+ip_set_alloc(size_t size, gfp_t gfp_mask, u8 *flags)
 {
-       void *members = kzalloc(size, gfp_mask);
+       void *members = kzalloc(size, gfp_mask | __GFP_NOWARN);
        
        if (members) {
-               *flags &= ~IP_SET_FLAG_VMALLOC;
-               D("allocated with kmalloc %p", members);
+               *flags |= IP_SET_FLAG_KMALLOC;
+               pr_debug("%p: allocated with kmalloc", members);
                return members;
        }
        
        members = __vmalloc(size, gfp_mask | __GFP_ZERO, PAGE_KERNEL);
        if (!members)
                return NULL;
-       *flags |= IP_SET_FLAG_VMALLOC;
-       D("allocated with vmalloc %p", members);
+       *flags &= ~IP_SET_FLAG_KMALLOC;
+       pr_debug("%p: allocated with vmalloc", members);
        
        return members;
 }
 
 static inline void
-ip_set_free(void *members, uint8_t flags)
+ip_set_free(void *members, u8 flags)
 {
-       D("free with %s %p", flags & IP_SET_FLAG_VMALLOC ? "vmalloc" : "kmalloc",
-         members);
-       if (flags & IP_SET_FLAG_VMALLOC)
-               vfree(members);
-       else
+       pr_debug("%p: free with %s", members,
+                flags & IP_SET_FLAG_KMALLOC ? "kmalloc" : "vmalloc");
+       if (flags & IP_SET_FLAG_KMALLOC)
                kfree(members);
+       else
+               vfree(members);
 }
 
 /* Useful converters */
-static inline uint32_t
+static inline u32
 ip_set_get_h32(const struct nlattr *attr)
 {
-       uint32_t value = nla_get_u32(attr);
+       u32 value = nla_get_u32(attr);
        
        return attr->nla_type & NLA_F_NET_BYTEORDER ? ntohl(value) : value;
 }
 
-static inline uint16_t
+static inline u16
 ip_set_get_h16(const struct nlattr *attr)
 {
-       uint16_t value = nla_get_u16(attr);
+       u16 value = nla_get_u16(attr);
        
        return attr->nla_type & NLA_F_NET_BYTEORDER ? ntohs(value) : value;
 }
 
-static inline uint32_t
+static inline u32
 ip_set_get_n32(const struct nlattr *attr)
 {
-       uint32_t value = nla_get_u32(attr);
+       u32 value = nla_get_u32(attr);
        
        return attr->nla_type & NLA_F_NET_BYTEORDER ? value : htonl(value);
 }
 
-static inline uint16_t
+static inline u16
 ip_set_get_n16(const struct nlattr *attr)
 {
-       uint16_t value = nla_get_u16(attr);
+       u16 value = nla_get_u16(attr);
        
        return attr->nla_type & NLA_F_NET_BYTEORDER ? value : htons(value);
 }
@@ -404,31 +386,49 @@ ip_set_get_n16(const struct nlattr *attr)
        NLA_PUT_BE16(skb, type | NLA_F_NET_BYTEORDER, value)
 
 /* Get address from skbuff */
-static inline uint32_t
-ip4addr(const struct sk_buff *skb, const uint8_t *flags)
+static inline u32
+ip4addr(const struct sk_buff *skb, bool src)
 {
-       return flags[0] & IPSET_SRC ? ip_hdr(skb)->saddr
-                                   : ip_hdr(skb)->daddr;
+       return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr;
 }
 
 static inline void
-ip4addrptr(const struct sk_buff *skb, const uint8_t *flags, uint32_t *addr)
+ip4addrptr(const struct sk_buff *skb, bool src, u32 *addr)
 {
-       *addr = flags[0] & IPSET_SRC ? ip_hdr(skb)->saddr
-                                    : ip_hdr(skb)->daddr;
+       *addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr;
 }
 
 static inline void
-ip6addrptr(const struct sk_buff *skb, const uint8_t *flags,
-          struct in6_addr *addr)
+ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr)
 {
-       memcpy(addr, flags[0] & IPSET_SRC ? &ipv6_hdr(skb)->saddr
-                                         : &ipv6_hdr(skb)->daddr,
+       memcpy(addr, src ? &ipv6_hdr(skb)->saddr : &ipv6_hdr(skb)->daddr,
               sizeof(*addr));
 }
 
-#define pack_ip_port(map, ip, port) \
-       (port + ((ip - ((map)->first_ip)) << 16))
+/* Interface to iptables/ip6tables */
+
+#define SO_IP_SET              83
+
+union ip_set_name_index {
+       char name[IPSET_MAXNAMELEN];
+       ip_set_id_t index;
+};
+
+#define IP_SET_OP_GET_BYNAME   0x00000006      /* Get set index by name */
+struct ip_set_req_get_set {
+       unsigned op;
+       unsigned version;
+       union ip_set_name_index set;
+};
+
+#define IP_SET_OP_GET_BYINDEX  0x00000007      /* Get set name by index */
+/* Uses ip_set_req_get_set */
+
+#define IP_SET_OP_VERSION      0x00000100      /* Ask kernel version */
+struct ip_set_req_version {
+       unsigned op;
+       unsigned version;
+};
 
 #endif /* __KERNEL__ */
 
index 49d0f5c43e91790becca8ab48c3727a66ca5ad9a..0d067d050950c258b7ab4d28ca70c56a4a522b29 100644 (file)
@@ -12,10 +12,10 @@ enum {
 
 /* Common functions */
 
-static inline uint32_t
-range_to_mask(uint32_t from, uint32_t to, uint8_t *bits)
+static inline u32
+range_to_mask(u32 from, u32 to, u8 *bits)
 {
-       uint32_t mask = 0xFFFFFFFE;
+       u32 mask = 0xFFFFFFFE;
        
        *bits = 32;
        while (--(*bits) > 0 && mask && (to & mask) != from)
diff --git a/kernel/include/linux/netfilter/ip_set_chash.h b/kernel/include/linux/netfilter/ip_set_chash.h
new file mode 100644 (file)
index 0000000..0d77a5d
--- /dev/null
@@ -0,0 +1,1096 @@
+#ifndef _IP_SET_CHASH_H
+#define _IP_SET_CHASH_H
+
+#include <linux/netfilter/ip_set_jhash.h>
+#include <linux/netfilter/ip_set_slist.h>
+#include <linux/netfilter/ip_set_timeout.h>
+
+#define CONCAT(a, b, c)                a##b##c
+#define TOKEN(a, b, c)         CONCAT(a, b, c)
+
+/* Cache friendly hash with resizing when linear searching becomes too long.
+ * Internally jhash is used with the assumption that the size of the stored
+ * data is a multiple of sizeof(u32). If storage supports timeout, the
+ * timeout field must be the last one in the data structure.
+ */
+   
+/* Number of elements to store in an array block */
+#define CHASH_DEFAULT_ARRAY_SIZE        4
+/* Number of arrays: max ARRAY_SIZE * CHAIN_LIMIT "long" chains */
+#define CHASH_DEFAULT_CHAIN_LIMIT       3
+
+struct chash_nets {
+       u32 nets;               /* number of elements per cidr */
+       u8 cidr;                /* the cidr values added to the set */
+};
+
+struct chash {
+       struct slist *htable;   /* Hashtable of single linked lists */
+       u32 maxelem;            /* Max elements in the hash */
+       u32 elements;           /* Current element (vs timeout) */
+       u32 initval;            /* random jhash init value */
+       u32 timeout;            /* timeout value, if enabled */
+       struct timer_list gc;   /* garbage collection when timeout enabled */
+       u8 htable_bits;         /* size of hash table == 2^htable_bits */
+       u8 array_size;          /* number of elements in an array */
+       u8 chain_limit;         /* max number of arrays */
+#ifdef IP_SET_HASH_WITH_NETMASK
+       u8 netmask;             /* netmask value for subnets to store */
+#endif
+#ifdef IP_SET_HASH_WITH_NETS
+       struct chash_nets nets[0]; /* book keeping of networks */
+#endif
+};
+
+static inline u8
+htable_bits(u32 hashsize)
+{
+       /* Assume that hashsize == 2^htable_bits */
+       u8 bits = fls(hashsize - 1);
+       if (jhash_size(bits) != hashsize)
+               /* Round up to the first 2^n value */
+               bits = fls(hashsize);
+
+       return bits;
+}
+
+static inline void
+add_cidr(struct chash_nets *nets, u8 host_mask, u8 cidr)
+{
+       u8 i;
+
+       pr_debug("add_cidr %u", cidr);
+       for (i = 0; i < host_mask - 1 && nets[i].cidr; i++) {
+               /* Add in increasing prefix order, so larger cidr first */
+               if (nets[i].cidr < cidr)
+                       swap(nets[i].cidr, cidr);
+       }
+       if (i < host_mask - 1)
+               nets[i].cidr = cidr;
+}
+
+static inline void
+del_cidr(struct chash_nets *nets, u8 host_mask, u8 cidr)
+{
+       u8 i;
+
+       pr_debug("del_cidr %u", cidr);
+       for (i = 0; i < host_mask - 2 && nets[i].cidr; i++) {
+               if (nets[i].cidr == cidr)
+                       nets[i].cidr = cidr = nets[i+1].cidr;
+       }
+       nets[host_mask - 2].cidr = 0;
+}
+
+static void
+chash_destroy(struct slist *t, u8 htable_bits, u8 flags)
+{
+       struct slist *n, *tmp;
+       u32 i;
+       
+       for (i = 0; i < jhash_size(htable_bits); i++)
+               slist_for_each_safe(n, tmp, &t[i])
+                       /* FIXME: slab cache */
+                       kfree(n);
+
+       ip_set_free(t, flags);
+}
+
+static size_t
+chash_memsize(const struct chash *h, size_t dsize, u8 host_mask)
+{
+       struct slist *n;
+       u32 i;
+       size_t memsize = sizeof(*h)
+#ifdef IP_SET_HASH_WITH_NETS
+                        + sizeof(struct chash_nets) * (host_mask - 1)
+#endif
+                        + jhash_size(h->htable_bits) * sizeof(struct slist);
+       
+       for (i = 0; i < jhash_size(h->htable_bits); i++)
+               slist_for_each(n, &h->htable[i])
+                       memsize += sizeof(struct slist)
+                               + h->array_size * dsize;
+       
+       return memsize;
+}
+
+static void
+ip_set_hash_flush(struct ip_set *set)
+{
+       struct chash *h = set->data;
+       struct slist *n, *tmp;
+       u32 i;
+       
+       for (i = 0; i < jhash_size(h->htable_bits); i++) {
+               slist_for_each_safe(n, tmp, &h->htable[i])
+                       /* FIXME: slab cache */
+                       kfree(n);
+               h->htable[i].next = NULL;
+       }
+#ifdef IP_SET_HASH_WITH_NETS
+       memset(h->nets, 0, sizeof(struct chash_nets)
+                          * (set->family == AF_INET ? 31 : 127));
+#endif
+       h->elements = 0;
+}
+
+static void
+ip_set_hash_destroy(struct ip_set *set)
+{
+       struct chash *h = set->data;
+
+       if (with_timeout(h->timeout))
+               del_timer_sync(&h->gc);
+
+       chash_destroy(h->htable, h->htable_bits, set->flags);
+       kfree(h);
+       
+       set->data = NULL;
+}
+
+#define JHASH2(data, initval, htable_bits)                             \
+jhash2((u32 *)(data), sizeof(struct type_pf_elem)/sizeof(u32), initval)        \
+       & jhash_mask(htable_bits)
+
+#endif /* _IP_SET_CHASH_H */
+
+/* Type/family dependent function prototypes */
+
+#define type_pf_data_equal     TOKEN(TYPE, PF, _data_equal)
+#define type_pf_data_isnull    TOKEN(TYPE, PF, _data_isnull)
+#define type_pf_data_copy      TOKEN(TYPE, PF, _data_copy)
+#define type_pf_data_swap      TOKEN(TYPE, PF, _data_swap)
+#define type_pf_data_zero_out  TOKEN(TYPE, PF, _data_zero_out)
+#define type_pf_data_netmask   TOKEN(TYPE, PF, _data_netmask)
+#define type_pf_data_list      TOKEN(TYPE, PF, _data_list)
+#define type_pf_data_tlist     TOKEN(TYPE, PF, _data_tlist)
+
+#define type_pf_elem           TOKEN(TYPE, PF, _elem)
+#define type_pf_telem          TOKEN(TYPE, PF, _telem)
+#define type_pf_data_timeout   TOKEN(TYPE, PF, _data_timeout)
+#define type_pf_data_expired   TOKEN(TYPE, PF, _data_expired)
+#define type_pf_data_swap_timeout TOKEN(TYPE, PF, _data_swap_timeout)
+#define type_pf_data_timeout_set TOKEN(TYPE, PF, _data_timeout_set)
+
+#define type_pf_chash_readd    TOKEN(TYPE, PF, _chash_readd)
+#define type_pf_chash_del_elem TOKEN(TYPE, PF, _chash_del_elem)
+#define type_pf_chash_add      TOKEN(TYPE, PF, _chash_add)
+#define type_pf_chash_del      TOKEN(TYPE, PF, _chash_del)
+#define type_pf_chash_test_cidrs TOKEN(TYPE, PF, _chash_test_cidrs)
+#define type_pf_chash_test     TOKEN(TYPE, PF, _chash_test)
+
+#define type_pf_chash_treadd   TOKEN(TYPE, PF, _chash_treadd)
+#define type_pf_chash_del_telem        TOKEN(TYPE, PF, _chash_del_telem)
+#define type_pf_chash_expire   TOKEN(TYPE, PF, _chash_expire)
+#define type_pf_chash_tadd     TOKEN(TYPE, PF, _chash_tadd)
+#define type_pf_chash_tdel     TOKEN(TYPE, PF, _chash_tdel)
+#define type_pf_chash_ttest_cidrs TOKEN(TYPE, PF, _chash_ttest_cidrs)
+#define type_pf_chash_ttest    TOKEN(TYPE, PF, _chash_ttest)
+
+#define type_pf_resize         TOKEN(TYPE, PF, _resize)
+#define type_pf_tresize                TOKEN(TYPE, PF, _tresize)
+#define type_pf_flush          ip_set_hash_flush
+#define type_pf_destroy                ip_set_hash_destroy
+#define type_pf_head           TOKEN(TYPE, PF, _head)
+#define type_pf_list           TOKEN(TYPE, PF, _list)
+#define type_pf_tlist          TOKEN(TYPE, PF, _tlist)
+#define type_pf_same_set       TOKEN(TYPE, PF, _same_set)
+#define type_pf_kadt           TOKEN(TYPE, PF, _kadt)
+#define type_pf_uadt           TOKEN(TYPE, PF, _uadt)
+#define type_pf_gc             TOKEN(TYPE, PF, _gc)
+#define type_pf_gc_init                TOKEN(TYPE, PF, _gc_init)
+#define type_pf_variant                TOKEN(TYPE, PF, _variant)
+#define type_pf_tvariant       TOKEN(TYPE, PF, _tvariant)
+
+/* Flavour without timeout */
+
+#define chash_data(n, i) \
+(struct type_pf_elem *)((char *)(n) + sizeof(struct slist) + (i)*sizeof(struct type_pf_elem))
+
+static int
+type_pf_chash_readd(struct chash *h, struct slist *t, u8 htable_bits,
+                   const struct type_pf_elem *value, gfp_t gfp_flags)
+{
+       struct slist *n, *prev;
+       struct type_pf_elem *data;
+       void *tmp;
+       int i = 0, j = 0;
+       u32 hash = JHASH2(value, h->initval, htable_bits);
+
+       slist_for_each_prev(prev, n, &t[hash]) {
+               for (i = 0; i < h->array_size; i++) {
+                       data = chash_data(n, i);
+                       if (type_pf_data_isnull(data)) {
+                               tmp = n;
+                               goto found;
+                       }
+               }
+               j++;
+       }
+       if (j < h->chain_limit) {
+               tmp = kzalloc(h->array_size * sizeof(struct type_pf_elem)
+                             + sizeof(struct slist), gfp_flags);
+               if (!tmp)
+                       return -ENOMEM;
+               prev->next = (struct slist *) tmp;
+               data = chash_data(tmp, 0);
+       } else {
+               /* Rehashing */
+               return -EAGAIN;
+       }
+found:
+       type_pf_data_copy(data, value);
+       return 0;
+}
+
+static void
+type_pf_chash_del_elem(struct chash *h, struct slist *prev,
+                      struct slist *n, int i)
+{
+       struct type_pf_elem *data = chash_data(n, i);
+       struct slist *tmp;
+       int j;
+
+       if (n->next != NULL) {
+               for (prev = n, tmp = n->next;
+                    tmp->next != NULL;
+                    prev = tmp, tmp = tmp->next)
+                       /* Find last array */;
+               j = 0;
+       } else {
+               /* Already at last array */
+               tmp = n;
+               j = i;
+       }
+       /* Find last non-empty element */
+       for (; j < h->array_size - 1; j++)
+               if (type_pf_data_isnull(chash_data(tmp, j + 1)))
+                       break;
+
+       if (!(tmp == n && i == j)) {
+               type_pf_data_swap(data, chash_data(tmp, j));
+       }
+#ifdef IP_SET_HASH_WITH_NETS
+       if (--h->nets[data->cidr-1].nets == 0)
+               del_cidr(h->nets, HOST_MASK, data->cidr);
+#endif
+       if (j == 0) {
+               prev->next = NULL;
+               kfree(tmp);
+       } else
+               type_pf_data_zero_out(chash_data(tmp, j));
+
+       h->elements--;
+}
+
+static int
+type_pf_resize(struct ip_set *set, gfp_t gfp_flags, bool retried)
+{
+       struct chash *h = set->data;
+       u8 htable_bits = h->htable_bits;
+       struct slist *t, *n;
+       const struct type_pf_elem *data;
+       u32 i, j;
+       u8 oflags, flags;
+       int ret;
+
+retry:
+       ret = 0;
+       htable_bits++;
+       if (!htable_bits)
+               /* In case we have plenty of memory :-) */
+               return -IPSET_ERR_HASH_FULL;
+       t = ip_set_alloc(jhash_size(htable_bits) * sizeof(struct slist),
+                        gfp_flags, &flags);
+       if (!t)
+               return -ENOMEM;
+
+       write_lock_bh(&set->lock);
+       flags = oflags = set->flags;
+       for (i = 0; i < jhash_size(h->htable_bits); i++) {
+next_slot:
+               slist_for_each(n, &h->htable[i]) {
+                       for (j = 0; j < h->array_size; j++) {
+                               data = chash_data(n, j);
+                               if (type_pf_data_isnull(data)) {
+                                       i++;
+                                       goto next_slot;
+                               }
+                               ret = type_pf_chash_readd(h, t, htable_bits,
+                                                         data, gfp_flags);
+                               if (ret < 0) {
+                                       write_unlock_bh(&set->lock);
+                                       chash_destroy(t, htable_bits, flags);
+                                       if (ret == -EAGAIN)
+                                               goto retry;
+                                       return ret;
+                               }
+                       }
+               }
+       }
+
+       n = h->htable;
+       i = h->htable_bits;
+       
+       h->htable = t;
+       h->htable_bits = htable_bits;
+       set->flags = flags;
+       write_unlock_bh(&set->lock);
+
+       chash_destroy(n, i, oflags);
+       
+       return 0;
+}
+
+static int
+type_pf_chash_add(struct ip_set *set, void *value,
+                 gfp_t gfp_flags, u32 timeout)
+{
+       struct chash *h = set->data;
+       const struct type_pf_elem *d = value;
+       struct slist *n, *prev, *t = h->htable;
+       struct type_pf_elem *data;
+       void *tmp;
+       int i = 0, j = 0;
+       u32 hash;
+
+#ifdef IP_SET_HASH_WITH_NETS
+       if (h->elements >= h->maxelem || h->nets[d->cidr-1].nets == UINT_MAX)
+#else
+       if (h->elements >= h->maxelem)
+#endif
+               return -IPSET_ERR_HASH_FULL;
+
+       hash = JHASH2(value, h->initval, h->htable_bits);
+       slist_for_each_prev(prev, n, &t[hash]) {
+               for (i = 0; i < h->array_size; i++) {
+                       data = chash_data(n, i);
+                       if (type_pf_data_isnull(data)) {
+                               tmp = n;
+                               goto found;
+                       }
+                       if (type_pf_data_equal(data, d))
+                               return -IPSET_ERR_EXIST;
+               }
+               j++;
+       }
+       if (j < h->chain_limit) {
+               tmp = kzalloc(h->array_size * sizeof(struct type_pf_elem)
+                             + sizeof(struct slist), gfp_flags);
+               if (!tmp)
+                       return -ENOMEM;
+               prev->next = (struct slist *) tmp;
+               data = chash_data(tmp, 0);
+       } else {
+               /* Rehashing */
+               return -EAGAIN;
+       }
+found:
+       type_pf_data_copy(data, d);
+#ifdef IP_SET_HASH_WITH_NETS
+       if (h->nets[d->cidr-1].nets++ == 0)
+               add_cidr(h->nets, HOST_MASK, d->cidr);
+#endif
+       h->elements++;
+       return 0;
+}
+
+static int
+type_pf_chash_del(struct ip_set *set, void *value,
+                 gfp_t gfp_flags, u32 timeout)
+{
+       struct chash *h = set->data;
+       const struct type_pf_elem *d = value;
+       struct slist *n, *prev;
+       int i;
+       struct type_pf_elem *data;
+       u32 hash = JHASH2(value, h->initval, h->htable_bits);
+
+       slist_for_each_prev(prev, n, &h->htable[hash])
+               for (i = 0; i < h->array_size; i++) {
+                       data = chash_data(n, i);
+                       if (type_pf_data_isnull(data))
+                               return -IPSET_ERR_EXIST;
+                       if (type_pf_data_equal(data, d)) {
+                               type_pf_chash_del_elem(h, prev, n, i);
+                               return 0;
+                       }
+               }
+
+       return -IPSET_ERR_EXIST;
+}
+
+#ifdef IP_SET_HASH_WITH_NETS
+static inline int
+type_pf_chash_test_cidrs(struct ip_set *set,
+                        struct type_pf_elem *d,
+                        gfp_t gfp_flags, u32 timeout)
+{
+       struct chash *h = set->data;
+       struct slist *n;
+       const struct type_pf_elem *data;
+       int i, j = 0;
+       u32 hash;
+       u8 host_mask = set->family == AF_INET ? 32 : 128;
+
+retry:
+       pr_debug("test by nets");
+       for (; j < host_mask - 1 && h->nets[j].cidr; j++) {
+               type_pf_data_netmask(d, h->nets[j].cidr);
+               hash = JHASH2(d, h->initval, h->htable_bits);
+               slist_for_each(n, &h->htable[hash])
+                       for (i = 0; i < h->array_size; i++) {
+                               data = chash_data(n, i);
+                               if (type_pf_data_isnull(data)) {
+                                       j++;
+                                       goto retry;
+                               }
+                               if (type_pf_data_equal(data, d))
+                                       return 1;
+                       }
+       }
+       return 0;
+}
+#endif
+
+static inline int
+type_pf_chash_test(struct ip_set *set, void *value,
+                  gfp_t gfp_flags, u32 timeout)
+{
+       struct chash *h = set->data;
+       struct type_pf_elem *d = value;
+       struct slist *n;
+       const struct type_pf_elem *data;
+       int i;
+       u32 hash;
+#ifdef IP_SET_HASH_WITH_NETS
+       u8 host_mask = set->family == AF_INET ? 32 : 128;
+
+       if (d->cidr == host_mask)
+               return type_pf_chash_test_cidrs(set, d, gfp_flags, timeout);
+#endif
+
+       hash = JHASH2(d, h->initval, h->htable_bits);
+       slist_for_each(n, &h->htable[hash])
+               for (i = 0; i < h->array_size; i++) {
+                       data = chash_data(n, i);
+                       if (type_pf_data_isnull(data))
+                               return 0;
+                       if (type_pf_data_equal(data, d))
+                               return 1;
+               }
+       return 0;
+}
+
+static int
+type_pf_head(struct ip_set *set, struct sk_buff *skb)
+{
+       const struct chash *h = set->data;
+       struct nlattr *nested;
+       size_t memsize;
+       
+       read_lock_bh(&set->lock);
+       memsize = chash_memsize(h, with_timeout(h->timeout)
+                                       ? sizeof(struct type_pf_telem)
+                                       : sizeof(struct type_pf_elem),
+                               set->family == AF_INET ? 32 : 128);
+       read_unlock_bh(&set->lock);
+
+       nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+       if (!nested)
+               goto nla_put_failure;
+       NLA_PUT_NET32(skb, IPSET_ATTR_HASHSIZE,
+                     htonl(jhash_size(h->htable_bits)));
+       NLA_PUT_NET32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem));
+#ifdef IP_SET_HASH_WITH_NETMASK
+       if (h->netmask != HOST_MASK)
+               NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask);
+#endif
+       NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
+                     htonl(atomic_read(&set->ref) - 1));
+       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize));
+       if (with_timeout(h->timeout))
+               NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout));
+       ipset_nest_end(skb, nested);
+       
+       return 0;
+nla_put_failure:
+       return -EFAULT;
+}
+
+static int
+type_pf_list(struct ip_set *set,
+            struct sk_buff *skb, struct netlink_callback *cb)
+{
+       const struct chash *h = set->data;
+       struct nlattr *atd, *nested;
+       struct slist *n;
+       const struct type_pf_elem *data;
+       u32 first = cb->args[2];
+       int i;
+
+       atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
+       if (!atd)
+               return -EFAULT;
+       pr_debug("list hash set %s", set->name);
+       for (; cb->args[2] < jhash_size(h->htable_bits); cb->args[2]++) {
+               slist_for_each(n, &h->htable[cb->args[2]]) {
+                       for (i = 0; i < h->array_size; i++) {
+                               data = chash_data(n, i);
+                               if (type_pf_data_isnull(data))
+                                       break;
+                               pr_debug("list hash %lu slist %p i %u",
+                                        cb->args[2], n, i);
+                               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+                               if (!nested) {
+                                       if (cb->args[2] == first) {
+                                               nla_nest_cancel(skb, atd);
+                                               return -EFAULT;
+                                       } else
+                                               goto nla_put_failure;
+                               }
+                               if (type_pf_data_list(skb, data))
+                                       goto nla_put_failure;
+                               ipset_nest_end(skb, nested);
+                       }
+               }
+       }
+       ipset_nest_end(skb, atd);
+       /* Set listing finished */
+       cb->args[2] = 0;
+       
+       return 0;
+
+nla_put_failure:
+       nla_nest_cancel(skb, nested);
+       ipset_nest_end(skb, atd);
+       return 0;
+}
+
+static int
+type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
+            enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
+static int
+type_pf_uadt(struct ip_set *set, struct nlattr *head, int len,
+            enum ipset_adt adt, u32 *lineno, u32 flags);
+
+static const struct ip_set_type_variant type_pf_variant __read_mostly = {
+       .kadt   = type_pf_kadt,
+       .uadt   = type_pf_uadt,
+       .adt    = {
+               [IPSET_ADD] = type_pf_chash_add,
+               [IPSET_DEL] = type_pf_chash_del,
+               [IPSET_TEST] = type_pf_chash_test,
+       },
+       .destroy = type_pf_destroy,
+       .flush  = type_pf_flush,
+       .head   = type_pf_head,
+       .list   = type_pf_list,
+       .resize = type_pf_resize,
+       .same_set = type_pf_same_set,
+};
+
+/* Flavour with timeout support */
+
+#define chash_tdata(n, i) \
+(struct type_pf_elem *)((char *)(n) + sizeof(struct slist) + (i)*sizeof(struct type_pf_telem))
+
+static inline u32
+type_pf_data_timeout(const struct type_pf_elem *data)
+{
+       const struct type_pf_telem *tdata =
+               (const struct type_pf_telem *) data;
+
+       return tdata->timeout;
+}
+
+static inline bool
+type_pf_data_expired(const struct type_pf_elem *data)
+{
+       const struct type_pf_telem *tdata =
+               (const struct type_pf_telem *) data;
+
+       return ip_set_timeout_expired(tdata->timeout);
+}
+
+static inline void
+type_pf_data_swap_timeout(struct type_pf_elem *src,
+                         struct type_pf_elem *dst)
+{
+       struct type_pf_telem *x = (struct type_pf_telem *) src;
+       struct type_pf_telem *y = (struct type_pf_telem *) dst;
+
+       swap(x->timeout, y->timeout);
+}
+
+static inline void
+type_pf_data_timeout_set(struct type_pf_elem *data, u32 timeout)
+{
+       struct type_pf_telem *tdata = (struct type_pf_telem *) data;
+
+       tdata->timeout = ip_set_timeout_set(timeout);
+}
+
+static int
+type_pf_chash_treadd(struct chash *h, struct slist *t, u8 htable_bits,
+                    const struct type_pf_elem *value,
+                    gfp_t gfp_flags, u32 timeout)
+{
+       struct slist *n, *prev;
+       struct type_pf_elem *data;
+       void *tmp;
+       int i = 0, j = 0;
+       u32 hash = JHASH2(value, h->initval, htable_bits);
+
+       slist_for_each_prev(prev, n, &t[hash]) {
+               for (i = 0; i < h->array_size; i++) {
+                       data = chash_tdata(n, i);
+                       if (type_pf_data_isnull(data)) {
+                               tmp = n;
+                               goto found;
+                       }
+               }
+               j++;
+       }
+       if (j < h->chain_limit) {
+               tmp = kzalloc(h->array_size * sizeof(struct type_pf_telem)
+                             + sizeof(struct slist), gfp_flags);
+               if (!tmp)
+                       return -ENOMEM;
+               prev->next = (struct slist *) tmp;
+               data = chash_tdata(tmp, 0);
+       } else {
+               /* Rehashing */
+               return -EAGAIN;
+       }
+found:
+       type_pf_data_copy(data, value);
+       type_pf_data_timeout_set(data, timeout);
+       return 0;
+}
+
+static void
+type_pf_chash_del_telem(struct chash *h, struct slist *prev,
+                       struct slist *n, int i)
+{
+       struct type_pf_elem *d, *data = chash_tdata(n, i);
+       struct slist *tmp;
+       int j;
+
+       pr_debug("del %u", i);
+       if (n->next != NULL) {
+               for (prev = n, tmp = n->next;
+                    tmp->next != NULL;
+                    prev = tmp, tmp = tmp->next)
+                       /* Find last array */;
+               j = 0;
+       } else {
+               /* Already at last array */
+               tmp = n;
+               j = i;
+       }
+       /* Find last non-empty element */
+       for (; j < h->array_size - 1; j++)
+               if (type_pf_data_isnull(chash_tdata(tmp, j + 1)))
+                       break;
+
+       d = chash_tdata(tmp, j);
+       if (!(tmp == n && i == j)) {
+               type_pf_data_swap(data, d);
+               type_pf_data_swap_timeout(data, d);
+       }
+#ifdef IP_SET_HASH_WITH_NETS
+       if (--h->nets[data->cidr-1].nets == 0)
+               del_cidr(h->nets, HOST_MASK, data->cidr);
+#endif
+       if (j == 0) {
+               prev->next = NULL;
+               kfree(tmp);
+       } else
+               type_pf_data_zero_out(d);
+
+       h->elements--;
+}
+
+static void
+type_pf_chash_expire(struct chash *h)
+{
+       struct slist *n, *prev;
+       struct type_pf_elem *data;
+       u32 i;
+       int j;
+       
+       for (i = 0; i < jhash_size(h->htable_bits); i++)
+               slist_for_each_prev(prev, n, &h->htable[i])
+                       for (j = 0; j < h->array_size; j++) {
+                               data = chash_tdata(n, j);
+                               if (type_pf_data_isnull(data))
+                                       break;
+                               if (type_pf_data_expired(data)) {
+                                       pr_debug("expire %u/%u", i, j);
+                                       type_pf_chash_del_telem(h, prev, n, j);
+                               }
+                       }
+}
+
+static int
+type_pf_tresize(struct ip_set *set, gfp_t gfp_flags, bool retried)
+{
+       struct chash *h = set->data;
+       u8 htable_bits = h->htable_bits;
+       struct slist *t, *n;
+       const struct type_pf_elem *data;
+       u32 i, j;
+       u8 oflags, flags;
+       int ret;
+
+       /* Try to cleanup once */
+       if (!retried) {
+               i = h->elements;
+               write_lock_bh(&set->lock);
+               type_pf_chash_expire(set->data);
+               write_unlock_bh(&set->lock);
+               if (h->elements <  i)
+                       return 0;
+       }
+
+retry:
+       ret = 0;
+       htable_bits++;
+       if (!htable_bits)
+               /* In case we have plenty of memory :-) */
+               return -IPSET_ERR_HASH_FULL;
+       t = ip_set_alloc(jhash_size(htable_bits) * sizeof(struct slist),
+                        gfp_flags, &flags);
+       if (!t)
+               return -ENOMEM;
+
+       write_lock_bh(&set->lock);
+       flags = oflags = set->flags;
+       for (i = 0; i < jhash_size(h->htable_bits); i++) {
+next_slot:
+               slist_for_each(n, &h->htable[i]) {
+                       for (j = 0; j < h->array_size; j++) {
+                               data = chash_tdata(n, j);
+                               if (type_pf_data_isnull(data)) {
+                                       i++;
+                                       goto next_slot;
+                               }
+                               ret = type_pf_chash_treadd(h, t, htable_bits,
+                                                          data, gfp_flags,
+                                                          type_pf_data_timeout(data));
+                               if (ret < 0) {
+                                       write_unlock_bh(&set->lock);
+                                       chash_destroy(t, htable_bits, flags);
+                                       if (ret == -EAGAIN)
+                                               goto retry;
+                                       return ret;
+                               }
+                       }
+               }
+       }
+
+       n = h->htable;
+       i = h->htable_bits;
+       
+       h->htable = t;
+       h->htable_bits = htable_bits;
+       set->flags = flags;
+       write_unlock_bh(&set->lock);
+
+       chash_destroy(n, i, oflags);
+       
+       return 0;
+}
+
+static int
+type_pf_chash_tadd(struct ip_set *set, void *value,
+                  gfp_t gfp_flags, u32 timeout)
+{      
+       struct chash *h = set->data;
+       const struct type_pf_elem *d = value;
+       struct slist *n, *prev, *t = h->htable;
+       struct type_pf_elem *data;
+       void *tmp;
+       int i = 0, j = 0;
+       u32 hash;
+
+       if (h->elements >= h->maxelem)
+               /* FIXME: when set is full, we slow down here */
+               type_pf_chash_expire(h);
+#ifdef IP_SET_HASH_WITH_NETS
+       if (h->elements >= h->maxelem || h->nets[d->cidr-1].nets == UINT_MAX)
+#else
+       if (h->elements >= h->maxelem)
+#endif
+               return -IPSET_ERR_HASH_FULL;
+
+       hash = JHASH2(d, h->initval, h->htable_bits);
+       slist_for_each_prev(prev, n, &t[hash]) {
+               for (i = 0; i < h->array_size; i++) {
+                       data = chash_tdata(n, i);
+                       if (type_pf_data_isnull(data)
+                           || type_pf_data_expired(data)) {
+                               tmp = n;
+                               goto found;
+                       }
+                       if (type_pf_data_equal(data, d))
+                               return -IPSET_ERR_EXIST;
+               }
+               j++;
+       }
+       if (j < h->chain_limit) {
+               tmp = kzalloc(h->array_size * sizeof(struct type_pf_telem)
+                             + sizeof(struct slist), gfp_flags);
+               if (!tmp)
+                       return -ENOMEM;
+               prev->next = (struct slist *) tmp;
+               data = chash_tdata(tmp, 0);
+       } else {
+               /* Rehashing */
+               return -EAGAIN;
+       }
+found:
+       if (type_pf_data_isnull(data)) {
+               h->elements++;
+#ifdef IP_SET_HASH_WITH_NETS
+       } else {
+               if (--h->nets[data->cidr-1].nets == 0)
+                       del_cidr(h->nets, HOST_MASK, data->cidr);
+       }
+       if (h->nets[d->cidr-1].nets++ == 0) {
+               add_cidr(h->nets, HOST_MASK, d->cidr);
+#endif
+       }
+       type_pf_data_copy(data, d);
+       type_pf_data_timeout_set(data, timeout);
+       return 0;
+}
+
+static int
+type_pf_chash_tdel(struct ip_set *set, void *value,
+                  gfp_t gfp_flags, u32 timeout)
+{
+       struct chash *h = set->data;
+       const struct type_pf_elem *d = value;
+       struct slist *n, *prev;
+       int i, ret = 0;
+       struct type_pf_elem *data;
+       u32 hash = JHASH2(value, h->initval, h->htable_bits);
+
+       slist_for_each_prev(prev, n, &h->htable[hash])
+               for (i = 0; i < h->array_size; i++) {
+                       data = chash_tdata(n, i);
+                       if (type_pf_data_isnull(data))
+                               return -IPSET_ERR_EXIST;
+                       if (type_pf_data_equal(data, d)) {
+                               if (type_pf_data_expired(data))
+                                       ret = -IPSET_ERR_EXIST;
+                               type_pf_chash_del_telem(h, prev, n, i);
+                               return ret;
+                       }
+               }
+
+       return -IPSET_ERR_EXIST;
+}
+
+#ifdef IP_SET_HASH_WITH_NETS
+static inline int
+type_pf_chash_ttest_cidrs(struct ip_set *set,
+                         struct type_pf_elem *d,
+                         gfp_t gfp_flags, u32 timeout)
+{
+       struct chash *h = set->data;
+       struct type_pf_elem *data;
+       struct slist *n;
+       int i, j = 0;
+       u32 hash;
+       u8 host_mask = set->family == AF_INET ? 32 : 128;
+
+retry:
+       for (; j < host_mask - 1 && h->nets[j].cidr; j++) {
+               type_pf_data_netmask(d, h->nets[j].cidr);
+               hash = JHASH2(d, h->initval, h->htable_bits);
+               slist_for_each(n, &h->htable[hash])
+                       for (i = 0; i < h->array_size; i++) {
+                               data = chash_tdata(n, i);
+                               if (type_pf_data_isnull(data)) {
+                                       j++;
+                                       goto retry;
+                               }
+                               if (type_pf_data_equal(data, d))
+                                       return !type_pf_data_expired(data);
+                       }
+       }
+       return 0;
+}
+#endif
+
+static inline int
+type_pf_chash_ttest(struct ip_set *set, void *value,
+                   gfp_t gfp_flags, u32 timeout)
+{
+       struct chash *h = set->data;
+       struct type_pf_elem *data, *d = value;
+       struct slist *n;
+       int i;
+       u32 hash;
+#ifdef IP_SET_HASH_WITH_NETS
+       u8 host_mask = set->family == AF_INET ? 32 : 128;
+
+       if (d->cidr == host_mask)
+               return type_pf_chash_ttest_cidrs(set, d, gfp_flags,
+                                                timeout);
+#endif
+       hash = JHASH2(d, h->initval, h->htable_bits);
+       slist_for_each(n, &h->htable[hash])
+               for (i = 0; i < h->array_size; i++) {
+                       data = chash_tdata(n, i);
+                       if (type_pf_data_isnull(data))
+                               return 0;
+                       if (type_pf_data_equal(data, d))
+                               return !type_pf_data_expired(data);
+               }
+       return 0;
+}
+
+static int
+type_pf_tlist(struct ip_set *set,
+             struct sk_buff *skb, struct netlink_callback *cb)
+{
+       const struct chash *h = set->data;
+       struct nlattr *atd, *nested;
+       struct slist *n;
+       const struct type_pf_elem *data;
+       u32 first = cb->args[2];
+       int i;
+
+       atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
+       if (!atd)
+               return -EFAULT;
+       for (; cb->args[2] < jhash_size(h->htable_bits); cb->args[2]++) {
+               slist_for_each(n, &h->htable[cb->args[2]]) {
+                       for (i = 0; i < h->array_size; i++) {
+                               data = chash_tdata(n, i);
+                               pr_debug("list %p %u", n, i);
+                               if (type_pf_data_isnull(data))
+                                       break;
+                               if (type_pf_data_expired(data))
+                                       continue;
+                               pr_debug("do list %p %u", n, i);
+                               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+                               if (!nested) {
+                                       if (cb->args[2] == first) {
+                                               nla_nest_cancel(skb, atd);
+                                               return -EFAULT;
+                                       } else
+                                               goto nla_put_failure;
+                               }
+                               if (type_pf_data_tlist(skb, data))
+                                       goto nla_put_failure;
+                               ipset_nest_end(skb, nested);
+                       }
+               }
+       }
+       ipset_nest_end(skb, atd);
+       /* Set listing finished */
+       cb->args[2] = 0;
+       
+       return 0;
+
+nla_put_failure:
+       nla_nest_cancel(skb, nested);
+       ipset_nest_end(skb, atd);
+       return 0;
+}
+
+static const struct ip_set_type_variant type_pf_tvariant __read_mostly = {
+       .kadt   = type_pf_kadt,
+       .uadt   = type_pf_uadt,
+       .adt    = {
+               [IPSET_ADD] = type_pf_chash_tadd,
+               [IPSET_DEL] = type_pf_chash_tdel,
+               [IPSET_TEST] = type_pf_chash_ttest,
+       },
+       .destroy = type_pf_destroy,
+       .flush  = type_pf_flush,
+       .head   = type_pf_head,
+       .list   = type_pf_tlist,
+       .resize = type_pf_tresize,
+       .same_set = type_pf_same_set,
+};
+
+static void
+type_pf_gc(unsigned long ul_set)
+{
+       struct ip_set *set = (struct ip_set *) ul_set;
+       struct chash *h = set->data;
+
+       pr_debug("called");
+       write_lock_bh(&set->lock);
+       type_pf_chash_expire(h);
+       write_unlock_bh(&set->lock);
+
+       h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
+       add_timer(&h->gc);
+}
+
+static inline void
+type_pf_gc_init(struct ip_set *set)
+{
+       struct chash *h = set->data;
+       
+       init_timer(&h->gc);
+       h->gc.data = (unsigned long) set;
+       h->gc.function = type_pf_gc;
+       h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
+       add_timer(&h->gc);
+       pr_debug("gc initialized, run in every %u", IPSET_GC_PERIOD(h->timeout));
+}
+
+#undef type_pf_data_equal
+#undef type_pf_data_isnull
+#undef type_pf_data_copy
+#undef type_pf_data_swap
+#undef type_pf_data_zero_out
+#undef type_pf_data_list
+#undef type_pf_data_tlist
+
+#undef type_pf_elem
+#undef type_pf_telem
+#undef type_pf_data_timeout
+#undef type_pf_data_expired
+#undef type_pf_data_swap_timeout
+#undef type_pf_data_netmask
+#undef type_pf_data_timeout_set
+
+#undef type_pf_chash_readd
+#undef type_pf_chash_del_elem
+#undef type_pf_chash_add
+#undef type_pf_chash_del
+#undef type_pf_chash_test_cidrs
+#undef type_pf_chash_test
+
+#undef type_pf_chash_treadd
+#undef type_pf_chash_del_telem
+#undef type_pf_chash_expire
+#undef type_pf_chash_tadd
+#undef type_pf_chash_tdel
+#undef type_pf_chash_ttest_cidrs
+#undef type_pf_chash_ttest
+
+#undef type_pf_resize
+#undef type_pf_tresize
+#undef type_pf_flush
+#undef type_pf_destroy
+#undef type_pf_head
+#undef type_pf_list
+#undef type_pf_tlist
+#undef type_pf_same_set
+#undef type_pf_kadt
+#undef type_pf_uadt
+#undef type_pf_gc
+#undef type_pf_gc_init
+#undef type_pf_variant
+#undef type_pf_tvariant
index 855f12a281549db80366ea5aba444c514a95f7df..ffa89f115eea7faa5b4380ff5dc398dbfe62b133 100644 (file)
@@ -8,8 +8,8 @@
 #define IPSET_INVALID_PORT     65536
 
 /* We must handle non-linear skbs */
-static uint32_t
-get_port(uint8_t pf, const struct sk_buff *skb, const uint8_t *flags)
+static bool
+get_port(u8 pf, const struct sk_buff *skb, bool src, u16 *port)
 {
        unsigned short protocol;
        unsigned int protoff;
@@ -30,19 +30,19 @@ get_port(uint8_t pf, const struct sk_buff *skb, const uint8_t *flags)
                
                protohdr = ipv6_find_hdr(skb, &protoff, -1, &frag_off);
                if (protohdr < 0)
-                       return IPSET_INVALID_PORT;
+                       return false;
 
                protocol = protohdr;
                fragoff = frag_off;
                break;
        }
        default:
-               return IPSET_INVALID_PORT;
+               return false;
        }
 
        /* See comments at tcp_match in ip_tables.c */
        if (fragoff)
-               return IPSET_INVALID_PORT;
+               return false;
 
        switch (protocol) {
        case IPPROTO_TCP: {
@@ -52,9 +52,10 @@ get_port(uint8_t pf, const struct sk_buff *skb, const uint8_t *flags)
                th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
                if (th == NULL)
                        /* No choice either */
-                       return IPSET_INVALID_PORT;
+                       return false;
                
-               return flags[0] & IPSET_SRC ? th->source : th->dest;
+               *port = src ? th->source : th->dest;
+               break;
            }
        case IPPROTO_UDP: {
                struct udphdr _udph;
@@ -63,14 +64,16 @@ get_port(uint8_t pf, const struct sk_buff *skb, const uint8_t *flags)
                uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
                if (uh == NULL)
                        /* No choice either */
-                       return IPSET_INVALID_PORT;
+                       return false;
                
-               return flags[0] & IPSET_SRC ? uh->source : uh->dest;
+               *port = src ? uh->source : uh->dest;
+               break;
            }
        default:
-               return IPSET_INVALID_PORT;
+               return false;
        }
+       return true;
 }
-#endif                         /* __KERNEL__ */
+#endif /* __KERNEL__ */
 
 #endif /*_IP_SET_GETPORT_H*/
index dd183b70bbd76a3d81891ef3a050f6f68cb740ef..c1a69646396d16cb064560fb3e04e4ca03bc13f5 100644 (file)
@@ -9,12 +9,11 @@ enum {
 
 #ifdef __KERNEL__
 
-#define initval_t uint32_t
-
 #define IPSET_DEFAULT_HASHSIZE         1024
+#define IPSET_MIMINAL_HASHSIZE         64
 #define IPSET_DEFAULT_MAXELEM          65536
 #define IPSET_DEFAULT_PROBES           4
-#define IPSET_DEFAULT_RESIZE           50
+#define IPSET_DEFAULT_RESIZE           100
 
 #endif /* __KERNEL__ */
        
index 90bfcc3d32433f1c85a4925fbecd29e728bbaf2b..d5e0d6d039c57f57693b43c2965ab4e78f229ef4 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _LINUX_JHASH_H
 #define _LINUX_JHASH_H
-
-/* jhash.h: Jenkins hash support.
+/* jhash.c: Jenkins hash support.
  *
  * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
  *
  * if SELF_TEST is defined.  You can use this free for any purpose.  It's in
  * the public domain.  It has no warranty.
  *
- * Copyright (C) 2009 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
+ * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
  *
  * I've modified Bob's hash to be useful in the Linux kernel, and
- * any bugs present are my fault.  Jozsef
+ * any bugs present are my fault. The generic jhash is left out intentionally.
+ * Jozsef
  */
-
-#define __rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
-
-/* __jhash_mix - mix 3 32-bit values reversibly. */
-#define __jhash_mix(a,b,c)             \
-{                                      \
-  a -= c;  a ^= __rot(c, 4);  c += b;  \
-  b -= a;  b ^= __rot(a, 6);  a += c;  \
-  c -= b;  c ^= __rot(b, 8);  b += a;  \
-  a -= c;  a ^= __rot(c,16);  c += b;  \
-  b -= a;  b ^= __rot(a,19);  a += c;  \
-  c -= b;  c ^= __rot(b, 4);  b += a;  \
+#ifdef __KERNEL__
+#include <asm/byteorder.h>
+
+/* Best hash sizes are of power of two */
+#define jhash_size(n)   ((u32)1<<(n))
+/* Mask the hash value, i.e (value & jhash_mask(n)) instead of (value % n) */
+#define jhash_mask(n)   (jhash_size(n)-1)
+
+/* __jhash_rot - rotate 32 bit */
+#define __jhash_rot(x,k)       (((x)<<(k)) | ((x)>>(32-(k))))
+
+/* __jhash_mix -- mix 3 32-bit values reversibly. */
+#define __jhash_mix(a,b,c)                     \
+{                                              \
+  a -= c;  a ^= __jhash_rot(c, 4);  c += b;    \
+  b -= a;  b ^= __jhash_rot(a, 6);  a += c;    \
+  c -= b;  c ^= __jhash_rot(b, 8);  b += a;    \
+  a -= c;  a ^= __jhash_rot(c,16);  c += b;    \
+  b -= a;  b ^= __jhash_rot(a,19);  a += c;    \
+  c -= b;  c ^= __jhash_rot(b, 4);  b += a;    \
 }
 
 /* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
-#define __jhash_final(a,b,c)           \
-{                                      \
-  c ^= b; c -= __rot(b,14);            \
-  a ^= c; a -= __rot(c,11);            \
-  b ^= a; b -= __rot(a,25);            \
-  c ^= b; c -= __rot(b,16);            \
-  a ^= c; a -= __rot(c,4);             \
-  b ^= a; b -= __rot(a,14);            \
-  c ^= b; c -= __rot(b,24);            \
+#define __jhash_final(a,b,c)                   \
+{                                              \
+  c ^= b; c -= __jhash_rot(b,14);              \
+  a ^= c; a -= __jhash_rot(c,11);              \
+  b ^= a; b -= __jhash_rot(a,25);              \
+  c ^= b; c -= __jhash_rot(b,16);              \
+  a ^= c; a -= __jhash_rot(c,4);               \
+  b ^= a; b -= __jhash_rot(a,14);              \
+  c ^= b; c -= __jhash_rot(b,24);              \
 }
 
-/* An arbitrary value */
-#define JHASH_RANDOM_PARAM     0xdeadbeef
-
-/* The most generic version, hashes an arbitrary sequence
- * of bytes.  No alignment or length assumptions are made about
- * the input key. The result depends on endianness.
- */
-static inline u32 jhash(const void *key, u32 length, u32 initval)
-{
-       u32 a,b,c;
-       const u8 *k = key;
-
-       /* Set up the internal state */
-       a = b = c = JHASH_RANDOM_PARAM + length + initval;
-
-       /* all but the last block: affect some 32 bits of (a,b,c) */
-       while (length > 12) {
-               a += (k[0] + ((u32)k[1]<<8) + ((u32)k[2]<<16) + ((u32)k[3]<<24));
-               b += (k[4] + ((u32)k[5]<<8) + ((u32)k[6]<<16) + ((u32)k[7]<<24));
-               c += (k[8] + ((u32)k[9]<<8) + ((u32)k[10]<<16) + ((u32)k[11]<<24));
-               __jhash_mix(a, b, c);
-               length -= 12;
-               k += 12;
-       }
-
-       /* last block: affect all 32 bits of (c) */
-       /* all the case statements fall through */
-       switch (length) {
-       case 12: c += (u32)k[11]<<24;
-       case 11: c += (u32)k[10]<<16;
-       case 10: c += (u32)k[9]<<8;
-       case 9 : c += k[8];
-       case 8 : b += (u32)k[7]<<24;
-       case 7 : b += (u32)k[6]<<16;
-       case 6 : b += (u32)k[5]<<8;
-       case 5 : b += k[4];
-       case 4 : a += (u32)k[3]<<24;
-       case 3 : a += (u32)k[2]<<16;
-       case 2 : a += (u32)k[1]<<8;
-       case 1 : a += k[0];
-               __jhash_final(a, b, c);
-       case 0 :
-               break;
-       }
-
-       return c;
-}
+#define JHASH_INITVAL          0xdeadbeef
 
-/* A special optimized version that handles 1 or more of u32s.
- * The length parameter here is the number of u32s in the key.
+/* jhash2 - hash an array of u32's
+ * @k: the key which must be an array of u32's
+ * @length: the number of u32's in the key
+ * @initval: the previous hash, or an arbitray value
+ *
+ * Returns the hash value of the key.
  */
 static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
 {
        u32 a, b, c;
 
        /* Set up the internal state */
-       a = b = c = JHASH_RANDOM_PARAM + (length<<2) + initval;
+       a = b = c = JHASH_INITVAL + (length<<2) + initval;
 
-       /* handle most of the key */
+       /* Handle most of the key */
        while (length > 3) {
                a += k[0];
                b += k[1];
                c += k[2];
-               __jhash_mix(a, b, c);
+               __jhash_mix(a,b,c);
                length -= 3;
                k += 3;
        }
-
-       /* handle the last 3 u32's */
-       /* all the case statements fall through */ 
-       switch (length) {
+       
+       /* Handle the last 3 u32's: all the case statements fall through */
+       switch(length) {
        case 3: c += k[2];
        case 2: b += k[1];
        case 1: a += k[0];
-               __jhash_final(a, b, c);
-       case 0:     /* case 0: nothing left to add */
+       __jhash_final(a,b,c);
+       case 0: /* Nothing left to add */
                break;
        }
 
        return c;
 }
 
-/* A special ultra-optimized versions that knows they are hashing exactly
- * 3, 2 or 1 word(s).
- */
+/* jhash_3words - hash exactly 3, 2 or 1 word(s) */
 static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
 {
-       a += JHASH_RANDOM_PARAM + initval;
-       b += JHASH_RANDOM_PARAM + initval;
-       c += JHASH_RANDOM_PARAM + initval;
-
-       __jhash_final(a, b, c);
+       a += JHASH_INITVAL;
+       b += JHASH_INITVAL;
+       c += initval;
 
+       __jhash_final(a,b,c);
+       
        return c;
 }
-
 static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
 {
-       return jhash_3words(0, a, b, initval);
+       return jhash_3words(a, b, 0, initval);
 }
 
 static inline u32 jhash_1word(u32 a, u32 initval)
 {
-       return jhash_3words(0, 0, a, initval);
+        return jhash_3words(a, 0, 0, initval);
 }
 
+#endif /* __KERNEL__ */
+
 #endif /* _LINUX_JHASH_H */
diff --git a/kernel/include/linux/netfilter/ip_set_kernel.h b/kernel/include/linux/netfilter/ip_set_kernel.h
new file mode 100644 (file)
index 0000000..d6e033b
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _IP_SET_KERNEL_H
+#define _IP_SET_KERNEL_H
+
+/* Copyright (C) 2003-2010 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.  
+ */
+
+#ifdef __KERNEL__
+
+/* Complete debug messages */
+#define pr_fmt(fmt) "%s %s[%i]: " fmt "\n", __FILE__, __func__, __LINE__
+
+#include <linux/kernel.h>
+
+#endif /* __KERNEL__ */
+
+#endif /*_IP_SET_H */
diff --git a/kernel/include/linux/netfilter/ip_set_list.h b/kernel/include/linux/netfilter/ip_set_list.h
new file mode 100644 (file)
index 0000000..c40643e
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __IP_SET_LIST_H
+#define __IP_SET_LIST_H
+
+/* List type specific error codes */
+enum {
+       IPSET_ERR_NAME = IPSET_ERR_TYPE_SPECIFIC,
+       IPSET_ERR_LOOP,
+       IPSET_ERR_BEFORE,
+       IPSET_ERR_NAMEREF,
+       IPSET_ERR_LIST_FULL,
+       IPSET_ERR_REF_EXIST,
+};
+
+#ifdef __KERNEL__
+
+#define IP_SET_LIST_DEFAULT_SIZE       8
+#define IP_SET_LIST_MIN_SIZE           4
+
+#endif /* __KERNEL__ */
+       
+#endif /* __IP_SET_LIST_H */
diff --git a/kernel/include/linux/netfilter/ip_set_slist.h b/kernel/include/linux/netfilter/ip_set_slist.h
new file mode 100644 (file)
index 0000000..abc5afe
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef _IP_SET_SLIST_H
+#define _IP_SET_SLIST_H
+
+#include <linux/stddef.h>
+#include <linux/prefetch.h>
+#include <asm/system.h>
+
+/*
+ * Single linked lists with a single pointer.
+ * Mostly useful for hash tables where the two pointer list head 
+ * and list node is too wasteful.
+ */
+
+struct slist {
+       struct slist *next;
+};
+
+#define SLIST(name) struct slist name = {  .next = NULL }
+#define INIT_SLIST(ptr) ((ptr)->next = NULL)
+
+#define slist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define slist_for_each(pos, head) \
+       for (pos = (head)->next; pos && ({ prefetch(pos->next); 1; }); \
+            pos = pos->next)
+
+#define slist_for_each_prev(prev, pos, head) \
+       for (prev = head, pos = (head)->next; pos && ({ prefetch(pos->next); 1; }); \
+            prev = pos, pos = pos->next)
+
+#define slist_for_each_safe(pos, n, head) \
+       for (pos = (head)->next; pos && ({ n = pos->next; 1; }); \
+            pos = n)
+
+/**
+ * slist_for_each_entry        - iterate over list of given type
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct slist to use as a loop cursor.
+ * @head:      the head for your list.
+ * @member:    the name of the slist within the struct.
+ */
+#define slist_for_each_entry(tpos, pos, head, member)                   \
+       for (pos = (head)->next;                                         \
+            pos && ({ prefetch(pos->next); 1;}) &&                      \
+               ({ tpos = slist_entry(pos, typeof(*tpos), member); 1;}); \
+            pos = pos->next)
+
+/**
+ * slist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct slist to use as a loop cursor.
+ * @member:    the name of the slist within the struct.
+ */
+#define slist_for_each_entry_continue(tpos, pos, member)                \
+       for (pos = (pos)->next;                                          \
+            pos && ({ prefetch(pos->next); 1;}) &&                      \
+               ({ tpos = slist_entry(pos, typeof(*tpos), member); 1;}); \
+            pos = pos->next)
+
+/**
+ * slist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct slist to use as a loop cursor.
+ * @member:    the name of the slist within the struct.
+ */
+#define slist_for_each_entry_from(tpos, pos, member)                    \
+       for (; pos && ({ prefetch(pos->next); 1;}) &&                    \
+               ({ tpos = slist_entry(pos, typeof(*tpos), member); 1;}); \
+            pos = pos->next)
+
+/**
+ * slist_for_each_entry_safe - iterate over list of given type safe against
+ *                            removal of list entry
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct slist to use as a loop cursor.
+ * @n:         another &struct slist to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the slist within the struct.
+ */
+#define slist_for_each_entry_safe(tpos, pos, n, head, member)           \
+       for (pos = (head)->next;                                         \
+            pos && ({ n = pos->next; 1; }) &&                           \
+               ({ tpos = slist_entry(pos, typeof(*tpos), member); 1;}); \
+            pos = n)
+
+#endif /* _IP_SET_SLIST_H */
index da18875220dc1b0d50ae0780478d64d771f741e8..bf1cbf68d58165d6a0d595881a35d784b0d2a36b 100644 (file)
 
 #ifdef __KERNEL__
 
-/* How often should the gc be run at a minimum */
+/* How often should the gc be run by default */
 #define IPSET_GC_TIME                  (3 * 60)
 
 /* Timeout period depending on the timeout value of the given set */
 #define IPSET_GC_PERIOD(timeout) \
-       max_t(uint32_t, (timeout)/10, IPSET_GC_TIME)
+       ((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1)
 
-/* How much msec to sleep before retrying to destroy gc timer */
-#define IPSET_DESTROY_TIMER_SLEEP      10
+/* Set is defined without timeout support */
+#define IPSET_NO_TIMEOUT       UINT_MAX
 
-/* Timing out etries: unset and permanent */
+#define with_timeout(timeout)  ((timeout) != IPSET_NO_TIMEOUT)
+
+static inline unsigned int
+ip_set_timeout_uget(struct nlattr *tb)
+{
+       unsigned int timeout = ip_set_get_h32(tb);
+
+       return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout;
+}
+
+#ifdef IP_SET_BITMAP_TIMEOUT
+
+/* Bitmap entry is unset */
 #define IPSET_ELEM_UNSET       0
+/* Bitmap entry is set with no timeout value */
 #define IPSET_ELEM_PERMANENT   UINT_MAX/2
 
-#ifdef IP_SET_BITMAP_TIMEOUT
 static inline bool
 ip_set_timeout_test(unsigned long timeout)
 {
@@ -42,7 +54,7 @@ ip_set_timeout_expired(unsigned long timeout)
 }
 
 static inline unsigned long
-ip_set_timeout_set(uint32_t timeout)
+ip_set_timeout_set(u32 timeout)
 {
        unsigned long t;
        
@@ -56,7 +68,7 @@ ip_set_timeout_set(uint32_t timeout)
        return t;
 }
 
-static inline uint32_t
+static inline u32
 ip_set_timeout_get(unsigned long timeout)
 {
        return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
@@ -64,6 +76,9 @@ ip_set_timeout_get(unsigned long timeout)
 
 #else
 
+/* Hash entry is set with no timeout value */
+#define IPSET_ELEM_UNSET       0
+
 static inline bool
 ip_set_timeout_test(unsigned long timeout)
 {
@@ -77,7 +92,7 @@ ip_set_timeout_expired(unsigned long timeout)
 }
 
 static inline unsigned long
-ip_set_timeout_set(uint32_t timeout)
+ip_set_timeout_set(u32 timeout)
 {
        unsigned long t;
        
@@ -91,7 +106,7 @@ ip_set_timeout_set(uint32_t timeout)
        return t;
 }
 
-static inline uint32_t
+static inline u32
 ip_set_timeout_get(unsigned long timeout)
 {
        return timeout == IPSET_ELEM_UNSET ? 0 : (timeout - jiffies)/HZ;
diff --git a/kernel/include/linux/netfilter/ipt_set.h b/kernel/include/linux/netfilter/ipt_set.h
deleted file mode 100644 (file)
index 2a18b93..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef _IPT_SET_H
-#define _IPT_SET_H
-
-#include <linux/netfilter_ipv4/ip_set.h>
-
-struct ipt_set_info {
-       ip_set_id_t index;
-       u_int32_t flags[IP_SET_MAX_BINDINGS + 1];
-};
-
-/* match info */
-struct ipt_set_info_match {
-       struct ipt_set_info match_set;
-};
-
-struct ipt_set_info_target {
-       struct ipt_set_info add_set;
-       struct ipt_set_info del_set;
-};
-
-#endif /*_IPT_SET_H*/
diff --git a/kernel/include/linux/netfilter/xt_set.h b/kernel/include/linux/netfilter/xt_set.h
new file mode 100644 (file)
index 0000000..949fa59
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _XT_SET_H
+#define _XT_SET_H
+
+#include <linux/netfilter/ip_set.h>
+
+/* Revision 0 interface: backward compatible with netfilter/iptables */
+
+/*
+ * Option flags for kernel operations (xt_set_info_v0)
+ */
+#define IPSET_SRC              0x01    /* Source match/add */
+#define IPSET_DST              0x02    /* Destination match/add */
+#define IPSET_MATCH_INV                0x04    /* Inverse matching */
+
+struct xt_set_info_v0 {
+       ip_set_id_t index;
+       union {
+               u_int32_t flags[IPSET_DIM_MAX + 1];
+               struct {
+                       u_int32_t __flags[IPSET_DIM_MAX];
+                       u_int8_t dim;
+                       u_int8_t flags;
+               } compat;
+       } u;
+};
+
+/* match and target infos */
+struct xt_set_info_match_v0 {
+       struct xt_set_info_v0 match_set;
+};
+
+struct xt_set_info_target_v0 {
+       struct xt_set_info_v0 add_set;
+       struct xt_set_info_v0 del_set;
+};
+
+/* Revision 1: current interface to netfilter/iptables */
+
+struct xt_set_info {
+       ip_set_id_t index;
+       u_int8_t dim;
+       u_int8_t flags;
+};
+
+/* match and target infos */
+struct xt_set_info_match {
+       struct xt_set_info match_set;
+};
+
+struct xt_set_info_target {
+       struct xt_set_info add_set;
+       struct xt_set_info del_set;
+};
+
+#endif /*_XT_SET_H*/
index 3af8fce6a80e1d51350635b889f1802cc7407a60..5bf331e565e72e5de2ec6c96919b6ab6e2a8d39a 100644 (file)
@@ -9,25 +9,26 @@
 
 /* Kernel module for IP set management */
 
+#include <linux/netfilter/ip_set_kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/kernel.h>
 #include <linux/ip.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/netlink.h>
+#include <linux/rculist.h>
 #include <net/netlink.h>
 
 #include <linux/netfilter.h>
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/ip_set.h>
-#include <linux/netfilter/ip_set_jhash.h>
 
-static struct list_head ip_set_type_list;      /* all registered sets */
+static struct list_head ip_set_type_list;      /* all registered set types */
+static DEFINE_MUTEX(ip_set_type_mutex);                /* protects ip_set_type_list */
+
 static struct ip_set **ip_set_list;            /* all individual sets */
-static DEFINE_MUTEX(ip_set_type_mutex);                /* protects ip_set_type_lists */
-static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX;
+static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */
 
 #define STREQ(a,b)     (strncmp(a,b,IPSET_MAXNAMELEN) == 0)
 
@@ -43,31 +44,146 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
 /*
  * The set types are implemented in modules and registered set types
  * can be found in ip_set_type_list. Adding/deleting types is
- * serialized by ip_set_type_list_lock/ip_set_type_list_unlock.
+ * serialized by ip_set_type_mutex.
  */
 
 static inline void
-ip_set_type_list_lock(void)
+ip_set_type_lock(void)
 {
        mutex_lock(&ip_set_type_mutex);
 }
 
 static inline void
-ip_set_type_list_unlock(void)
+ip_set_type_unlock(void)
 {
        mutex_unlock(&ip_set_type_mutex);
 }
 
+/* Register and deregister settype */
+
+static inline struct ip_set_type *
+find_set_type(const char *name, u8 family, u8 revision)
+{
+       struct ip_set_type *type;
+
+       list_for_each_entry_rcu(type, &ip_set_type_list, list)
+               if (STREQ(type->name, name)
+                   && (type->family == family || type->family == AF_UNSPEC)
+                   && type->revision == revision)
+                       return type;
+       return NULL;
+}
+
+/* Find a set type so that rcu_read_lock() is called by the function.
+ * If we succeeded, the RCU lock is NOT released and the caller
+ * must release it later.
+ */
+static struct ip_set_type *
+find_set_type_rcu(const char *name, u8 family, u8 revision)
+{
+       struct ip_set_type *type;
+       
+       rcu_read_lock();
+       type = find_set_type(name, family, revision);
+       if (type == NULL)
+               rcu_read_unlock();
+
+       return type;
+}
+
+/* Find a given set type by name and family together
+ * with the supported minimal and maximum revisions.
+ */
+static bool
+find_set_type_minmax(const char *name, u8 family,
+                    u8 *min, u8 *max)
+{
+       struct ip_set_type *type;
+       bool ret = false;
+       
+       *min = *max = 0;
+       rcu_read_lock();
+       list_for_each_entry_rcu(type, &ip_set_type_list, list)
+               if (STREQ(type->name, name)
+                   && (type->family == family || type->family == AF_UNSPEC)) {
+                       ret = true;
+                       if (type->revision < *min)
+                               *min = type->revision;
+                       else if (type->revision > *max)
+                               *max = type->revision;
+               }
+       rcu_read_unlock();
+
+       return ret;
+}
+
+#define family_name(f) ((f) == AF_INET ? "inet" : \
+                        (f) == AF_INET6 ? "inet6" : "any")
+
+/* Register a set type structure. The type is identified by
+ * the unique triple of name, family and revision.
+ */
+int
+ip_set_type_register(struct ip_set_type *type)
+{
+       int ret = 0;
+       
+       if (type->protocol != IPSET_PROTOCOL) {
+               pr_warning("ip_set type %s, family %s, revision %u uses "
+                          "wrong protocol version %u (want %u)\n",
+                          type->name, family_name(type->family),
+                          type->revision, type->protocol, IPSET_PROTOCOL);
+               return -EINVAL;
+       }
+
+       ip_set_type_lock();
+       if (find_set_type(type->name, type->family, type->revision)) {
+               /* Duplicate! */
+               pr_warning("ip_set type %s, family %s, revision %u "
+                          "already registered!\n", type->name,
+                          family_name(type->family), type->revision);
+               ret = -EINVAL;
+               goto unlock;
+       }
+       list_add_rcu(&type->list, &ip_set_type_list);
+       pr_debug("type %s, family %s, revision %u registered.",
+                type->name, family_name(type->family), type->revision);
+unlock:
+       ip_set_type_unlock();
+       return ret;
+}
+EXPORT_SYMBOL(ip_set_type_register);
+
+/* Unregister a set type. There's a small race with ip_set_create */
+void
+ip_set_type_unregister(struct ip_set_type *type)
+{
+       ip_set_type_lock();
+       if (!find_set_type(type->name, type->family, type->revision)) {
+               pr_warning("ip_set type %s, family %s, revision %u "
+                          "not registered\n", type->name,
+                          family_name(type->family), type->revision);
+               goto unlock;
+       }
+       list_del_rcu(&type->list);
+       pr_debug("type %s, family %s, revision %u unregistered.",
+                type->name, family_name(type->family), type->revision);
+unlock:
+       ip_set_type_unlock();
+
+       synchronize_rcu();
+}
+EXPORT_SYMBOL(ip_set_type_unregister);
+
 /*
  * Creating/destroying/renaming/swapping affect the existence and
- * integrity of a set. All of these can be executed from userspace only
- * and serialized by nfnl_lock/nfnl_unlock indirectly from nfnetlink.
+ * the properties of a set. All of these can be executed from userspace
+ * only and serialized by the nfnl mutex indirectly from nfnetlink.
  *
  * Sets are identified by their index in ip_set_list and the index 
  * is used by the external references (set/SET netfilter modules).
  *
- * The set behind an index may change by swapping.
- *
+ * The set behind an index may change by swapping only, from userspace.
  */
 
 static inline void
@@ -82,264 +198,306 @@ __ip_set_put(ip_set_id_t index)
        atomic_dec(&ip_set_list[index]->ref);
 }
 
-/* Add, del and test set entries from kernel */
+/* 
+ * Add, del and test set entries from kernel.
+ *
+ * The set behind the index must exist and must be referenced
+ * so it can't be destroyed (or changed) under our foot.
+ */
 
 int
 ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
-           uint8_t family, const uint8_t *flags)
+           u8 family, u8 dim, u8 flags)
 {
-       struct ip_set *set;
+       struct ip_set *set = ip_set_list[index];
        int ret = 0;
 
-       rcu_read_lock();
-       set = rcu_dereference(ip_set_list[index]);
-       D("set %s, index %u", set->name, index);
+       BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
+       pr_debug("set %s, index %u", set->name, index);
+
+       if (dim < set->type->dimension
+           || !(family == set->family || set->family == AF_UNSPEC))
+               return 0;
 
        read_lock_bh(&set->lock);
-       ret = set->variant->kadt(set, skb, IPSET_TEST, family, flags);
+       ret = set->variant->kadt(set, skb, IPSET_TEST, family, dim, flags);
        read_unlock_bh(&set->lock);
 
        if (ret == -EAGAIN) {
                /* Type requests element to be re-added */
+               pr_debug("element must be competed, ADD is triggered");
                write_lock_bh(&set->lock);
-               set->variant->kadt(set, skb, IPSET_ADD, family, flags);
+               set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
                write_unlock_bh(&set->lock);
                ret = 1;
        }
 
-       rcu_read_unlock();
-
+       /* Convert error codes to nomatch */
        return (ret < 0 ? 0 : ret);
 }
+EXPORT_SYMBOL(ip_set_test);
 
 int
 ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
-          uint8_t family, const uint8_t *flags)
+          u8 family, u8 dim, u8 flags)
 {
-       struct ip_set *set;
+       struct ip_set *set = ip_set_list[index];
        int ret = 0, retried = 0;
 
-retry:
-       rcu_read_lock();
-       set = rcu_dereference(ip_set_list[index]);
-       D("set %s, index %u", set->name, index);
+       BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
+       pr_debug("set %s, index %u", set->name, index);
 
+       if (dim < set->type->dimension
+           || !(family == set->family || set->family == AF_UNSPEC))
+               return 0;
+
+retry:
        write_lock_bh(&set->lock);
-       ret = set->variant->kadt(set, skb, IPSET_ADD, family, flags);
+       ret = set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
        write_unlock_bh(&set->lock);
 
-       rcu_read_unlock();
        /* Retry function must be called without holding any lock */
        if (ret == -EAGAIN
            && set->variant->resize
-           && (ret = set->variant->resize(set, retried++)) == 0)
+           && (ret = set->variant->resize(set, GFP_ATOMIC, retried++)) == 0)
                goto retry;
        
        return ret;
 }
+EXPORT_SYMBOL(ip_set_add);
 
 int
 ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
-          uint8_t family, const uint8_t *flags)
+          u8 family, u8 dim, u8 flags)
 {
-       struct ip_set *set;
+       struct ip_set *set = ip_set_list[index];
        int ret = 0;
 
-       rcu_read_lock();
-       set = rcu_dereference(ip_set_list[index]);
-       D("set %s, index %u", set->name, index);
+       BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
+       pr_debug("set %s, index %u", set->name, index);
+
+       if (dim < set->type->dimension
+           || !(family == set->family || set->family == AF_UNSPEC))
+               return 0;
 
        write_lock_bh(&set->lock);
-       ret = set->variant->kadt(set, skb, IPSET_DEL, family, flags);
+       ret = set->variant->kadt(set, skb, IPSET_DEL, family, dim, flags);
        write_unlock_bh(&set->lock);
-
-       rcu_read_unlock();
        
        return ret;
 }
+EXPORT_SYMBOL(ip_set_del);
 
-/* Register and deregister settype */
-
-#define family_name(f) ((f) == AF_INET ? "inet" : \
-                        (f) == AF_INET6 ? "inet6" : "any")
-
-static inline struct ip_set_type *
-find_set_type(const char *name, uint8_t family, uint8_t revision)
+/*
+ * Find set by name, reference it once. The reference makes sure the
+ * thing pointed to, does not go away under our feet.
+ *
+ * The nfnl mutex must already be activated.
+ */
+ip_set_id_t
+ip_set_get_byname(const char *name, struct ip_set **set)
 {
-       struct ip_set_type *type;
-
-       list_for_each_entry(type, &ip_set_type_list, list)
-               if (STREQ(type->name, name)
-                   && (type->family == family || type->family == AF_UNSPEC)
-                   && type->revision == revision)
-                       return type;
-       return NULL;
-}
+       ip_set_id_t i, index = IPSET_INVALID_ID;
+       struct ip_set *s;
 
-int
-ip_set_type_register(struct ip_set_type *type)
-{
-       int ret = 0;
-       
-       if (type->protocol != IPSET_PROTOCOL) {
-               printk("set type %s, family %s, revision %u uses "
-                      "wrong protocol version %u (want %u)\n",
-                      type->name, family_name(type->family), type->revision,
-                      type->protocol, IPSET_PROTOCOL);
-               return -EINVAL;
+       for (i = 0; i < ip_set_max; i++) {
+               s = ip_set_list[i];
+               if (s != NULL && STREQ(s->name, name)) {
+                       __ip_set_get(i);
+                       index = i;
+                       *set = s;
+               }
        }
 
-       ip_set_type_list_lock();
-       if (find_set_type(type->name, type->family, type->revision)) {
-               /* Duplicate! */
-               printk("type %s, family %s, revision %u already registered!\n",
-                      type->name, family_name(type->family), type->revision);
-               ret = -EINVAL;
-               goto unlock;
-       }
-       list_add(&type->list, &ip_set_type_list);
-       D("type %s, family %s, revision %u registered.",
-         type->name, family_name(type->family), type->revision);
-unlock:
-       ip_set_type_list_unlock();
-       return ret;
+       return index;
 }
+EXPORT_SYMBOL(ip_set_get_byname);
 
+/*
+ * If the given set pointer points to a valid set, decrement
+ * reference count by 1. The caller shall not assume the index
+ * to be valid, after calling this function.
+ *
+ * The nfnl mutex must already be activated.
+ */
 void
-ip_set_type_unregister(struct ip_set_type *type)
+ip_set_put_byindex(ip_set_id_t index)
 {
-       ip_set_type_list_lock();
-       if (!find_set_type(type->name, type->family, type->revision)) {
-               printk("type %s, family %s, revision %u not registered\n",
-                      type->name, family_name(type->family), type->revision);
-               goto unlock;
+       if (ip_set_list[index] != NULL) {
+               BUG_ON(atomic_read(&ip_set_list[index]->ref) == 0);
+               __ip_set_put(index);
        }
-       list_del(&type->list);
-       D("type %s, family %s, revision %u unregistered.",
-         type->name, family_name(type->family), type->revision);
-unlock:
-       ip_set_type_list_unlock();
 }
+EXPORT_SYMBOL(ip_set_put_byindex);
+
+/*
+ * Get the name of a set behind a set index.
+ * We assume the set is referenced, so it does exist and
+ * can't be destroyed. The set cannot be renamed due to
+ * the referencing either.
+ *
+ * The nfnl mutex must already be activated.
+ */
+const char *
+ip_set_name_byindex(ip_set_id_t index)
+{
+       struct ip_set *set = ip_set_list[index];
+
+       BUG_ON(set == NULL);
+       BUG_ON(atomic_read(&set->ref) == 0);
+
+       /* Referenced, so it's safe */
+       return set->name;       
+}
+EXPORT_SYMBOL(ip_set_name_byindex);
 
-/* Get/put a set with referencing */
+/*
+ * Routines to call by external subsystems, which do not
+ * call nfnl_lock for us.
+ */
 
 /*
  * Find set by name, reference it once. The reference makes sure the
- * thing pointed to, does not go away under our feet. Drop the reference
- * later, using ip_set_put*().
+ * thing pointed to, does not go away under our feet.
+ *
+ * The nfnl mutex is used in the function.
  */
 ip_set_id_t
-ip_set_get_byname(const char *name)
+ip_set_nfnl_get(const char *name)
 {
-       ip_set_id_t i, index = IPSET_INVALID_ID;
-       
-       nfnl_lock();    
-       for (i = 0; index == IPSET_INVALID_ID && i < ip_set_max; i++)
-               if (STREQ(ip_set_list[i]->name, name)) {
-                       __ip_set_get(i);
-                       index = i;
-               }
+       struct ip_set *s;
+       ip_set_id_t index;
+
+       nfnl_lock();
+       index = ip_set_get_byname(name, &s);
+       nfnl_unlock();
+
+       return index;
+}
+EXPORT_SYMBOL(ip_set_nfnl_get);
+
+/*
+ * Find set by index, reference it once. The reference makes sure the
+ * thing pointed to, does not go away under our feet.
+ *
+ * The nfnl mutex is used in the function.
+ */
+ip_set_id_t
+ip_set_nfnl_get_byindex(ip_set_id_t index)
+{
+       if (index > ip_set_max)
+               return IPSET_INVALID_ID;
+
+       nfnl_lock();
+       if (ip_set_list[index])
+               __ip_set_get(index);
+       else
+               index = IPSET_INVALID_ID;
        nfnl_unlock();
 
        return index;
 }
+EXPORT_SYMBOL(ip_set_nfnl_get_byindex);
 
 /*
  * If the given set pointer points to a valid set, decrement
  * reference count by 1. The caller shall not assume the index
  * to be valid, after calling this function.
+ *
+ * The nfnl mutex is used in the function.
  */
 void
-ip_set_put_byindex(ip_set_id_t index)
+ip_set_nfnl_put(ip_set_id_t index)
 {
        nfnl_lock();
-       if (ip_set_list[index])
+       if (ip_set_list[index] != NULL) {
+               BUG_ON(atomic_read(&ip_set_list[index]->ref) == 0);
                __ip_set_put(index);
+       }
        nfnl_unlock();
 }
+EXPORT_SYMBOL(ip_set_nfnl_put);
 
-static ip_set_id_t
-find_set_id(const char *name)
+/*
+ * Communication protocol with userspace over netlink.
+ *
+ * We already locked by nfnl_lock.
+ */
+
+static inline bool
+protocol_failed(const struct nlattr * const tb[])
 {
-       ip_set_id_t i, index = IPSET_INVALID_ID;
-       
-       for (i = 0; index == IPSET_INVALID_ID && i < ip_set_max; i++) {
-               if (ip_set_list[i] != NULL
-                   && STREQ(ip_set_list[i]->name, name))
-                       index = i;
-       }
-       return index;
+       return !tb[IPSET_ATTR_PROTOCOL]
+              || nla_get_u8(tb[IPSET_ATTR_PROTOCOL]) != IPSET_PROTOCOL;
 }
 
-static ip_set_id_t
-find_set_id_rcu(const char *name)
+static inline u32
+flag_exist(const struct nlmsghdr *nlh)
 {
-       ip_set_id_t i, index = IPSET_INVALID_ID;
-       struct ip_set *set;
-       
-       for (i = 0; index == IPSET_INVALID_ID && i < ip_set_max; i++) {
-               set = rcu_dereference(ip_set_list[i]);
-               if (set != NULL && STREQ(set->name, name))
-                       index = i;
-       }
-       return index;
+       return nlh->nlmsg_flags & NLM_F_EXCL ? 0 : IPSET_FLAG_EXIST;
 }
 
-static struct ip_set *
-find_set(const char *name)
+static inline bool
+flag_nested(const struct nlattr *nla)
 {
-       ip_set_id_t index = find_set_id(name);
-
-       return index == IPSET_INVALID_ID ? NULL : ip_set_list[index];
+       return nla->nla_type & NLA_F_NESTED;
 }
 
-/* Communication protocol with userspace over netlink */
+static struct nlmsghdr *
+start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags,
+         enum ipset_cmd cmd)
+{
+       struct nlmsghdr *nlh;
+       struct nfgenmsg *nfmsg;
+
+       nlh = nlmsg_put(skb, pid, seq, cmd | (NFNL_SUBSYS_IPSET << 8),
+                       sizeof(*nfmsg), flags);
+       if (nlh == NULL)
+               return NULL;
+
+       nfmsg = nlmsg_data(nlh);
+       nfmsg->nfgen_family = AF_INET;
+       nfmsg->version = NFNETLINK_V0;
+       nfmsg->res_id = 0;
+       
+       return nlh;
+}
 
 /* Create a set */
 
 static const struct nla_policy
 ip_set_create_policy[IPSET_ATTR_CMD_MAX + 1] __read_mostly = {
        [IPSET_ATTR_PROTOCOL]   = { .type = NLA_U8 },
-       [IPSET_ATTR_SETNAME]    = { .type = NLA_STRING,
-                                   .len = IPSET_MAXNAMELEN },
-       [IPSET_ATTR_TYPENAME]   = { .type = NLA_STRING,
-                                   .len = IPSET_MAXNAMELEN },
+       [IPSET_ATTR_SETNAME]    = { .type = NLA_NUL_STRING,
+                                   .len = IPSET_MAXNAMELEN -1 },
+       [IPSET_ATTR_TYPENAME]   = { .type = NLA_NUL_STRING,
+                                   .len = IPSET_MAXNAMELEN - 1},
        [IPSET_ATTR_REVISION]   = { .type = NLA_U8 },
        [IPSET_ATTR_FAMILY]     = { .type = NLA_U8 },
        [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
        [IPSET_ATTR_DATA]       = { .type = NLA_NESTED },
 };
 
-static inline bool
-protocol_failed(const struct nlattr * const tb[])
-{
-       return !tb[IPSET_ATTR_PROTOCOL]
-              || nla_get_u8(tb[IPSET_ATTR_PROTOCOL]) != IPSET_PROTOCOL;
-}
-
-static inline uint32_t
-flag_exist(const struct nlmsghdr *nlh)
-{
-       return nlh->nlmsg_flags & NLM_F_EXCL ? 0 : IPSET_FLAG_EXIST;
-}
-
-static inline bool
-flag_nested(const struct nlattr *nla)
+static ip_set_id_t
+find_set_id(const char *name)
 {
-       return nla->nla_type & NLA_F_NESTED;
+       ip_set_id_t i, index = IPSET_INVALID_ID;
+       struct ip_set *set;
+       
+       for (i = 0; index == IPSET_INVALID_ID && i < ip_set_max; i++) {
+               set = ip_set_list[i];
+               if (set != NULL && STREQ(set->name, name))
+                       index = i;
+       }
+       return index;
 }
 
-static struct ip_set_type *
-find_set_type_lock(const char *name, uint8_t family, uint8_t revision)
+static inline struct ip_set *
+find_set(const char *name)
 {
-       struct ip_set_type *type;
-       
-       ip_set_type_list_lock();
-       type = find_set_type(name, family, revision);
-       if (type == NULL)
-               ip_set_type_list_unlock();
+       ip_set_id_t index = find_set_id(name);
 
-       return type;
+       return index == IPSET_INVALID_ID ? NULL : ip_set_list[index];
 }
 
 static int
@@ -364,30 +522,10 @@ find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set)
        return 0;
 }
 
-static struct nlmsghdr *
-start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags,
-         enum ipset_cmd cmd)
-{
-       struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
-
-       nlh = nlmsg_put(skb, pid, seq, cmd | (NFNL_SUBSYS_IPSET << 8),
-                       sizeof(*nfmsg), flags);
-       if (nlh == NULL)
-               return NULL;
-
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family = AF_INET;
-       nfmsg->version = NFNETLINK_V0;
-       nfmsg->res_id = 0;
-       
-       return nlh;
-}
-
 static inline void
 load_type_module(const char *typename)
 {
-       D("try to load ip_set_%s", typename);
+       pr_debug("try to load ip_set_%s", typename);
        request_module("ip_set_%s", typename);
 }
 
@@ -399,8 +537,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
        struct ip_set *set, *clash;
        ip_set_id_t index = IPSET_INVALID_ID;
        const char *name, *typename;
-       uint8_t family, revision;
-       uint32_t flags = flag_exist(nlh);
+       u8 family, revision;
+       u32 flags = flag_exist(nlh);
        int ret = 0, len;
 
        if (unlikely(protocol_failed(attr)      
@@ -416,8 +554,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
        typename = nla_data(attr[IPSET_ATTR_TYPENAME]);
        family = nla_get_u8(attr[IPSET_ATTR_FAMILY]);
        revision = nla_get_u8(attr[IPSET_ATTR_REVISION]);
-       D("setname: %s, typename: %s, family: %s, revision: %u",
-         name, typename, family_name(family), revision);
+       pr_debug("setname: %s, typename: %s, family: %s, revision: %u",
+                name, typename, family_name(family), revision);
 
        /*
         * First, and without any locks, allocate and initialize
@@ -429,6 +567,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
        rwlock_init(&set->lock);
        strncpy(set->name, name, IPSET_MAXNAMELEN);
        atomic_set(&set->ref, 0);
+       set->family = family;
 
        /*
         * Next, check that we know the type, and take
@@ -438,31 +577,32 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
         * After referencing the type, we try to create the type
         * specific part of the set without holding any locks.
         */
-       set->type = find_set_type_lock(typename, family, revision);
+       set->type = find_set_type_rcu(typename, family, revision);
        if (set->type == NULL) {
                /* Try loading the module */
                load_type_module(typename);
-               set->type = find_set_type_lock(typename, family, revision);
+               set->type = find_set_type_rcu(typename, family, revision);
                if (set->type == NULL) {
-                       printk("Can't find type %s, family %s, revision %u:"
-                              " set '%s' not created",
-                              typename, family_name(family), revision, name);
+                       pr_warning("Can't find ip_set type %s, family %s, "
+                                  "revision %u: set '%s' not created",
+                                  typename, family_name(family), revision,
+                                  name);
                        ret = -IPSET_ERR_FIND_TYPE;
                        goto out;
                }
        }
        if (!try_module_get(set->type->me)) {
-               ip_set_type_list_unlock();
+               rcu_read_unlock();
                ret = -EFAULT;
                goto out;
        }
-       ip_set_type_list_unlock();
+       rcu_read_unlock();
 
        /*
         * Without holding any locks, create private part.
         */
        len = attr[IPSET_ATTR_DATA] ? nla_len(attr[IPSET_ATTR_DATA]) : 0;
-       D("data len: %u", len);
+       pr_debug("data len: %u", len);
        ret = set->type->create(set, attr[IPSET_ATTR_DATA] ?
                                nla_data(attr[IPSET_ATTR_DATA]) : NULL, len,
                                flags);
@@ -482,7 +622,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
                    && (flags & IPSET_FLAG_EXIST)
                    && STREQ(set->type->name, clash->type->name)
                    && set->type->family == clash->type->family
-                   && set->type->revision == clash->type->revision)
+                   && set->type->revision == clash->type->revision
+                   && set->variant->same_set(set, clash))
                        ret = 0;
                goto cleanup;
        }
@@ -490,7 +631,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
        /*
         * Finally! Add our shiny new set to the list, and be done.
         */
-       D("create: '%s' created with index %u!", set->name, index);
+       pr_debug("create: '%s' created with index %u!", set->name, index);
        ip_set_list[index] = set;
 
        return ret;
@@ -509,8 +650,8 @@ out:
 static const struct nla_policy
 ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] __read_mostly = {
        [IPSET_ATTR_PROTOCOL]   = { .type = NLA_U8 },
-       [IPSET_ATTR_SETNAME]    = { .type = NLA_STRING,
-                                   .len = IPSET_MAXNAMELEN },
+       [IPSET_ATTR_SETNAME]    = { .type = NLA_NUL_STRING,
+                                   .len = IPSET_MAXNAMELEN - 1 },
 };
 
 static inline void
@@ -518,7 +659,7 @@ ip_set_destroy_set(ip_set_id_t index)
 {
        struct ip_set *set = ip_set_list[index];
 
-       D("set: %s",  set->name);
+       pr_debug("set: %s",  set->name);
        ip_set_list[index] = NULL;
 
        /* Must call it without holding any lock */
@@ -565,7 +706,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
 static inline void
 ip_set_flush_set(struct ip_set *set)
 {
-       D("set: %s",  set->name);
+       pr_debug("set: %s",  set->name);
 
        write_lock_bh(&set->lock);
        set->variant->flush(set);
@@ -602,10 +743,10 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
 static const struct nla_policy
 ip_set_setname2_policy[IPSET_ATTR_CMD_MAX + 1] __read_mostly = {
        [IPSET_ATTR_PROTOCOL]   = { .type = NLA_U8 },
-       [IPSET_ATTR_SETNAME]    = { .type = NLA_STRING,
-                                   .len = IPSET_MAXNAMELEN },
-       [IPSET_ATTR_SETNAME2]   = { .type = NLA_STRING,
-                                   .len = IPSET_MAXNAMELEN },
+       [IPSET_ATTR_SETNAME]    = { .type = NLA_NUL_STRING,
+                                   .len = IPSET_MAXNAMELEN - 1 },
+       [IPSET_ATTR_SETNAME2]   = { .type = NLA_NUL_STRING,
+                                   .len = IPSET_MAXNAMELEN - 1 },
 };
 
 static int
@@ -625,6 +766,8 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
        set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
        if (set == NULL)
                return -EEXIST;
+       if (atomic_read(&set->ref) != 0)
+               return -IPSET_ERR_REFERENCED;
 
        name2 = nla_data(attr[IPSET_ATTR_SETNAME2]);
        for (i = 0; i < ip_set_max; i++) {
@@ -638,7 +781,13 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
 }
 
 /* Swap two sets so that name/index points to the other.
- * References are also swapped. */
+ * References and set names are also swapped.
+ *
+ * We are protected by the nfnl mutex and references are
+ * manipulated only by holding the mutex. The kernel interfaces
+ * do not hold the mutex but the pointer settings are atomic
+ * so the ip_set_list always contains valid pointers to the sets.
+ */
 
 static int
 ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
@@ -648,7 +797,7 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
        struct ip_set *from, *to;
        ip_set_id_t from_id, to_id;
        char from_name[IPSET_MAXNAMELEN];
-       uint32_t from_ref;
+       u32 from_ref;
        
        if (unlikely(protocol_failed(attr)
                     || attr[IPSET_ATTR_SETNAME] == NULL
@@ -673,7 +822,7 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
              && from->type->family == to->type->family))
                return -IPSET_ERR_TYPE_MISMATCH;
 
-       /* No magic here: ref munging protected by the mutex */ 
+       /* No magic here: ref munging protected by the nfnl_lock */     
        strncpy(from_name, from->name, IPSET_MAXNAMELEN);
        from_ref = atomic_read(&from->ref);
 
@@ -682,20 +831,29 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
        strncpy(to->name, from_name, IPSET_MAXNAMELEN);
        atomic_set(&to->ref, from_ref);
        
-       rcu_assign_pointer(ip_set_list[from_id], to);
-       rcu_assign_pointer(ip_set_list[to_id], from);
-       synchronize_rcu();
+       ip_set_list[from_id] = to;
+       ip_set_list[to_id] = from;
+
+       /* Avoid possible race between ongoing slow add/del in kernel space
+        * and next destroy command. */
+       synchronize_net();
 
        return 0;
 }
 
 /* List/save set data */
 
+#define DUMP_ALL       0L
+#define DUMP_ONE       1L
+#define DUMP_LAST      2L
+
 static int
 ip_set_dump_done(struct netlink_callback *cb)
 {
-       if (cb->args[2])
+       if (cb->args[2]) {
+               pr_debug("release set %s", ip_set_list[cb->args[1]]->name);
                __ip_set_put((ip_set_id_t) cb->args[1]);
+       }
        return 0;
 }
 
@@ -705,9 +863,9 @@ dump_attrs(struct nlmsghdr *nlh)
        struct nlattr *attr;
        int rem;
 
-       D("dump nlmsg");        
+       pr_debug("dump nlmsg"); 
        nlmsg_for_each_attr(attr, nlh, sizeof(struct nfgenmsg), rem) {
-               D("type: %u, len %u", nla_type(attr), attr->nla_len);
+               pr_debug("type: %u, len %u", nla_type(attr), attr->nla_len);
        }
 }
 
@@ -720,22 +878,32 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
        unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0;
        int ret = 0;
 
-       max = cb->args[0] ? cb->args[1] + 1 : ip_set_max;
-       rcu_read_lock();
+       if (cb->args[1] >= ip_set_max)
+               goto out;
+
+       pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]);
+       max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
        for (; cb->args[1] < max; cb->args[1]++) {
                index = (ip_set_id_t) cb->args[1];
-               set = rcu_dereference(ip_set_list[index]);
+               set = ip_set_list[index];
                if (set == NULL) {
-                       if (cb->args[0]) {
+                       if (cb->args[0] == DUMP_ONE) {
                                ret = -EEXIST;
-                               goto unlock;
+                               goto out;
                        }
                        continue;
                }
-               D("List set: %s", set->name);
+               /* When dumping all sets, we must dump "sorted"
+                * so that lists (unions of sets) are dumped last.
+                */
+               if (cb->args[0] != DUMP_ONE
+                   && !((cb->args[0] == DUMP_ALL)
+                        ^ (set->type->features & IPSET_DUMP_LAST)))
+                       continue;
+               pr_debug("List set: %s", set->name);
                if (!cb->args[2]) {
                        /* Start listing: make sure set won't be destroyed */
-                       D("reference set");
+                       pr_debug("reference set");
                        __ip_set_get(index);
                }
                nlh = start_msg(skb, NETLINK_CB(cb->skb).pid,
@@ -753,7 +921,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
                        NLA_PUT_STRING(skb, IPSET_ATTR_TYPENAME,
                                       set->type->name);
                        NLA_PUT_U8(skb, IPSET_ATTR_FAMILY,
-                                  set->type->family);
+                                  set->family);
                        NLA_PUT_U8(skb, IPSET_ATTR_REVISION,
                                   set->type->revision);
                        ret = set->variant->head(set, skb);
@@ -764,28 +932,35 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
                        read_lock_bh(&set->lock);
                        ret = set->variant->list(set, skb, cb);
                        read_unlock_bh(&set->lock);
-                       if (!cb->args[2])
+                       if (!cb->args[2]) {
                                /* Set is done, proceed with next one */
-                               cb->args[1]++;
+                               if (cb->args[0] == DUMP_ONE)
+                                       cb->args[1] = IPSET_INVALID_ID;
+                               else
+                                       cb->args[1]++;
+                       }
                        goto release_refcount;
                }
        }
-       goto unlock;
+       goto out;
 
 nla_put_failure:
        ret = -EFAULT;
 release_refcount:
        /* If there was an error or set is done, release set */
        if (ret || !cb->args[2]) {
-               D("release set");
+               pr_debug("release set %s", ip_set_list[index]->name);
                __ip_set_put(index);
        }
-unlock:
-       rcu_read_unlock();
 
+       /* If we dump all sets, continue with dumping last ones */
+       if (cb->args[0] == DUMP_ALL && cb->args[1] >= max && !cb->args[2])
+               cb->args[0] = DUMP_LAST;
+
+out:
        if (nlh) {
                nlmsg_end(skb, nlh);
-               D("nlmsg_len: %u", nlh->nlmsg_len);
+               pr_debug("nlmsg_len: %u", nlh->nlmsg_len);
                dump_attrs(nlh);
        }
        
@@ -807,23 +982,18 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb,
                                          ip_set_dump_start,
                                          ip_set_dump_done);
 
-       rcu_read_lock();
-       index = find_set_id_rcu(nla_data(attr[IPSET_ATTR_SETNAME]));
-       if (index == IPSET_INVALID_ID) {
-               rcu_read_unlock();
+       index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
+       if (index == IPSET_INVALID_ID)
                return -EEXIST;
-       }
-       rcu_read_unlock();
 
-       /* cb->args[0] : 1 => dump single set,
-        *             : 0 => dump all sets
+       /* cb->args[0] : dump single set/all sets
         *         [1] : set index
         *         [..]: type specific
         */
        return netlink_dump_init(ctnl, skb, nlh,
                                 ip_set_dump_start,
                                 ip_set_dump_done,
-                                2, 1, index);
+                                2, DUMP_ONE, index);
 }
 
 /* Add, del and test */
@@ -831,8 +1001,8 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb,
 static const struct nla_policy
 ip_set_adt_policy[IPSET_ATTR_CMD_MAX + 1] __read_mostly = {
        [IPSET_ATTR_PROTOCOL]   = { .type = NLA_U8 },
-       [IPSET_ATTR_SETNAME]    = { .type = NLA_STRING,
-                                   .len = IPSET_MAXNAMELEN },
+       [IPSET_ATTR_SETNAME]    = { .type = NLA_NUL_STRING,
+                                   .len = IPSET_MAXNAMELEN - 1 },
        [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
        [IPSET_ATTR_DATA]       = { .type = NLA_NESTED },
        [IPSET_ATTR_ADT]        = { .type = NLA_NESTED },
@@ -842,11 +1012,11 @@ static int
 call_ad(struct sock *ctnl, struct sk_buff *skb,
        const struct nlattr * const attr[],
        struct ip_set *set, const struct nlattr *nla,
-       enum ipset_adt adt, uint32_t flags)
+       enum ipset_adt adt, u32 flags)
 {
        struct nlattr *head = nla_data(nla);
        int ret, len = nla_len(nla), retried = 0;
-       uint32_t lineno = 0;
+       u32 lineno = 0;
        bool eexist = flags & IPSET_FLAG_EXIST;
        
        do {
@@ -856,13 +1026,13 @@ call_ad(struct sock *ctnl, struct sk_buff *skb,
                write_unlock_bh(&set->lock);
        } while (ret == -EAGAIN
                 && set->variant->resize
-                && (ret = set->variant->resize(set, retried++)) == 0);
+                && (ret = set->variant->resize(set, GFP_KERNEL, retried++)) == 0);
 
        if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
                return 0;
        if (lineno && attr[IPSET_ATTR_LINENO]) {
                /* Error in restore/batch mode: send back lineno */
-               uint32_t *errline = nla_data(attr[IPSET_ATTR_LINENO]);
+               u32 *errline = nla_data(attr[IPSET_ATTR_LINENO]);
                
                *errline = lineno;
        }
@@ -877,7 +1047,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,
 {
        struct ip_set *set;
        const struct nlattr *nla;
-       uint32_t flags = flag_exist(nlh);
+       u32 flags = flag_exist(nlh);
        int ret = 0;
 
        if (unlikely(protocol_failed(attr)
@@ -921,7 +1091,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,
 {
        struct ip_set *set;
        const struct nlattr *nla;
-       uint32_t flags = flag_exist(nlh);
+       u32 flags = flag_exist(nlh);
        int ret = 0;
 
        if (unlikely(protocol_failed(attr)
@@ -1022,7 +1192,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,
        NLA_PUT_U8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
        NLA_PUT_STRING(skb2, IPSET_ATTR_SETNAME, set->name);
        NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, set->type->name);
-       NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, set->type->family);
+       NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, set->family);
        NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->type->revision);
        nlmsg_end(skb2, nlh2);
 
@@ -1044,34 +1214,11 @@ nlmsg_failure:
 static const struct nla_policy
 ip_set_type_policy[IPSET_ATTR_CMD_MAX + 1] __read_mostly = {
        [IPSET_ATTR_PROTOCOL]   = { .type = NLA_U8 },
-       [IPSET_ATTR_TYPENAME]   = { .type = NLA_STRING,
-                                   .len = IPSET_MAXNAMELEN },
+       [IPSET_ATTR_TYPENAME]   = { .type = NLA_NUL_STRING,
+                                   .len = IPSET_MAXNAMELEN - 1 },
        [IPSET_ATTR_FAMILY]     = { .type = NLA_U8 },
 };
 
-static bool
-find_set_type_minmax(const char *name, uint8_t family,
-                    uint8_t *min, uint8_t *max)
-{
-       struct ip_set_type *type;
-       bool ret = false;
-       
-       *min = *max = 0;
-       ip_set_type_list_lock();
-       list_for_each_entry(type, &ip_set_type_list, list)
-               if (STREQ(type->name, name)
-                   && (type->family == family || type->family == AF_UNSPEC)) {
-                       ret = true;
-                       if (type->revision < *min)
-                               *min = type->revision;
-                       else if (type->revision > *max)
-                               *max = type->revision;
-               }
-       ip_set_type_list_unlock();
-
-       return ret;
-}
-
 static int
 ip_set_type(struct sock *ctnl, struct sk_buff *skb,
            const struct nlmsghdr *nlh,
@@ -1079,7 +1226,7 @@ ip_set_type(struct sock *ctnl, struct sk_buff *skb,
 {
        struct sk_buff *skb2;
        struct nlmsghdr *nlh2;
-       uint8_t family, min, max;
+       u8 family, min, max;
        const char *typename;
        int ret = 0;
 
@@ -1094,7 +1241,7 @@ ip_set_type(struct sock *ctnl, struct sk_buff *skb,
                /* Try to load in the type module */
                load_type_module(typename);
                if (!find_set_type_minmax(typename, family, &min, &max)) {
-                       D("can't find: %s, family: %u", typename, family);
+                       pr_debug("can't find: %s, family: %u", typename, family);
                        return -EEXIST;
                }
        }
@@ -1114,7 +1261,7 @@ ip_set_type(struct sock *ctnl, struct sk_buff *skb,
        NLA_PUT_U8(skb2, IPSET_ATTR_REVISION_MIN, min);
        nlmsg_end(skb2, nlh2);
 
-       D("Send TYPE, nlmsg_len: %u", nlh2->nlmsg_len);
+       pr_debug("Send TYPE, nlmsg_len: %u", nlh2->nlmsg_len);
        ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
        if (ret < 0)
                return -EFAULT;
@@ -1171,7 +1318,8 @@ nlmsg_failure:
        return -EFAULT;
 }
 
-static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
+static const struct nfnl_callback __read_mostly
+ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
        [IPSET_CMD_CREATE]      = {
                .call           = ip_set_create,
                .attr_count     = IPSET_ATTR_CMD_MAX,
@@ -1246,6 +1394,106 @@ static struct nfnetlink_subsystem ip_set_netlink_subsys = {
        .cb             = ip_set_netlink_subsys_cb,
 };
 
+/* Interface to iptables/ip6tables */
+
+static int
+ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len)
+{
+       unsigned *op;
+       void *data;
+       int copylen = *len, ret = 0;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+       if (optval != SO_IP_SET)
+               return -EBADF;
+       if (*len < sizeof(unsigned)) {
+               return -EINVAL;
+       }
+       data = vmalloc(*len);
+       if (!data)
+               return -ENOMEM;
+       if (copy_from_user(data, user, *len) != 0) {
+               ret = -EFAULT;
+               goto done;
+       }
+       op = (unsigned *) data;
+
+       if (*op < IP_SET_OP_VERSION) {
+               /* Check the version at the beginning of operations */
+               struct ip_set_req_version *req_version = data;
+               if (req_version->version != IPSET_PROTOCOL) {
+                       ret = -EPROTO;
+                       goto done;
+               }
+       }
+
+       switch (*op) {
+       case IP_SET_OP_VERSION: {
+               struct ip_set_req_version *req_version = data;
+
+               if (*len != sizeof(struct ip_set_req_version)) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+
+               req_version->version = IPSET_PROTOCOL;
+               ret = copy_to_user(user, req_version,
+                                  sizeof(struct ip_set_req_version));
+               goto done;
+       }
+       case IP_SET_OP_GET_BYNAME: {
+               struct ip_set_req_get_set *req_get = data;
+
+               if (*len != sizeof(struct ip_set_req_get_set)) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+               req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';
+               nfnl_lock();
+               req_get->set.index = find_set_id(req_get->set.name);
+               nfnl_unlock();
+               goto copy;
+       }
+       case IP_SET_OP_GET_BYINDEX: {
+               struct ip_set_req_get_set *req_get = data;
+
+               if (*len != sizeof(struct ip_set_req_get_set)
+                   || req_get->set.index >= ip_set_max) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+               nfnl_lock();
+               strncpy(req_get->set.name,
+                       ip_set_list[req_get->set.index]
+                               ? ip_set_list[req_get->set.index]->name : "",
+                       IPSET_MAXNAMELEN);
+               nfnl_unlock();
+               goto copy;
+       }
+       default:
+               ret = -EBADMSG;
+               goto done;
+       }       /* end of switch(op) */
+
+    copy:
+       ret = copy_to_user(user, data, copylen);
+       
+    done:
+       vfree(data);
+       if (ret > 0)
+               ret = 0;
+       return ret;
+}
+
+static struct nf_sockopt_ops so_set = {
+       .pf             = PF_INET,
+       .get_optmin     = SO_IP_SET,
+       .get_optmax     = SO_IP_SET + 1,
+       .get            = &ip_set_sockfn_get,
+       .owner          = THIS_MODULE,
+};
+
 static int __init
 ip_set_init(void)
 {
@@ -1258,7 +1506,7 @@ ip_set_init(void)
 
        ip_set_list = kzalloc(sizeof(struct ip_set *) * ip_set_max, GFP_KERNEL);
        if (!ip_set_list) {
-               printk(KERN_ERR "Unable to create ip_set_list\n");
+               pr_err("ip_set: Unable to create ip_set_list");
                return -ENOMEM;
        }
 
@@ -1266,12 +1514,19 @@ ip_set_init(void)
 
        ret = nfnetlink_subsys_register(&ip_set_netlink_subsys);
        if (ret != 0) {
-               printk("ip_set_init: cannot register with nfnetlink.\n");
+               pr_err("ip_set: cannot register with nfnetlink.");
+               kfree(ip_set_list);
+               return ret;
+       }
+       ret = nf_register_sockopt(&so_set);
+       if (ret != 0) {
+               pr_err("SO_SET registry failed: %d", ret);
+               nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
                kfree(ip_set_list);
                return ret;
        }
 
-       printk("ip_set with protocol version %u loaded\n", IPSET_PROTOCOL);     
+       pr_notice("ip_set with protocol version %u loaded", IPSET_PROTOCOL);    
        return 0;
 }
 
@@ -1279,20 +1534,11 @@ static void __exit
 ip_set_fini(void)
 {
        /* There can't be any existing set */
+       nf_unregister_sockopt(&so_set);
        nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
        kfree(ip_set_list);
-       D("these are the famous last words");
+       pr_debug("these are the famous last words");
 }
 
-EXPORT_SYMBOL(ip_set_type_register);
-EXPORT_SYMBOL(ip_set_type_unregister);
-
-EXPORT_SYMBOL(ip_set_get_byname);
-EXPORT_SYMBOL(ip_set_put_byindex);
-
-EXPORT_SYMBOL(ip_set_add);
-EXPORT_SYMBOL(ip_set_del);
-EXPORT_SYMBOL(ip_set_test);
-
 module_init(ip_set_init);
 module_exit(ip_set_fini);
index ccb5473a05d7ab766346da9c57b004e4f3df0b5f..66d39799e71a6ddf41e804c744bd15c04fee0081 100644 (file)
@@ -9,6 +9,7 @@
 
 /* Kernel module implementing an IP set type: the bitmap:ip type */
 
+#include <linux/netfilter/ip_set_kernel.h>
 #include <linux/module.h>
 #include <linux/ip.h>
 #include <linux/skbuff.h>
@@ -17,7 +18,6 @@
 #include <asm/bitops.h>
 #include <linux/spinlock.h>
 #include <linux/netlink.h>
-#include <linux/delay.h>
 #include <linux/jiffies.h>
 #include <linux/timer.h>
 #include <net/netlink.h>
@@ -38,28 +38,28 @@ MODULE_ALIAS("ip_set_bitmap:ip");
 
 struct bitmap_ip {
        void *members;          /* the set members */
-       uint32_t first_ip;      /* host byte order, included in range */
-       uint32_t last_ip;       /* host byte order, included in range */
-       uint32_t elements;      /* number of max elements in the set */
-       uint32_t hosts;         /* number of hosts in a subnet */
+       u32 first_ip;           /* host byte order, included in range */
+       u32 last_ip;            /* host byte order, included in range */
+       u32 elements;           /* number of max elements in the set */
+       u32 hosts;              /* number of hosts in a subnet */
        size_t memsize;         /* members size */
-       uint8_t netmask;        /* subnet netmask */
+       u8 netmask;             /* subnet netmask */
 };
 
-static inline uint32_t
-ip_to_id(const struct bitmap_ip *map, uint32_t ip)
+static inline u32
+ip_to_id(const struct bitmap_ip *map, u32 ip)
 {
        return ((ip & HOSTMASK(map->netmask)) - map->first_ip)/map->hosts;
 }
 
 static inline int
-bitmap_ip_test(const struct bitmap_ip *map, uint32_t id)
+bitmap_ip_test(const struct bitmap_ip *map, u32 id)
 {
        return !!test_bit(id, map->members);
 }
 
 static inline int
-bitmap_ip_add(struct bitmap_ip *map, uint32_t id)
+bitmap_ip_add(struct bitmap_ip *map, u32 id)
 {
        if (test_and_set_bit(id, map->members))
                return -IPSET_ERR_EXIST;
@@ -68,7 +68,7 @@ bitmap_ip_add(struct bitmap_ip *map, uint32_t id)
 }
 
 static inline int
-bitmap_ip_del(struct bitmap_ip *map, uint32_t id)
+bitmap_ip_del(struct bitmap_ip *map, u32 id)
 {
        if (!test_and_clear_bit(id, map->members))
                return -IPSET_ERR_EXIST;
@@ -78,14 +78,12 @@ bitmap_ip_del(struct bitmap_ip *map, uint32_t id)
 
 static int
 bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
-              enum ipset_adt adt, uint8_t pf, const uint8_t *flags)
+              enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
        struct bitmap_ip *map = set->data;
-       uint32_t ip = ntohl(ip4addr(skb, flags));
+       u32 ip;
        
-       if (pf != AF_INET)
-               return -EINVAL;
-
+       ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
        if (ip < map->first_ip || ip > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
 
@@ -113,12 +111,12 @@ bitmap_ip_adt_policy[IPSET_ATTR_ADT_MAX+1] __read_mostly = {
 
 static int
 bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
-              enum ipset_adt adt, uint32_t *lineno, uint32_t flags)
+              enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        struct bitmap_ip *map = set->data;
        struct nlattr *tb[IPSET_ATTR_ADT_MAX];
        bool eexist = flags & IPSET_FLAG_EXIST;
-       uint32_t ip, ip_to, id;
+       u32 ip, ip_to, id;
        int ret = 0;
 
        if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
@@ -133,6 +131,8 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
        if (ip < map->first_ip || ip > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
 
+       /* Set was defined without timeout support,
+        * don't ignore attribute silently */
        if (tb[IPSET_ATTR_TIMEOUT])
                return -IPSET_ERR_TIMEOUT;
 
@@ -147,10 +147,11 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
                                return -IPSET_ERR_BITMAP_RANGE;
                }
        } else if (tb[IPSET_ATTR_CIDR]) {
-               uint8_t cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+               u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
                
                if (cidr > 32)
                        return -IPSET_ERR_INVALID_CIDR;
+               ip &= HOSTMASK(cidr);
                ip_to = ip | ~HOSTMASK(cidr);
        } else
                ip_to = ip;
@@ -168,7 +169,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
                                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
                        return ret;
                }
-       };
+       }
        return ret;
 }
 
@@ -196,11 +197,6 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
 {
        const struct bitmap_ip *map = set->data;
        struct nlattr *nested;
-       uint32_t id, elements;
-
-       for (id = 0, elements = 0; id < map->elements; id++)
-               if (bitmap_ip_test(map, id)) 
-                       elements++;
 
        nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
        if (!nested)
@@ -209,10 +205,10 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
        NLA_PUT_NET32(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
        if (map->netmask != 32)
                NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
-       NLA_PUT_NET32(skb, IPSET_ATTR_ELEMENTS, htonl(elements));
        NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
                      htonl(atomic_read(&set->ref) - 1));
-       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(map->memsize));
+       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
+                     htonl(sizeof(*map) + map->memsize));
        ipset_nest_end(skb, nested);
        
        return 0;
@@ -226,7 +222,7 @@ bitmap_ip_list(struct ip_set *set,
 {
        const struct bitmap_ip *map = set->data;
        struct nlattr *atd, *nested;
-       uint32_t id, first = cb->args[2];
+       u32 id, first = cb->args[2];
 
        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
        if (!atd)
@@ -245,8 +241,6 @@ bitmap_ip_list(struct ip_set *set,
                }
                NLA_PUT_NET32(skb, IPSET_ATTR_IP,
                              htonl(map->first_ip + id * map->hosts));
-               if (map->netmask != 32)
-                       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, map->netmask);
                ipset_nest_end(skb, nested);
        }
        ipset_nest_end(skb, atd);
@@ -260,6 +254,17 @@ nla_put_failure:
        return 0;
 }
 
+static bool
+bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
+{
+       struct bitmap_ip *x = a->data;
+       struct bitmap_ip *y = b->data;
+       
+       return x->first_ip == y->first_ip
+              && x->last_ip == y->last_ip
+              && x->netmask == y->netmask;
+}
+
 static const struct ip_set_type_variant bitmap_ip __read_mostly = {
        .kadt   = bitmap_ip_kadt,
        .uadt   = bitmap_ip_uadt,
@@ -267,34 +272,35 @@ static const struct ip_set_type_variant bitmap_ip __read_mostly = {
        .flush  = bitmap_ip_flush,
        .head   = bitmap_ip_head,
        .list   = bitmap_ip_list,
+       .same_set = bitmap_ip_same_set,
 };
 
 /* Timeout variant */
 
 struct bitmap_ip_timeout {
        void *members;          /* the set members */
-       uint32_t first_ip;      /* host byte order, included in range */
-       uint32_t last_ip;       /* host byte order, included in range */
-       uint32_t elements;      /* number of max elements in the set */
-       uint32_t hosts;         /* number of hosts in a subnet */
+       u32 first_ip;           /* host byte order, included in range */
+       u32 last_ip;            /* host byte order, included in range */
+       u32 elements;           /* number of max elements in the set */
+       u32 hosts;              /* number of hosts in a subnet */
        size_t memsize;         /* members size */
-       uint8_t netmask;        /* subnet netmask */
+       u8 netmask;             /* subnet netmask */
 
-       uint32_t timeout;       /* timeout parameter */
+       u32 timeout;            /* timeout parameter */
        struct timer_list gc;   /* garbage collection */
 };
 
 static inline bool
-bitmap_ip_timeout_test(const struct bitmap_ip_timeout *map, uint32_t id)
+bitmap_ip_timeout_test(const struct bitmap_ip_timeout *map, u32 id)
 {
        unsigned long *table = map->members;
 
        return ip_set_timeout_test(table[id]);
 }
 
-static int
+static inline int
 bitmap_ip_timeout_add(struct bitmap_ip_timeout *map,
-                     uint32_t id, uint32_t timeout)
+                     u32 id, u32 timeout)
 {
        unsigned long *table = map->members;
 
@@ -306,8 +312,8 @@ bitmap_ip_timeout_add(struct bitmap_ip_timeout *map,
        return 0;
 }
 
-static int
-bitmap_ip_timeout_del(struct bitmap_ip_timeout *map, uint32_t id)
+static inline int
+bitmap_ip_timeout_del(struct bitmap_ip_timeout *map, u32 id)
 {
        unsigned long *table = map->members;
        int ret = -IPSET_ERR_EXIST;
@@ -321,14 +327,12 @@ bitmap_ip_timeout_del(struct bitmap_ip_timeout *map, uint32_t id)
 
 static int
 bitmap_ip_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
-                      enum ipset_adt adt, uint8_t pf, const uint8_t *flags)
+                      enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
        struct bitmap_ip_timeout *map = set->data;
-       uint32_t ip = ntohl(ip4addr(skb, flags));
-
-       if (pf != AF_INET)
-               return -EINVAL;
+       u32 ip;
 
+       ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
        if (ip < map->first_ip || ip > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
 
@@ -348,12 +352,12 @@ bitmap_ip_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
 
 static int
 bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
-                      enum ipset_adt adt, uint32_t *lineno, uint32_t flags)
+                      enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        struct bitmap_ip_timeout *map = set->data;
        struct nlattr *tb[IPSET_ATTR_ADT_MAX];
        bool eexist = flags & IPSET_FLAG_EXIST;
-       uint32_t ip, ip_to, id, timeout = map->timeout;
+       u32 ip, ip_to, id, timeout = map->timeout;
        int ret = 0;
 
        if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
@@ -380,10 +384,11 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
                                return -IPSET_ERR_BITMAP_RANGE;
                }
        } else if (tb[IPSET_ATTR_CIDR]) {
-               uint8_t cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+               u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
                
                if (cidr > 32)
                        return -IPSET_ERR_INVALID_CIDR;
+               ip &= HOSTMASK(cidr);
                ip_to = ip | ~HOSTMASK(cidr);
        } else
                ip_to = ip;
@@ -391,9 +396,8 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
        if (ip_to > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
        
-       if (tb[IPSET_ATTR_TIMEOUT]) {
-               timeout = ip_set_get_h32(tb[IPSET_ATTR_TIMEOUT]);
-       }
+       if (tb[IPSET_ATTR_TIMEOUT])
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 
        for (; !before(ip_to, ip); ip += map->hosts) {
                id = ip_to_id((const struct bitmap_ip *)map, ip);
@@ -414,11 +418,8 @@ static void
 bitmap_ip_timeout_destroy(struct ip_set *set)
 {
        struct bitmap_ip_timeout *map = set->data;
-
-       /* gc might be running: del_timer_sync can't be used */
-       while (!del_timer(&map->gc))
-               msleep(IPSET_DESTROY_TIMER_SLEEP);
-
+       
+       del_timer_sync(&map->gc);
        ip_set_free(map->members, set->flags);
        kfree(map);
        
@@ -438,11 +439,6 @@ bitmap_ip_timeout_head(struct ip_set *set, struct sk_buff *skb)
 {
        const struct bitmap_ip_timeout *map = set->data;
        struct nlattr *nested;
-       uint32_t id, elements;
-       
-       for (id = 0, elements = 0; id < map->elements; id++)
-               if (bitmap_ip_timeout_test(map, id))
-                       elements++;
        
        nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
        if (!nested)
@@ -452,10 +448,10 @@ bitmap_ip_timeout_head(struct ip_set *set, struct sk_buff *skb)
        if (map->netmask != 32)
                NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT , htonl(map->timeout));
-       NLA_PUT_NET32(skb, IPSET_ATTR_ELEMENTS, htonl(elements));
        NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
                      htonl(atomic_read(&set->ref) - 1));
-       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(map->memsize));
+       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
+                     htonl(sizeof(*map) + map->memsize));
        ipset_nest_end(skb, nested);
        
        return 0;
@@ -469,7 +465,7 @@ bitmap_ip_timeout_list(struct ip_set *set,
 {
        const struct bitmap_ip_timeout *map = set->data;
        struct nlattr *adt, *nested;
-       uint32_t id, first = cb->args[2];
+       u32 id, first = cb->args[2];
        unsigned long *table = map->members;
        
        adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
@@ -489,8 +485,6 @@ bitmap_ip_timeout_list(struct ip_set *set,
                }
                NLA_PUT_NET32(skb, IPSET_ATTR_IP,
                              htonl(map->first_ip + id * map->hosts));
-               if (map->netmask != 32)
-                       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, map->netmask);
                NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
                              htonl(ip_set_timeout_get(table[id])));
                ipset_nest_end(skb, nested);
@@ -508,6 +502,18 @@ nla_put_failure:
        return 0;
 }
 
+static bool
+bitmap_ip_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
+{
+       struct bitmap_ip_timeout *x = a->data;
+       struct bitmap_ip_timeout *y = b->data;
+       
+       return x->first_ip == y->first_ip
+              && x->last_ip == y->last_ip
+              && x->netmask == y->netmask
+              && x->timeout == y->timeout;
+}
+
 static const struct ip_set_type_variant bitmap_ip_timeout __read_mostly = {
        .kadt   = bitmap_ip_timeout_kadt,
        .uadt   = bitmap_ip_timeout_uadt,
@@ -515,15 +521,16 @@ static const struct ip_set_type_variant bitmap_ip_timeout __read_mostly = {
        .flush  = bitmap_ip_timeout_flush,
        .head   = bitmap_ip_timeout_head,
        .list   = bitmap_ip_timeout_list,
+       .same_set = bitmap_ip_timeout_same_set,
 };
 
 static void
-bitmap_ip_timeout_gc(unsigned long ul_set)
+bitmap_ip_gc(unsigned long ul_set)
 {
        struct ip_set *set = (struct ip_set *) ul_set;
        struct bitmap_ip_timeout *map = set->data;
        unsigned long *table = map->members;
-       uint32_t id;
+       u32 id;
 
        /* We run parallel with other readers (test element)
         * but adding/deleting new entries is locked out */
@@ -544,7 +551,7 @@ bitmap_ip_gc_init(struct ip_set *set)
 
        init_timer(&map->gc);
        map->gc.data = (unsigned long) set;
-       map->gc.function = bitmap_ip_timeout_gc;
+       map->gc.function = bitmap_ip_gc;
        map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
        add_timer(&map->gc);
 }
@@ -562,8 +569,8 @@ bitmap_ip_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
 
 static bool
 init_map_ip(struct ip_set *set, struct bitmap_ip *map,
-           uint32_t first_ip, uint32_t last_ip,
-           uint32_t elements, uint32_t hosts, uint8_t netmask)
+           u32 first_ip, u32 last_ip,
+           u32 elements, u32 hosts, u8 netmask)
 {
        map->members = ip_set_alloc(map->memsize, GFP_KERNEL, &set->flags);
        if (!map->members)
@@ -582,11 +589,11 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
 
 static int
 bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
-                uint32_t flags)
+                u32 flags)
 {
        struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
-       uint32_t first_ip, last_ip, hosts, elements;
-       uint8_t netmask = 32;
+       u32 first_ip, last_ip, hosts, elements;
+       u8 netmask = 32;
 
        if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
                      bitmap_ip_create_policy))
@@ -600,13 +607,13 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
        if (tb[IPSET_ATTR_IP_TO]) {
                last_ip = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]);
                if (first_ip > last_ip) {
-                       uint32_t tmp = first_ip;
+                       u32 tmp = first_ip;
                        
                        first_ip = last_ip;
                        last_ip = tmp;
                }
        } else if (tb[IPSET_ATTR_CIDR]) {
-               uint8_t cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+               u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
                
                if (cidr >= 32)
                        return -IPSET_ERR_INVALID_CIDR;
@@ -628,8 +635,8 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
                hosts = 1;
                elements = last_ip - first_ip + 1;
        } else {
-               uint8_t mask_bits;
-               uint32_t mask;
+               u8 mask_bits;
+               u32 mask;
 
                mask = range_to_mask(first_ip, last_ip, &mask_bits);
 
@@ -637,14 +644,14 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
                    || netmask <= mask_bits)
                        return -IPSET_ERR_BITMAP_RANGE;
 
-               D("mask_bits %u, netmask %u", mask_bits, netmask);
+               pr_debug("mask_bits %u, netmask %u", mask_bits, netmask);
                hosts = 2 << (32 - netmask - 1);
                elements = 2 << (netmask - mask_bits - 1);
        }
        if (elements > IPSET_BITMAP_MAX_RANGE + 1) {
                return -IPSET_ERR_BITMAP_RANGE_SIZE;
        }
-       D("hosts %u, elements %u", hosts, elements);
+       pr_debug("hosts %u, elements %u", hosts, elements);
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
                struct bitmap_ip_timeout *map;
@@ -662,8 +669,7 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
                        return -ENOMEM;
                }
 
-               map->timeout = ip_set_get_h32(tb[IPSET_ATTR_TIMEOUT]);
-               set->flags |= IP_SET_FLAG_TIMEOUT;
+               map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
                set->variant = &bitmap_ip_timeout;
                
                bitmap_ip_gc_init(set);
@@ -692,6 +698,7 @@ static struct ip_set_type bitmap_ip_type = {
        .name           = "bitmap:ip",
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_IP,
+       .dimension      = IPSET_DIM_ONE,
        .family         = AF_INET,
        .revision       = 0,
        .create         = bitmap_ip_create,
index 45335dd4e152a0b95a06031b73785663f229d8ea..d036862d381ed223b95824363040f6cdb1b0717e 100644 (file)
 
 /* Kernel module implementing an IP set type: the bitmap:ip,mac type */
 
+#include <linux/netfilter/ip_set_kernel.h>
 #include <linux/module.h>
 #include <linux/ip.h>
+#include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
@@ -19,7 +21,6 @@
 #include <linux/spinlock.h>
 #include <linux/if_ether.h>
 #include <linux/netlink.h>
-#include <linux/delay.h>
 #include <linux/jiffies.h>
 #include <linux/timer.h>
 #include <net/netlink.h>
@@ -40,119 +41,235 @@ enum {
        MAC_UNSET,              /* element is set, without MAC */
 };
 
-/* Member element without and with timeout */
+/* Type structure */
+struct bitmap_ipmac {
+       void *members;          /* the set members */
+       u32 first_ip;           /* host byte order, included in range */
+       u32 last_ip;            /* host byte order, included in range */
+       u32 timeout;            /* timeout value */
+       struct timer_list gc;   /* garbage collector */
+       size_t dsize;           /* size of element */
+};
 
 struct ipmac {
+       u32 id;                 /* id in array */
+       unsigned char *ether;   /* ethernet address */
+};
+
+/* Member element without and with timeout */
+
+struct ipmac_elem {
        unsigned char ether[ETH_ALEN];
        unsigned char match;
 };
 
-struct ipmac_timeout {
+struct ipmac_telem {
        unsigned char ether[ETH_ALEN];
        unsigned char match;
        unsigned long timeout;
 };
 
-struct bitmap_ipmac {
-       void *members;          /* the set members */
-       uint32_t first_ip;      /* host byte order, included in range */
-       uint32_t last_ip;       /* host byte order, included in range */
-       uint32_t timeout;       /* timeout value */
-       struct timer_list gc;   /* garbage collector */
-       size_t elem_size;       /* size of element */
-};
-
 static inline void *
-bitmap_ipmac_elem(const struct bitmap_ipmac *map, uint32_t id)
+bitmap_ipmac_elem(const struct bitmap_ipmac *map, u32 id)
 {
-       return (void *)((char *)map->members + id * map->elem_size);
+       return (void *)((char *)map->members + id * map->dsize);
 }
 
 static inline bool
-bitmap_timeout(const struct bitmap_ipmac *map, uint32_t id)
+bitmap_timeout(const struct bitmap_ipmac *map, u32 id)
 {
-       const struct ipmac_timeout *elem = bitmap_ipmac_elem(map, id);
+       const struct ipmac_telem *elem = bitmap_ipmac_elem(map, id);
 
        return ip_set_timeout_test(elem->timeout);
 }
 
 static inline bool
-bitmap_expired(const struct bitmap_ipmac *map, uint32_t id)
+bitmap_expired(const struct bitmap_ipmac *map, u32 id)
 {
-       const struct ipmac_timeout *elem = bitmap_ipmac_elem(map, id);
+       const struct ipmac_telem *elem = bitmap_ipmac_elem(map, id);
 
        return ip_set_timeout_expired(elem->timeout);
 }
 
 static inline int
-bitmap_ipmac_exist(const struct ipmac *elem, bool with_timeout)
+bitmap_ipmac_exist(const struct ipmac_telem *elem)
 {
-       const struct ipmac_timeout *e = (const struct ipmac_timeout *) elem;
-
        return elem->match == MAC_UNSET
               || (elem->match == MAC_FILLED
-                  && !(with_timeout && ip_set_timeout_expired(e->timeout)));
+                  && !ip_set_timeout_expired(elem->timeout));
 }
 
-static inline int
-bitmap_ipmac_test(const struct bitmap_ipmac *map, bool with_timeout,
-                 uint32_t id, const unsigned char *ether)
+/* Base variant */
+
+static int
+bitmap_ipmac_test(struct ip_set *set, void *value,
+                 gfp_t gfp_flags, u32 timeout)
 {
-       const struct ipmac *elem = bitmap_ipmac_elem(map, id);
+       const struct bitmap_ipmac *map = set->data;
+       const struct ipmac *data = value;
+       const struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
 
        switch (elem->match) {
        case MAC_UNSET:
                /* Trigger kernel to fill out the ethernet address */
                return -EAGAIN;
        case MAC_FILLED:
-               return (ether == NULL
-                       || memcmp(ether, elem->ether, ETH_ALEN) == 0)
-                      && (!with_timeout || bitmap_timeout(map, id));
+               return data->ether == NULL
+                      || compare_ether_addr(data->ether, elem->ether) == 0;
        }
        return 0;
 }
 
 static int
-bitmap_ipmac_add(struct bitmap_ipmac *map, bool with_timeout,
-                uint32_t id, const unsigned char *ether,
-                uint32_t timeout)
+bitmap_ipmac_add(struct ip_set *set, void *value,
+                gfp_t gfp_flags, u32 timeout)
 {
-       struct ipmac *elem = bitmap_ipmac_elem(map, id);
-       struct ipmac_timeout *e = (struct ipmac_timeout *) elem;
+       struct bitmap_ipmac *map = set->data;
+       const struct ipmac *data = value;
+       struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
 
        switch (elem->match) {
        case MAC_UNSET:
-               if (!ether)
+               if (!data->ether)
                        /* Already added without ethernet address */
                        return -IPSET_ERR_EXIST;
                /* Fill the MAC address and activate the timer */
-               memcpy(elem->ether, ether, ETH_ALEN);
+               memcpy(elem->ether, data->ether, ETH_ALEN);
                elem->match = MAC_FILLED;
-               if (with_timeout) {
-                       if (timeout == map->timeout)
-                               /* Timeout was not specified, get stored one */
-                               timeout = e->timeout;
-                       e->timeout = ip_set_timeout_set(timeout);
+               break;
+       case MAC_FILLED:
+               return -IPSET_ERR_EXIST;
+       case MAC_EMPTY:
+               if (data->ether) {
+                       memcpy(elem->ether, data->ether, ETH_ALEN);
+                       elem->match = MAC_FILLED;
+               } else
+                       elem->match = MAC_UNSET;
+       }
+
+       return 0;
+}
+
+static int
+bitmap_ipmac_del(struct ip_set *set, void *value,
+                gfp_t gfp_flags, u32 timeout)
+{
+       struct bitmap_ipmac *map = set->data;
+       const struct ipmac *data = value;
+       struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
+
+       if (elem->match == MAC_EMPTY)
+               return -IPSET_ERR_EXIST;
+
+       elem->match = MAC_EMPTY;
+
+       return 0;
+}
+
+static int
+bitmap_ipmac_list(struct ip_set *set,
+                 struct sk_buff *skb, struct netlink_callback *cb)
+{
+       const struct bitmap_ipmac *map = set->data;
+       const struct ipmac_elem *elem;
+       struct nlattr *atd, *nested;
+       u32 id, first = cb->args[2];
+       u32 last = map->last_ip - map->first_ip;
+
+       atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
+       if (!atd)
+               return -EFAULT;
+       for (; cb->args[2] <= last; cb->args[2]++) {
+               id = cb->args[2];
+               elem = bitmap_ipmac_elem(map, id);
+               if (elem->match == MAC_EMPTY)
+                       continue;
+               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+               if (!nested) {
+                       if (id == first) {
+                               nla_nest_cancel(skb, atd);
+                               return -EFAULT;
+                       } else
+                               goto nla_put_failure;
                }
+               NLA_PUT_NET32(skb, IPSET_ATTR_IP,
+                             htonl(map->first_ip + id));
+               if (elem->match == MAC_FILLED)
+                       NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN,
+                               elem->ether);
+               ipset_nest_end(skb, nested);
+       }
+       ipset_nest_end(skb, atd);
+       /* Set listing finished */
+       cb->args[2] = 0;
+       
+       return 0;
+
+nla_put_failure:
+       nla_nest_cancel(skb, nested);
+       ipset_nest_end(skb, atd);
+       return 0;
+}
+
+/* Timeout variant */
+
+static int
+bitmap_ipmac_ttest(struct ip_set *set, void *value,
+                  gfp_t gfp_flags, u32 timeout)
+{
+       const struct bitmap_ipmac *map = set->data;
+       const struct ipmac *data = value;
+       const struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
+
+       switch (elem->match) {
+       case MAC_UNSET:
+               /* Trigger kernel to fill out the ethernet address */
+               return -EAGAIN;
+       case MAC_FILLED:
+               return (data->ether == NULL
+                       || compare_ether_addr(data->ether, elem->ether) == 0)
+                      && !bitmap_expired(map, data->id);
+       }
+       return 0;
+}
+
+static int
+bitmap_ipmac_tadd(struct ip_set *set, void *value,
+                 gfp_t gfp_flags, u32 timeout)
+{
+       struct bitmap_ipmac *map = set->data;
+       const struct ipmac *data = value;
+       struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
+
+       switch (elem->match) {
+       case MAC_UNSET:
+               if (!data->ether)
+                       /* Already added without ethernet address */
+                       return -IPSET_ERR_EXIST;
+               /* Fill the MAC address and activate the timer */
+               memcpy(elem->ether, data->ether, ETH_ALEN);
+               elem->match = MAC_FILLED;
+               if (timeout == map->timeout)
+                       /* Timeout was not specified, get stored one */
+                       timeout = elem->timeout;
+               elem->timeout = ip_set_timeout_set(timeout);
                break;
        case MAC_FILLED:
-               if (!(with_timeout && bitmap_expired(map, id)))
+               if (bitmap_expired(map, data->id))
                        return -IPSET_ERR_EXIST;
                /* Fall through */
        case MAC_EMPTY:
-               if (ether) {
-                       memcpy(elem->ether, ether, ETH_ALEN);
+               if (data->ether) {
+                       memcpy(elem->ether, data->ether, ETH_ALEN);
                        elem->match = MAC_FILLED;
                } else
                        elem->match = MAC_UNSET;
-               if (with_timeout) {
-                       /* If MAC is unset yet, we store plain timeout
-                        * because the timer is not activated yet
-                        * and we can reuse it later when MAC is filled out,
-                        * possibly by the kernel */
-                       e->timeout = ether ? ip_set_timeout_set(timeout)
-                                          : timeout;
-               }
+               /* If MAC is unset yet, we store plain timeout
+                * because the timer is not activated yet
+                * and we can reuse it later when MAC is filled out,
+                * possibly by the kernel */
+               elem->timeout = data->ether ? ip_set_timeout_set(timeout)
+                                           : timeout;
                break;
        }
 
@@ -160,13 +277,14 @@ bitmap_ipmac_add(struct bitmap_ipmac *map, bool with_timeout,
 }
 
 static int
-bitmap_ipmac_del(struct bitmap_ipmac *map, bool with_timeout,
-                uint32_t id)
+bitmap_ipmac_tdel(struct ip_set *set, void *value,
+                 gfp_t gfp_flags, u32 timeout)
 {
-       struct ipmac *elem = bitmap_ipmac_elem(map, id);
+       struct bitmap_ipmac *map = set->data;
+       const struct ipmac *data = value;
+       struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
 
-       if (elem->match == MAC_EMPTY
-           || (with_timeout && bitmap_expired(map, id)))
+       if (elem->match == MAC_EMPTY || bitmap_expired(map, data->id))
                return -IPSET_ERR_EXIST;
 
        elem->match = MAC_EMPTY;
@@ -174,39 +292,75 @@ bitmap_ipmac_del(struct bitmap_ipmac *map, bool with_timeout,
        return 0;
 }
 
+static int
+bitmap_ipmac_tlist(struct ip_set *set,
+                  struct sk_buff *skb, struct netlink_callback *cb)
+{
+       const struct bitmap_ipmac *map = set->data;
+       const struct ipmac_telem *elem;
+       struct nlattr *atd, *nested;
+       u32 id, first = cb->args[2];
+       u32 timeout, last = map->last_ip - map->first_ip;
+
+       atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
+       if (!atd)
+               return -EFAULT;
+       for (; cb->args[2] <= last; cb->args[2]++) {
+               id = cb->args[2];
+               elem = bitmap_ipmac_elem(map, id);
+               if (!bitmap_ipmac_exist(elem)) 
+                       continue;
+               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+               if (!nested) {
+                       if (id == first) {
+                               nla_nest_cancel(skb, atd);
+                               return -EFAULT;
+                       } else
+                               goto nla_put_failure;
+               }
+               NLA_PUT_NET32(skb, IPSET_ATTR_IP,
+                             htonl(map->first_ip + id));
+               if (elem->match == MAC_FILLED)
+                       NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN,
+                               elem->ether);
+               timeout = elem->match == MAC_UNSET ? elem->timeout
+                               : ip_set_timeout_get(elem->timeout);
+               NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(timeout));
+               ipset_nest_end(skb, nested);
+       }
+       ipset_nest_end(skb, atd);
+       /* Set listing finished */
+       cb->args[2] = 0;
+       
+       return 0;
+
+nla_put_failure:
+       nla_nest_cancel(skb, nested);
+       ipset_nest_end(skb, atd);
+       return 0;
+}
+
 static int
 bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
-                 enum ipset_adt adt, uint8_t pf, const uint8_t *flags)
+                 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
        struct bitmap_ipmac *map = set->data;
-       uint32_t ip = ntohl(ip4addr(skb, flags));
-       bool with_timeout = set->flags & IP_SET_FLAG_TIMEOUT;
-
-       if (pf != AF_INET)
-               return -EINVAL;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct ipmac data;
 
-       if (ip < map->first_ip || ip > map->last_ip)
+       data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
+       if (data.id < map->first_ip || data.id > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
 
+       /* Backward compatibility: we don't check the second flag */
        if (skb_mac_header(skb) < skb->head
            || (skb_mac_header(skb) + ETH_HLEN) > skb->data)
                return -EINVAL;
 
-       ip -= map->first_ip;
-
-       switch (adt) {
-       case IPSET_TEST:
-               return bitmap_ipmac_test(map, with_timeout,
-                                        ip, eth_hdr(skb)->h_source);
-       case IPSET_ADD:
-               return bitmap_ipmac_add(map, with_timeout,
-                                       ip, eth_hdr(skb)->h_source,
-                                       map->timeout);
-       case IPSET_DEL:
-               return bitmap_ipmac_del(map, with_timeout, ip);
-       default:
-               return -EINVAL;
-       }
+       data.id -= map->first_ip;
+       data.ether = eth_hdr(skb)->h_source;
+
+       return adtfn(set, &data, GFP_ATOMIC, map->timeout);
 }
 
 static const struct nla_policy
@@ -218,14 +372,14 @@ bitmap_ipmac_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
 
 static int
 bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *head, int len,
-                 enum ipset_adt adt, uint32_t *lineno, uint32_t flags)
+                 enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        struct bitmap_ipmac *map = set->data;
        struct nlattr *tb[IPSET_ATTR_ADT_MAX];
+       ipset_adtfn adtfn = set->variant->adt[adt];
        bool eexist = flags & IPSET_FLAG_EXIST;
-       bool with_timeout = set->flags & IP_SET_FLAG_TIMEOUT;
-       uint32_t ip, timeout = map->timeout;
-       unsigned char *ether = NULL;
+       struct ipmac data;
+       u32 timeout = map->timeout;
        int ret = 0;
 
        if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
@@ -233,35 +387,31 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *head, int len,
                return -IPSET_ERR_PROTOCOL;
 
        if (tb[IPSET_ATTR_IP])
-               ip = ip_set_get_h32(tb[IPSET_ATTR_IP]);
+               data.id = ip_set_get_h32(tb[IPSET_ATTR_IP]);
        else
                return -IPSET_ERR_PROTOCOL;
 
-       if (ip < map->first_ip || ip > map->last_ip)
+       if (data.id < map->first_ip || data.id > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
 
        if (tb[IPSET_ATTR_ETHER])
-               ether = nla_data(tb[IPSET_ATTR_ETHER]);
+               data.ether = nla_data(tb[IPSET_ATTR_ETHER]);
+       else
+               data.ether = NULL;
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
-               if (!with_timeout)
+               if (!with_timeout(map->timeout))
                        return -IPSET_ERR_TIMEOUT;
-               timeout = ip_set_get_h32(tb[IPSET_ATTR_TIMEOUT]);
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       ip -= map->first_ip;
-
-       if (adt == IPSET_TEST)
-               return bitmap_ipmac_test(map, with_timeout, ip, ether);
+       data.id -= map->first_ip;
 
-       ret = adt == IPSET_ADD ? bitmap_ipmac_add(map, with_timeout,
-                                                 ip, ether, timeout)
-                              : bitmap_ipmac_del(map, with_timeout, ip);
+       ret = adtfn(set, &data, GFP_KERNEL, timeout);
 
        if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
                if (tb[IPSET_ATTR_LINENO])
                        *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
-               return ret;
        }
        return ret;
 }
@@ -271,10 +421,8 @@ bitmap_ipmac_destroy(struct ip_set *set)
 {
        struct bitmap_ipmac *map = set->data;
 
-       /* gc might be running: del_timer_sync can't be used */
-       if (set->flags & IP_SET_FLAG_TIMEOUT)
-               while (!del_timer(&map->gc))
-                       msleep(IPSET_DESTROY_TIMER_SLEEP);
+       if (with_timeout(map->timeout))
+               del_timer_sync(&map->gc);
        
        ip_set_free(map->members, set->flags);
        kfree(map);
@@ -288,7 +436,7 @@ bitmap_ipmac_flush(struct ip_set *set)
        struct bitmap_ipmac *map = set->data;
        
        memset(map->members, 0,
-              (map->last_ip - map->first_ip + 1) * map->elem_size);
+              (map->last_ip - map->first_ip + 1) * map->dsize);
 }
 
 static int
@@ -296,28 +444,18 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb)
 {
        const struct bitmap_ipmac *map = set->data;
        struct nlattr *nested;
-       const struct ipmac *elem;
-       uint32_t id, elements = 0, last = map->last_ip - map->first_ip;
-       bool with_timeout = set->flags & IP_SET_FLAG_TIMEOUT;
-
-       for (id = 0; id <= last; id++) {
-               elem = bitmap_ipmac_elem(map, id);
-               if (bitmap_ipmac_exist(elem, with_timeout))
-                       elements++;
-       }
 
        nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
        if (!nested)
                goto nla_put_failure;
        NLA_PUT_NET32(skb, IPSET_ATTR_IP, htonl(map->first_ip));
        NLA_PUT_NET32(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
-       NLA_PUT_NET32(skb, IPSET_ATTR_ELEMENTS, htonl(elements));
        NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
                      htonl(atomic_read(&set->ref) - 1));
        NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
-                     htonl((map->last_ip - map->first_ip + 1)
-                           * map->elem_size));
-       if (with_timeout)
+                     htonl(sizeof(*map)
+                          + (map->last_ip - map->first_ip + 1) * map->dsize));
+       if (with_timeout(map->timeout))
                NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
        ipset_nest_end(skb, nested);
        
@@ -326,77 +464,54 @@ nla_put_failure:
        return -EFAULT;
 }
 
-static int
-bitmap_ipmac_list(struct ip_set *set,
-                 struct sk_buff *skb, struct netlink_callback *cb)
+static bool
+bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)
 {
-       const struct bitmap_ipmac *map = set->data;
-       const struct ipmac *elem;
-       struct nlattr *atd, *nested;
-       uint32_t id, first = cb->args[2];
-       uint32_t last = map->last_ip - map->first_ip;
-       bool with_timeout = set->flags & IP_SET_FLAG_TIMEOUT;
-
-       atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
-       if (!atd)
-               return -EFAULT;
-       for (; cb->args[2] <= last; cb->args[2]++) {
-               id = cb->args[2];
-               elem = bitmap_ipmac_elem(map, id);
-               if (!bitmap_ipmac_exist(elem, with_timeout)) 
-                       continue;
-               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
-               if (!nested) {
-                       if (id == first) {
-                               nla_nest_cancel(skb, atd);
-                               return -EFAULT;
-                       } else
-                               goto nla_put_failure;
-               }
-               NLA_PUT_NET32(skb, IPSET_ATTR_IP,
-                             htonl(map->first_ip + id));
-               if (elem->match == MAC_FILLED)
-                       NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN,
-                               elem->ether);
-               if (with_timeout) {
-                       const struct ipmac_timeout *e =
-                               (const struct ipmac_timeout *)elem;
-                       uint32_t timeout = e->match == MAC_UNSET ? e->timeout
-                                       : ip_set_timeout_get(e->timeout);
+       struct bitmap_ipmac *x = a->data;
+       struct bitmap_ipmac *y = b->data;
        
-                       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
-                                     htonl(timeout));
-               }
-               ipset_nest_end(skb, nested);
-       }
-       ipset_nest_end(skb, atd);
-       /* Set listing finished */
-       cb->args[2] = 0;
-       
-       return 0;
-
-nla_put_failure:
-       nla_nest_cancel(skb, nested);
-       ipset_nest_end(skb, atd);
-       return 0;
+       return x->first_ip == y->first_ip
+              && x->last_ip == y->last_ip
+              && x->timeout == y->timeout;
 }
 
 const struct ip_set_type_variant bitmap_ipmac __read_mostly = {
        .kadt   = bitmap_ipmac_kadt,
        .uadt   = bitmap_ipmac_uadt,
+       .adt    = {
+               [IPSET_ADD] = bitmap_ipmac_add,
+               [IPSET_DEL] = bitmap_ipmac_del,
+               [IPSET_TEST] = bitmap_ipmac_test,
+       },
        .destroy = bitmap_ipmac_destroy,
        .flush  = bitmap_ipmac_flush,
        .head   = bitmap_ipmac_head,
        .list   = bitmap_ipmac_list,
+       .same_set = bitmap_ipmac_same_set,
+};
+
+const struct ip_set_type_variant bitmap_tipmac __read_mostly = {
+       .kadt   = bitmap_ipmac_kadt,
+       .uadt   = bitmap_ipmac_uadt,
+       .adt    = {
+               [IPSET_ADD] = bitmap_ipmac_tadd,
+               [IPSET_DEL] = bitmap_ipmac_tdel,
+               [IPSET_TEST] = bitmap_ipmac_ttest,
+       },
+       .destroy = bitmap_ipmac_destroy,
+       .flush  = bitmap_ipmac_flush,
+       .head   = bitmap_ipmac_head,
+       .list   = bitmap_ipmac_tlist,
+       .same_set = bitmap_ipmac_same_set,
 };
 
 static void
-bitmap_ipmac_timeout_gc(unsigned long ul_set)
+bitmap_ipmac_gc(unsigned long ul_set)
 {
        struct ip_set *set = (struct ip_set *) ul_set;
        struct bitmap_ipmac *map = set->data;
-       struct ipmac_timeout *elem;
-       uint32_t id, last = map->last_ip - map->first_ip;
+       struct ipmac_telem *elem;
+       u32 id, last = map->last_ip - map->first_ip;
        
        /* We run parallel with other readers (test element)
         * but adding/deleting new entries is locked out */
@@ -414,13 +529,13 @@ bitmap_ipmac_timeout_gc(unsigned long ul_set)
 }
 
 static inline void
-bitmap_ipmac_timeout_gc_init(struct ip_set *set)
+bitmap_ipmac_gc_init(struct ip_set *set)
 {
        struct bitmap_ipmac *map = set->data;
 
        init_timer(&map->gc);
        map->gc.data = (unsigned long) set;
-       map->gc.function = bitmap_ipmac_timeout_gc;
+       map->gc.function = bitmap_ipmac_gc;
        map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
        add_timer(&map->gc);
 }
@@ -436,14 +551,15 @@ bitmap_ipmac_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
 
 static bool
 init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
-              uint32_t first_ip, uint32_t last_ip)
+              u32 first_ip, u32 last_ip)
 {
-       map->members = ip_set_alloc((last_ip - first_ip + 1) * map->elem_size,
+       map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize,
                                    GFP_KERNEL, &set->flags);
        if (!map->members)
                return false;
        map->first_ip = first_ip;
        map->last_ip = last_ip;
+       map->timeout = IPSET_NO_TIMEOUT;
 
        set->data = map;
        set->family = AF_INET;
@@ -453,10 +569,10 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
 
 static int
 bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
-                   uint32_t flags)
+                   u32 flags)
 {
        struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
-       uint32_t first_ip, last_ip, elements;
+       u32 first_ip, last_ip, elements;
        struct bitmap_ipmac *map;
 
        if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
@@ -471,13 +587,13 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
        if (tb[IPSET_ATTR_IP_TO]) {
                last_ip = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]);
                if (first_ip > last_ip) {
-                       uint32_t tmp = first_ip;
+                       u32 tmp = first_ip;
                        
                        first_ip = last_ip;
                        last_ip = tmp;
                }
        } else if (tb[IPSET_ATTR_CIDR]) {
-               uint8_t cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+               u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
                
                if (cidr >= 32)
                        return -IPSET_ERR_INVALID_CIDR;
@@ -490,31 +606,32 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
        if (elements > IPSET_BITMAP_MAX_RANGE + 1)
                return -IPSET_ERR_BITMAP_RANGE_SIZE;
 
-       set->variant = &bitmap_ipmac;
-               
        map = kzalloc(sizeof(*map), GFP_KERNEL);
        if (!map)
                return -ENOMEM;
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
-               map->elem_size = sizeof(struct ipmac_timeout);
+               map->dsize = sizeof(struct ipmac_telem);
                               
                if (!init_map_ipmac(set, map, first_ip, last_ip)) {
                        kfree(map);
                        return -ENOMEM;
                }
 
-               map->timeout = ip_set_get_h32(tb[IPSET_ATTR_TIMEOUT]);
-               set->flags |= IP_SET_FLAG_TIMEOUT;
+               map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
                
-               bitmap_ipmac_timeout_gc_init(set);
+               set->variant = &bitmap_tipmac;          
+
+               bitmap_ipmac_gc_init(set);
        } else {                
-               map->elem_size = sizeof(struct ipmac);
+               map->dsize = sizeof(struct ipmac_elem);
 
                if (!init_map_ipmac(set, map, first_ip, last_ip)) {
                        kfree(map);
                        return -ENOMEM;
                }
+               set->variant = &bitmap_ipmac;
+               
        }
        return 0;
 }
@@ -522,7 +639,8 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
 struct ip_set_type bitmap_ipmac_type = {
        .name           = "bitmap:ip,mac",
        .protocol       = IPSET_PROTOCOL,
-       .features       = IPSET_TYPE_IP,
+       .features       = IPSET_TYPE_IP | IPSET_TYPE_MAC,
+       .dimension      = IPSET_DIM_TWO,
        .family         = AF_INET,
        .revision       = 0,
        .create         = bitmap_ipmac_create,
index 3afd0312eae78a6648107f00c6f4bc26e77139f8..f3e498a4a66d6fd7b2e35e920229c56364d3f458 100644 (file)
@@ -7,6 +7,7 @@
 
 /* Kernel module implementing an IP set type: the bitmap:port type */
 
+#include <linux/netfilter/ip_set_kernel.h>
 #include <linux/module.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
@@ -17,7 +18,6 @@
 #include <asm/bitops.h>
 #include <linux/spinlock.h>
 #include <linux/netlink.h>
-#include <linux/delay.h>
 #include <linux/jiffies.h>
 #include <linux/timer.h>
 #include <net/netlink.h>
@@ -38,19 +38,19 @@ MODULE_ALIAS("ip_set_bitmap:port");
 
 struct bitmap_port {
        void *members;          /* the set members */
-       uint16_t first_port;    /* host byte order, included in range */
-       uint16_t last_port;     /* host byte order, included in range */
+       u16 first_port;         /* host byte order, included in range */
+       u16 last_port;          /* host byte order, included in range */
        size_t memsize;         /* members size */
 };
 
 static inline int
-bitmap_port_test(const struct bitmap_port *map, uint16_t id)
+bitmap_port_test(const struct bitmap_port *map, u16 id)
 {
        return !!test_bit(id, map->members);
 }
 
 static inline int
-bitmap_port_add(struct bitmap_port *map, uint16_t id)
+bitmap_port_add(struct bitmap_port *map, u16 id)
 {
        if (test_and_set_bit(id, map->members))
                return -IPSET_ERR_EXIST;
@@ -59,7 +59,7 @@ bitmap_port_add(struct bitmap_port *map, uint16_t id)
 }
 
 static int
-bitmap_port_del(struct bitmap_port *map, uint16_t id)
+bitmap_port_del(struct bitmap_port *map, u16 id)
 {
        if (!test_and_clear_bit(id, map->members))
                return -IPSET_ERR_EXIST;
@@ -69,13 +69,13 @@ bitmap_port_del(struct bitmap_port *map, uint16_t id)
 
 static int
 bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
-                enum ipset_adt adt, uint8_t pf, const uint8_t *flags)
+                enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
        struct bitmap_port *map = set->data;
-       uint32_t port = get_port(pf, skb, flags);
-       
-       if (port == IPSET_INVALID_PORT)
-               return 0;
+       u16 port;
+
+       if (!get_port(pf, skb, flags & IPSET_DIM_ONE_SRC, &port))
+               return -EINVAL;
        
        port = ntohs(port);
 
@@ -105,13 +105,13 @@ bitmap_port_adt_policy[IPSET_ATTR_ADT_MAX+1] __read_mostly = {
 
 static int
 bitmap_port_uadt(struct ip_set *set, struct nlattr *head, int len,
-                enum ipset_adt adt, uint32_t *lineno, uint32_t flags)
+                enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        struct bitmap_port *map = set->data;
        struct nlattr *tb[IPSET_ATTR_ADT_MAX];
        bool eexist = flags & IPSET_FLAG_EXIST;
-       uint32_t port;
-       uint16_t id, port_to;
+       u32 port;       /* wraparound */
+       u16 id, port_to;
        int ret = 0;
 
        if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
@@ -183,22 +183,16 @@ bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
 {
        struct bitmap_port *map = set->data;
        struct nlattr *nested;
-       uint32_t id;
-       uint16_t elements, last = map->last_port - map->first_port;
-
-       for (id = 0, elements = 0; id <= last; id++)
-               if (test_bit(id, map->members)) 
-                       elements++;
 
        nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
        if (!nested)
                goto nla_put_failure;
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port));
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
-       NLA_PUT_NET32(skb, IPSET_ATTR_ELEMENTS, htonl(elements));
        NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
                      htonl(atomic_read(&set->ref) - 1));
-       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(map->memsize));
+       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
+                     htonl(sizeof(*map) + map->memsize));
        ipset_nest_end(skb, nested);
        
        return 0;
@@ -212,8 +206,8 @@ bitmap_port_list(struct ip_set *set,
 {
        struct bitmap_port *map = set->data;
        struct nlattr *atd, *nested;
-       uint16_t id, first = cb->args[2];
-       uint16_t last = map->last_port - map->first_port;
+       u16 id, first = cb->args[2];
+       u16 last = map->last_port - map->first_port;
 
        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
        if (!atd)
@@ -246,6 +240,16 @@ nla_put_failure:
        return 0;
 }
 
+static bool
+bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
+{
+       struct bitmap_port *x = a->data;
+       struct bitmap_port *y = b->data;
+       
+       return x->first_port == y->first_port
+              && x->last_port == y->last_port;
+}
+
 const struct ip_set_type_variant bitmap_port __read_mostly = {
        .kadt   = bitmap_port_kadt,
        .uadt   = bitmap_port_uadt,
@@ -253,22 +257,23 @@ const struct ip_set_type_variant bitmap_port __read_mostly = {
        .flush  = bitmap_port_flush,
        .head   = bitmap_port_head,
        .list   = bitmap_port_list,
+       .same_set = bitmap_port_same_set,
 };
 
 /* Timeout variant */
 
 struct bitmap_port_timeout {
        void *members;          /* the set members */
-       uint16_t first_port;    /* host byte order, included in range */
-       uint16_t last_port;     /* host byte order, included in range */
+       u16 first_port;         /* host byte order, included in range */
+       u16 last_port;          /* host byte order, included in range */
        size_t memsize;         /* members size */
 
-       uint32_t timeout;       /* timeout parameter */
+       u32 timeout;            /* timeout parameter */
        struct timer_list gc;   /* garbage collection */
 };
 
 static inline bool
-bitmap_port_timeout_test(const struct bitmap_port_timeout *map, uint16_t id)
+bitmap_port_timeout_test(const struct bitmap_port_timeout *map, u16 id)
 {
        unsigned long *timeout = map->members;
 
@@ -277,7 +282,7 @@ bitmap_port_timeout_test(const struct bitmap_port_timeout *map, uint16_t id)
 
 static int
 bitmap_port_timeout_add(const struct bitmap_port_timeout *map,
-                       uint16_t id, uint32_t timeout)
+                       u16 id, u32 timeout)
 {
        unsigned long *table = map->members;
 
@@ -291,7 +296,7 @@ bitmap_port_timeout_add(const struct bitmap_port_timeout *map,
 
 static int
 bitmap_port_timeout_del(const struct bitmap_port_timeout *map,
-                       uint16_t id)
+                       u16 id)
 {
        unsigned long *table = map->members;
        int ret = -IPSET_ERR_EXIST;
@@ -305,13 +310,13 @@ bitmap_port_timeout_del(const struct bitmap_port_timeout *map,
 
 static int
 bitmap_port_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
-                        enum ipset_adt adt, uint8_t pf, const uint8_t *flags)
+                        enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
        struct bitmap_port_timeout *map = set->data;
-       uint32_t port = get_port(pf, skb, flags);
-       
-       if (port == IPSET_INVALID_PORT)
-               return 0;
+       u16 port;
+
+       if (!get_port(pf, skb, flags & IPSET_DIM_ONE_SRC, &port))
+               return -EINVAL;
 
        port = ntohs(port);
 
@@ -334,13 +339,13 @@ bitmap_port_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
 
 static int
 bitmap_port_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
-                        enum ipset_adt adt, uint32_t *lineno, uint32_t flags)
+                        enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct bitmap_port_timeout *map = set->data;
        struct nlattr *tb[IPSET_ATTR_ADT_MAX];
        bool eexist = flags & IPSET_FLAG_EXIST;
-       uint16_t port_to, id;
-       uint32_t port, timeout = map->timeout;
+       u16 id, port_to;
+       u32 port, timeout = map->timeout;       /* wraparound */
        int ret = 0;
 
        if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
@@ -372,7 +377,7 @@ bitmap_port_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
                return -IPSET_ERR_BITMAP_RANGE;
 
        if (tb[IPSET_ATTR_TIMEOUT])
-               timeout = ip_set_get_h32(tb[IPSET_ATTR_TIMEOUT]);
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        
        for (; port <= port_to; port++) {
                id = port - map->first_port;
@@ -394,10 +399,7 @@ bitmap_port_timeout_destroy(struct ip_set *set)
 {
        struct bitmap_port_timeout *map = set->data;
 
-       /* gc might be running: del_timer_sync can't be used */
-       while (!del_timer(&map->gc))
-               msleep(IPSET_DESTROY_TIMER_SLEEP);
-
+       del_timer_sync(&map->gc);
        ip_set_free(map->members, set->flags);
        kfree(map);
        
@@ -417,23 +419,17 @@ bitmap_port_timeout_head(struct ip_set *set, struct sk_buff *skb)
 {
        struct bitmap_port_timeout *map = set->data;
        struct nlattr *nested;
-       uint32_t id;
-       uint16_t elements, last = map->last_port - map->first_port;
-       
-       for (id = 0, elements = 0; id <= last; id++)
-               if (bitmap_port_timeout_test(map, id))
-                       elements++;
-       
+
        nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
        if (!nested)
                goto nla_put_failure;
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port));
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT , htonl(map->timeout));
-       NLA_PUT_NET32(skb, IPSET_ATTR_ELEMENTS, htonl(elements));
        NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
                      htonl(atomic_read(&set->ref) - 1));
-       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(map->memsize));
+       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
+                     htonl(sizeof(*map) + map->memsize));
        ipset_nest_end(skb, nested);
        
        return 0;
@@ -447,8 +443,8 @@ bitmap_port_timeout_list(struct ip_set *set,
 {
        struct bitmap_port_timeout *map = set->data;
        struct nlattr *adt, *nested;
-       uint16_t id, first = cb->args[2];
-       uint16_t last = map->last_port - map->first_port;
+       u16 id, first = cb->args[2];
+       u16 last = map->last_port - map->first_port;
        unsigned long *table = map->members;
        
        adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
@@ -485,6 +481,17 @@ nla_put_failure:
        return 0;
 }
 
+static bool
+bitmap_port_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
+{
+       struct bitmap_port_timeout *x = a->data;
+       struct bitmap_port_timeout *y = b->data;
+       
+       return x->first_port == y->first_port
+              && x->last_port == y->last_port
+              && x->timeout == y->timeout;
+}
+
 const struct ip_set_type_variant bitmap_port_timeout __read_mostly = {
        .kadt   = bitmap_port_timeout_kadt,
        .uadt   = bitmap_port_timeout_uadt,
@@ -492,15 +499,17 @@ const struct ip_set_type_variant bitmap_port_timeout __read_mostly = {
        .flush  = bitmap_port_timeout_flush,
        .head   = bitmap_port_timeout_head,
        .list   = bitmap_port_timeout_list,
+       .same_set = bitmap_port_timeout_same_set,
 };
 
 static void
-bitmap_port_timeout_gc(unsigned long ul_set)
+bitmap_port_gc(unsigned long ul_set)
 {
        struct ip_set *set = (struct ip_set *) ul_set;
        struct bitmap_port_timeout *map = set->data;
        unsigned long *table = map->members;
-       uint16_t id, last = map->last_port - map->first_port;
+       u32 id; /* wraparound */
+       u16 last = map->last_port - map->first_port;
        
        /* We run parallel with other readers (test element)
         * but adding/deleting new entries is locked out */
@@ -515,13 +524,13 @@ bitmap_port_timeout_gc(unsigned long ul_set)
 }
 
 static inline void
-bitmap_port_timeout_gc_init(struct ip_set *set)
+bitmap_port_gc_init(struct ip_set *set)
 {
        struct bitmap_port_timeout *map = set->data;
 
        init_timer(&map->gc);
        map->gc.data = (unsigned long) set;
-       map->gc.function = bitmap_port_timeout_gc;
+       map->gc.function = bitmap_port_gc;
        map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
        add_timer(&map->gc);
 }
@@ -537,7 +546,7 @@ bitmap_port_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
 
 static bool
 init_map_port(struct ip_set *set, struct bitmap_port *map,
-             uint16_t first_port, uint16_t last_port)
+             u16 first_port, u16 last_port)
 {
        map->members = ip_set_alloc(map->memsize, GFP_KERNEL, &set->flags);
        if (!map->members)
@@ -553,10 +562,10 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
 
 static int
 bitmap_port_create(struct ip_set *set, struct nlattr *head, int len,
-                uint32_t flags)
+                u32 flags)
 {
        struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
-       uint16_t first_port, last_port;
+       u16 first_port, last_port;
 
        if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
                      bitmap_port_create_policy))
@@ -570,7 +579,7 @@ bitmap_port_create(struct ip_set *set, struct nlattr *head, int len,
        if (tb[IPSET_ATTR_PORT_TO]) {
                last_port = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
                if (first_port > last_port) {
-                       uint16_t tmp = first_port;
+                       u16 tmp = first_port;
                        
                        first_port = last_port;
                        last_port = tmp;
@@ -594,11 +603,10 @@ bitmap_port_create(struct ip_set *set, struct nlattr *head, int len,
                        return -ENOMEM;
                }
 
-               map->timeout = ip_set_get_h32(tb[IPSET_ATTR_TIMEOUT]);
-               set->flags |= IP_SET_FLAG_TIMEOUT;
+               map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
                set->variant = &bitmap_port_timeout;
                
-               bitmap_port_timeout_gc_init(set);
+               bitmap_port_gc_init(set);
        } else {
                struct bitmap_port *map;
                
@@ -607,7 +615,7 @@ bitmap_port_create(struct ip_set *set, struct nlattr *head, int len,
                        return -ENOMEM;
 
                map->memsize = bitmap_bytes(0, last_port - first_port);
-               D("memsize: %zu", map->memsize);
+               pr_debug("memsize: %zu", map->memsize);
                if (!init_map_port(set, map, first_port, last_port)) {
                        kfree(map);
                        return -ENOMEM;
@@ -622,6 +630,7 @@ struct ip_set_type bitmap_port_type = {
        .name           = "bitmap:port",
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_PORT,
+       .dimension      = IPSET_DIM_ONE,
        .family         = AF_UNSPEC,
        .revision       = 0,
        .create         = bitmap_port_create,
index d99c99b4dbc3eb70c5deacdd7bc013e7d0f1fbe8..e5ce6a42428ec38d2d067d4f894855d1fe660ba4 100644 (file)
@@ -7,6 +7,8 @@
 
 /* Kernel module implementing an IP set type: the hash:ip type */
 
+#include <linux/netfilter/ip_set_kernel.h>
+#include <linux/netfilter/ip_set_jhash.h>
 #include <linux/module.h>
 #include <linux/ip.h>
 #include <linux/skbuff.h>
@@ -19,6 +21,7 @@
 #include <net/ipv6.h>
 #include <net/netlink.h>
 #include <net/pfxlen.h>
+#include <net/tcp.h>
 
 #include <linux/netfilter.h>
 #include <linux/netfilter/ip_set.h>
@@ -30,213 +33,125 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
 MODULE_DESCRIPTION("hash:ip type of IP sets");
 MODULE_ALIAS("ip_set_hash:ip");
 
-/* Member elements without timeout */
-struct ip4_elem {
-       uint32_t ip;
-};
+/* Type specific function prefix */
+#define TYPE           hash_ip
 
-struct ip6_elem {
-       union nf_inet_addr ip;
-};
+static bool
+hash_ip_same_set(const struct ip_set *a, const struct ip_set *b);
 
-/* Member elements with timeout support */
-struct ip4_elem_timeout {
-       uint32_t ip;
-       unsigned long timeout;
-};
+#define hash_ip4_same_set      hash_ip_same_set
+#define hash_ip6_same_set      hash_ip_same_set
 
-struct ip6_elem_timeout {
-       union nf_inet_addr ip;
-       unsigned long timeout;
-};
+/* The type variant functions: IPv4 */
 
-/* The hash:ip type structure */
-struct hash_ip {
-       void *members;                  /* the set members */
-       uint32_t hashsize;              /* hash size */
-       uint32_t maxelem;               /* max number of elements/hashsize */
-       uint8_t probes;                 /* max number of probes  */
-       uint8_t resize;                 /* resize factor in percent */
-       uint8_t netmask;                /* netmask */
-       uint32_t timeout;               /* timeout value */
-       uint32_t elements;              /* number of elements */
-       struct timer_list gc;           /* garbage collector */
-       size_t elem_size;               /* size of element */
-       initval_t initval[0];           /* initvals for jhash_1word */
+/* Member elements without timeout */
+struct hash_ip4_elem {
+       u32 ip;
 };
 
-static inline void *
-hash_ip_elem(const struct hash_ip *map, uint32_t id)
-{
-       return (void *)((char *)map->members + id * map->elem_size);
-}
-
-static inline unsigned long
-get_ip4_elem_timeout(const struct ip4_elem *elem)
-{
-       return ((const struct ip4_elem_timeout *)elem)->timeout;
-}
-
-static inline unsigned long
-get_ip6_elem_timeout(const struct ip6_elem *elem)
-{
-       return ((const struct ip6_elem_timeout *)elem)->timeout;
-}
-
-static inline uint32_t
-ip4_hash(struct ip4_elem *elem, initval_t initval, uint32_t hashsize)
-{
-       return jhash_1word(elem->ip, initval) % hashsize;
-}
-
-static inline uint32_t
-ip6_hash(struct ip6_elem *elem, initval_t initval, uint32_t hashsize)
-{
-       return jhash2((u32 *)&elem->ip, 4, initval) % hashsize;
-}
+/* Member elements with timeout support */
+struct hash_ip4_telem {
+       u32 ip;
+       unsigned long timeout;
+};
 
 static inline bool
-ip4_cmp(struct ip4_elem *ip1, struct ip4_elem *ip2)
+hash_ip4_data_equal(const struct hash_ip4_elem *ip1,
+                   const struct hash_ip4_elem *ip2)
 {
        return ip1->ip == ip2->ip;
 }
 
 static inline bool
-ip6_cmp(struct ip6_elem *ip1, struct ip6_elem *ip2)
-{
-       return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6);
-}
-
-static inline bool
-ip4_null(struct ip4_elem *elem)
+hash_ip4_data_isnull(const struct hash_ip4_elem *elem)
 {
        return elem->ip == 0;
 }
 
-static inline bool
-ip6_null(struct ip6_elem *elem)
-{
-       return ipv6_addr_any(&elem->ip.in6);
-}
-
 static inline void
-ip4_cpy(struct ip4_elem *dst, const struct ip4_elem *src)
+hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src)
 {
        dst->ip = src->ip;
 }
 
 static inline void
-ip6_cpy(struct ip6_elem *dst, const struct ip6_elem *src)
+hash_ip4_data_swap(struct hash_ip4_elem *dst, struct hash_ip4_elem *src)
 {
-       ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
+       swap(dst->ip, src->ip);
 }
 
-/* Zero valued IP addresses (network order) cannot be stored */
+/* Zero valued IP addresses cannot be stored */
 static inline void
-ip4_zero_out(struct ip4_elem *elem)
+hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
 {
        elem->ip = 0;
 }
 
-static inline void
-ip6_zero_out(struct ip6_elem *elem)
+static inline bool
+hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data)
 {
-       ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0);
-}
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
+       return 0;
 
-static inline void
-ip6_netmask(union nf_inet_addr *ip, uint8_t prefix)
-{
-       ip->ip6[0] &= NETMASK6(prefix)[0];
-       ip->ip6[1] &= NETMASK6(prefix)[1];
-       ip->ip6[2] &= NETMASK6(prefix)[2];
-       ip->ip6[3] &= NETMASK6(prefix)[3];
+nla_put_failure:
+       return 1;
 }
 
-/* The type variant functions: generic ones */
-
-static void
-hash_ip_destroy(struct ip_set *set)
+static inline bool
+hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
 {
-       struct hash_ip *map = set->data;
+       const struct hash_ip4_telem *tdata =
+               (const struct hash_ip4_telem *)data;
 
-       /* gc might be running: del_timer_sync can't be used */
-       if (set->flags & IP_SET_FLAG_TIMEOUT)
-               while (!del_timer(&map->gc))
-                       msleep(IPSET_DESTROY_TIMER_SLEEP);
-
-       ip_set_free(map->members, set->flags);
-       kfree(map);
-       
-       set->data = NULL;
-}
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
+       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                     htonl(ip_set_timeout_get(tdata->timeout)));
 
-#define hash_ip4_destroy       hash_ip_destroy
-#define hash_ip6_destroy       hash_ip_destroy
+       return 0;
 
-static void
-hash_ip_flush(struct ip_set *set)
-{
-       struct hash_ip *map = set->data;
-       
-       memset(map->members, 0, map->hashsize * map->elem_size);
-       map->elements = 0;
+nla_put_failure:
+       return 1;
 }
 
-#define hash_ip4_flush         hash_ip_flush
-#define hash_ip6_flush         hash_ip_flush
-
-/* IPv4 variant */
-
-#define PF     4
-#include "ip_set_hash_ip_src.c"
-#undef PF
+#define IP_SET_HASH_WITH_NETMASK
+#define PF             4
+#define HOST_MASK      32
+#include <linux/netfilter/ip_set_chash.h>
 
 static int
 hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
-             enum ipset_adt adt, uint8_t pf, const uint8_t *flags)
+             enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
-       struct hash_ip *map = set->data;
-       bool with_timeout = set->flags & IP_SET_FLAG_TIMEOUT;
-       uint32_t ip;
+       struct chash *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       u32 ip;
        
-       if (pf != AF_INET)
-               return -EINVAL;
-
-       ip4addrptr(skb, flags, &ip);
-       ip &= NETMASK(map->netmask);
+       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip);
+       ip &= NETMASK(h->netmask);
        if (ip == 0)
                return -EINVAL;
 
-       switch (adt) {
-       case IPSET_TEST:
-               return hash_ip4_test(map, with_timeout,
-                                    (struct ip4_elem *)&ip);
-       case IPSET_ADD:
-               return hash_ip4_add(map, with_timeout,
-                                   (struct ip4_elem *)&ip, map->timeout);
-       case IPSET_DEL:
-               return hash_ip4_del(map, with_timeout, (struct ip4_elem *)&ip);
-       default:
-               BUG();
-       }
-       return 0;
+       return adtfn(set, &ip, GFP_ATOMIC, h->timeout);
 }
 
 static const struct nla_policy
 hash_ip4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
        [IPSET_ATTR_IP]         = { .type = NLA_U32 },
+       [IPSET_ATTR_IP_TO]      = { .type = NLA_U32 },
+       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
        [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 };
 
 static int
 hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
-             enum ipset_adt adt, uint32_t *lineno, uint32_t flags)
+             enum ipset_adt adt, u32 *lineno, u32 flags)
 {
-       struct hash_ip *map = set->data;
+       struct chash *h = set->data;
        struct nlattr *tb[IPSET_ATTR_ADT_MAX];
-       bool with_timeout = set->flags & IP_SET_FLAG_TIMEOUT;
-       uint32_t ip, timeout = map->timeout;
+       bool eexist = flags & IPSET_FLAG_EXIST;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       u32 ip, nip, ip_to, hosts, timeout = h->timeout;
+       int ret = 0;
 
        if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
                      hash_ip4_adt_policy))
@@ -247,69 +162,164 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
        else
                return -IPSET_ERR_PROTOCOL;
 
-       ip &= NETMASK(map->netmask);
+       ip &= NETMASK(h->netmask);
        if (ip == 0)
                return -IPSET_ERR_HASH_ELEM;
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
-               if (!with_timeout)
+               if (!with_timeout(h->timeout))
                        return -IPSET_ERR_TIMEOUT;
-               timeout = ip_set_get_h32(tb[IPSET_ATTR_TIMEOUT]);
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       switch (adt) {
-       case IPSET_TEST:
-               return hash_ip4_test(map, with_timeout,
-                                    (struct ip4_elem *)&ip);
-       case IPSET_ADD:
-               return hash_ip4_add(map, with_timeout,
-                                   (struct ip4_elem *)&ip, timeout);
-       case IPSET_DEL:
-               return hash_ip4_del(map, with_timeout,
-                                   (struct ip4_elem *)&ip);
-       default:
-               BUG();
+       if (adt == IPSET_TEST)
+               return adtfn(set, &ip, GFP_KERNEL, timeout);
+
+       ip = ntohl(ip);
+       if (tb[IPSET_ATTR_IP_TO]) {
+               ip_to = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]);
+               if (ip > ip_to)
+                       swap(ip, ip_to);
+       } else if (tb[IPSET_ATTR_CIDR]) {
+               u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+               
+               if (cidr > 32)
+                       return -IPSET_ERR_INVALID_CIDR;
+               ip &= HOSTMASK(cidr);
+               ip_to = ip | ~HOSTMASK(cidr);
+       } else
+               ip_to = ip;
+
+       hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
+
+       for (; !before(ip_to, ip); ip += hosts) {
+               nip = htonl(ip);
+               ret = adtfn(set, &nip, GFP_KERNEL, timeout);
+
+               if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
+                       if (tb[IPSET_ATTR_LINENO])
+                               *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+                       return ret;
+               }
        }
+       return ret;
+}
+
+static bool
+hash_ip_same_set(const struct ip_set *a, const struct ip_set *b)
+{
+       struct chash *x = a->data;
+       struct chash *y = b->data;
+       
+       return x->maxelem == y->maxelem
+              && x->timeout == y->timeout
+              && x->htable_bits == y->htable_bits      /* resizing ? */
+              && x->array_size == y->array_size
+              && x->chain_limit == y->chain_limit
+              && x->netmask == y->netmask;
+}
+
+/* The type variant functions: IPv6 */
+
+struct hash_ip6_elem {
+       union nf_inet_addr ip;
+};
 
+struct hash_ip6_telem {
+       union nf_inet_addr ip;
+       unsigned long timeout;
+};
+
+static inline bool
+hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
+                   const struct hash_ip6_elem *ip2)
+{
+       return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0;
+}
+
+static inline bool
+hash_ip6_data_isnull(const struct hash_ip6_elem *elem)
+{
+       return ipv6_addr_any(&elem->ip.in6);
+}
+
+static inline void
+hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
+{
+       ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
+}
+
+static inline void
+hash_ip6_data_swap(struct hash_ip6_elem *dst, struct hash_ip6_elem *src)
+{
+       struct in6_addr tmp;
+       
+       ipv6_addr_copy(&tmp, &dst->ip.in6);
+       ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
+       ipv6_addr_copy(&src->ip.in6, &tmp);
+}
+
+static inline void
+hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
+{
+       ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0);
+}
+
+static inline void
+ip6_netmask(union nf_inet_addr *ip, u8 prefix)
+{
+       ip->ip6[0] &= NETMASK6(prefix)[0];
+       ip->ip6[1] &= NETMASK6(prefix)[1];
+       ip->ip6[2] &= NETMASK6(prefix)[2];
+       ip->ip6[3] &= NETMASK6(prefix)[3];
+}
+
+static inline bool
+hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
+{
+       NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
        return 0;
+
+nla_put_failure:
+       return 1;
 }
 
-/* IPv6 variants */
+static inline bool
+hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
+{
+       const struct hash_ip6_telem *e = 
+               (const struct hash_ip6_telem *)data;
+       
+       NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
+       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                     htonl(ip_set_timeout_get(e->timeout)));
+       return 0;
+
+nla_put_failure:
+       return 1;
+}
 
-#define PF     6
-#include "ip_set_hash_ip_src.c"
 #undef PF
+#undef HOST_MASK
+
+#define PF             6
+#define HOST_MASK      128
+#include <linux/netfilter/ip_set_chash.h>
 
 static int
 hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
-             enum ipset_adt adt, uint8_t pf, const uint8_t *flags)
+             enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
-       struct hash_ip *map = set->data;
-       bool with_timeout = set->flags & IP_SET_FLAG_TIMEOUT;
+       struct chash *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
        union nf_inet_addr ip;
 
-       if (pf != AF_INET6)
-               return -EINVAL;
-
-       ip6addrptr(skb, flags, &ip.in6);
-       ip6_netmask(&ip, map->netmask);
+       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip.in6);
+       ip6_netmask(&ip, h->netmask);
        if (ipv6_addr_any(&ip.in6))
                return -EINVAL;
 
-       switch (adt) {
-       case IPSET_TEST:
-               return hash_ip6_test(map, with_timeout,
-                                    (struct ip6_elem *)&ip);
-       case IPSET_ADD:
-               return hash_ip6_add(map, with_timeout,
-                                   (struct ip6_elem *)&ip, map->timeout);
-       case IPSET_DEL:
-               return hash_ip6_del(map, with_timeout,
-                                   (struct ip6_elem *)&ip);
-       default:
-               BUG();
-       }
-       return 0;
+       return adtfn(set, &ip, GFP_ATOMIC, h->timeout);
 }
 
 static const struct nla_policy
@@ -321,13 +331,13 @@ hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
 
 static int
 hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len,
-             enum ipset_adt adt, uint32_t *lineno, uint32_t flags)
+             enum ipset_adt adt, u32 *lineno, u32 flags)
 {
-       struct hash_ip *map = set->data;
+       struct chash *h = set->data;
        struct nlattr *tb[IPSET_ATTR_ADT_MAX];
+       ipset_adtfn adtfn = set->variant->adt[adt];
        union nf_inet_addr *ip;
-       bool with_timeout = set->flags & IP_SET_FLAG_TIMEOUT;
-       uint32_t timeout = map->timeout;
+       u32 timeout = h->timeout;
 
        if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
                      hash_ip6_adt_policy))
@@ -338,31 +348,17 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len,
        else
                return -IPSET_ERR_PROTOCOL;
 
-       ip6_netmask(ip, map->netmask);
+       ip6_netmask(ip, h->netmask);
        if (ipv6_addr_any(&ip->in6))
                return -IPSET_ERR_HASH_ELEM;
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
-               if (!with_timeout)
+               if (!with_timeout(h->timeout))
                        return -IPSET_ERR_TIMEOUT;
-               timeout = ip_set_get_h32(tb[IPSET_ATTR_TIMEOUT]);
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       switch (adt) {
-       case IPSET_TEST:
-               return hash_ip6_test(map, with_timeout,
-                                    (struct ip6_elem *)ip);
-       case IPSET_ADD:
-               return hash_ip6_add(map, with_timeout,
-                                   (struct ip6_elem *)ip, timeout);
-       case IPSET_DEL:
-               return hash_ip6_del(map, with_timeout,
-                                   (struct ip6_elem *)ip);
-       default:
-               BUG();
-       }
-       
-       return 0;
+       return adtfn(set, ip, GFP_KERNEL, timeout);
 }
 
 /* Create hash:ip type of sets */
@@ -374,114 +370,84 @@ hash_ip_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
        [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
        [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
        [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       [IPSET_ATTR_NETMASK]    = { .type = NLA_U8  },
 };
 
-static bool
-init_map_ip(struct ip_set *set, struct hash_ip *map, uint32_t maxelem,
-           uint32_t probes, uint32_t resize, uint8_t netmask, uint8_t family)
-{
-       map->members = ip_set_alloc(map->hashsize * map->elem_size,
-                                   GFP_KERNEL, &set->flags);
-       if (!map->members)
-               return false;
-
-       map->maxelem = maxelem;
-       map->probes = probes;
-       map->resize = resize;
-       map->netmask = netmask;
-
-       set->data = map;
-       set->family = family;
-       
-       return true;
-}
-
 static int
-hash_ip_create(struct ip_set *set, struct nlattr *head, int len,
-                uint32_t flags)
+hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
 {
        struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
-       uint32_t hashsize, maxelem;
-       uint8_t probes, resize, netmask, family, i;
-       struct hash_ip *map;
+       u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+       u8 netmask;
+       struct chash *h;
+
+       if (!(set->family == AF_INET || set->family == AF_INET6))
+               return -IPSET_ERR_INVALID_FAMILY;
+       netmask = set->family == AF_INET ? 32 : 128;
+       pr_debug("Create set %s with family %s",
+                set->name, set->family == AF_INET ? "inet" : "inet6");
 
        if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
                      hash_ip_create_policy))
                return -IPSET_ERR_PROTOCOL;
 
-       hashsize = IPSET_DEFAULT_HASHSIZE;
-       maxelem = IPSET_DEFAULT_MAXELEM;
-       probes = IPSET_DEFAULT_PROBES;
-       resize = IPSET_DEFAULT_RESIZE;
-       family = AF_INET;
-
-       if (tb[IPSET_ATTR_HASHSIZE])
+       if (tb[IPSET_ATTR_HASHSIZE]) {
                hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
+               if (hashsize < IPSET_MIMINAL_HASHSIZE)
+                       hashsize = IPSET_MIMINAL_HASHSIZE;
+       }
 
        if (tb[IPSET_ATTR_MAXELEM])
                maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
 
-       if (tb[IPSET_ATTR_PROBES])
-               probes = nla_get_u8(tb[IPSET_ATTR_PROBES]);
-
-       if (tb[IPSET_ATTR_RESIZE])
-               resize = nla_get_u8(tb[IPSET_ATTR_RESIZE]);
-
-       if (tb[IPSET_ATTR_FAMILY])
-               family = nla_get_u8(tb[IPSET_ATTR_FAMILY]);
-       if (!(family == AF_INET || family == AF_INET6))
-               return -IPSET_ERR_INVALID_FAMILY;
-       netmask = family == AF_INET ? 32 : 128;
-
        if (tb[IPSET_ATTR_NETMASK]) {
                netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
                
-               if ((family == AF_INET && netmask > 32)
-                   || (family == AF_INET6 && netmask > 128))
+               if ((set->family == AF_INET && netmask > 32)
+                   || (set->family == AF_INET6 && netmask > 128)
+                   || netmask == 0)
                        return -IPSET_ERR_INVALID_NETMASK;
        }
 
-       map = kzalloc(sizeof(*map) + probes * sizeof(initval_t), GFP_KERNEL);
-       if (!map)
+       h = kzalloc(sizeof(*h), GFP_KERNEL);
+       if (!h)
                return -ENOMEM;
-               
-       map->hashsize = hashsize;
-       if (tb[IPSET_ATTR_TIMEOUT]) {
-               map->elem_size = family == AF_INET
-                                       ? sizeof(struct ip4_elem_timeout)
-                                       : sizeof(struct ip6_elem_timeout);
-
-               if (!init_map_ip(set, map, maxelem, probes, resize, netmask, 
-                                family)) {
-                       kfree(map);
-                       return -ENOMEM;
-               }
 
-               map->timeout = ip_set_get_h32(tb[IPSET_ATTR_TIMEOUT]);
-               set->flags |= IP_SET_FLAG_TIMEOUT;
+       h->maxelem = maxelem;
+       h->netmask = netmask;
+       h->htable_bits = htable_bits(hashsize);
+       h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
+       h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
+       get_random_bytes(&h->initval, sizeof(h->initval));
+       h->timeout = IPSET_NO_TIMEOUT;
+
+       h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
+                                GFP_KERNEL, &set->flags);
+       if (!h->htable) {
+               kfree(h);
+               return -ENOMEM;
+       }
+
+       set->data = h;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
                
-               if (family == AF_INET)
+               set->variant = set->family == AF_INET
+                       ? &hash_ip4_tvariant : &hash_ip6_tvariant;
+
+               if (set->family == AF_INET)
                        hash_ip4_gc_init(set);
                else
                        hash_ip6_gc_init(set);
        } else {
-               map->elem_size = family == AF_INET
-                                       ? sizeof(struct ip4_elem)
-                                       : sizeof(struct ip6_elem);
-
-               if (!init_map_ip(set, map, maxelem, probes, resize, netmask,
-                                family)) {
-                       kfree(map);
-                       return -ENOMEM;
-               }
+               set->variant = set->family == AF_INET
+                       ? &hash_ip4_variant : &hash_ip6_variant;
        }
-       for (i = 0; i < map->probes; i++)
-               get_random_bytes(((initval_t *) map->initval)+i,
-                                sizeof(initval_t));
        
-       set->variant = family == AF_INET ? &hash_ip4 : &hash_ip6;
-       D("create %s hashsize %u maxelem %u probes %u resize %u",
-          set->name, map->hashsize, map->maxelem, map->probes, map->resize);
+       pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
+                set->name, jhash_size(h->htable_bits),
+                h->htable_bits, h->maxelem, set->data, h->htable);
           
        return 0;
 }
@@ -490,6 +456,7 @@ static struct ip_set_type hash_ip_type = {
        .name           = "hash:ip",
        .protocol       = IPSET_PROTOCOL,
        .features       = IPSET_TYPE_IP,
+       .dimension      = IPSET_DIM_ONE,
        .family         = AF_UNSPEC,
        .revision       = 0,
        .create         = hash_ip_create,
diff --git a/kernel/ip_set_hash_ip_src.c b/kernel/ip_set_hash_ip_src.c
deleted file mode 100644 (file)
index ef0a8ec..0000000
+++ /dev/null
@@ -1,473 +0,0 @@
-/* Copyright (C) 2003-2010 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.
- */
-
-#define CONCAT(a, b, c)                a##b##c
-#define TOKEN(a, b, c)         CONCAT(a, b, c)
-
-/* IPv4/IPv6 dependent function prototypes for hash:ip */
-
-#if PF == 4
-#define HOST_MASK      32
-#define NLA_PUT_ADDR(skb, ip) \
-       NLA_PUT_NET32(skb, IPSET_ATTR_IP, *(ip));
-#else
-#define HOST_MASK      128
-#define NLA_PUT_ADDR(skb, ip) \
-       NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), ip);
-#endif
-
-#define hash_ip_pf_timeout     TOKEN(hash_ip, PF, _timeout)
-#define hash_ip_pf_expired     TOKEN(hash_ip, PF, _expired)
-#define hash_ip_pf_elem_test   TOKEN(hash_ip, PF, _elem_test)
-#define hash_ip_pf_elem_exist  TOKEN(hash_ip, PF, _elem_exist)
-#define hash_ip_pf_elem_expired        TOKEN(hash_ip, PF, _elem_expired)
-#define hash_ip_pf_test                TOKEN(hash_ip, PF, _test)
-#define hash_ip_pf_add         TOKEN(hash_ip, PF, _add)
-#define hash_ip_pf_readd       TOKEN(hash_ip, PF, _readd)
-#define hash_ip_pf_del         TOKEN(hash_ip, PF, _del)
-#define hash_ip_pf_map_expired TOKEN(hash_ip, PF, _map_expired)
-#define hash_ip_pf_set_expired TOKEN(hash_ip, PF, _set_expired)
-#define hash_ip_pf_head                TOKEN(hash_ip, PF, _head)
-#define hash_ip_pf_list                TOKEN(hash_ip, PF, _list)
-#define hash_ip_pf_resize      TOKEN(hash_ip, PF, _resize)
-#define hash_ip_pf             TOKEN(hash_ip, PF , )
-#define hash_ip_pf_kadt                TOKEN(hash_ip, PF, _kadt)
-#define hash_ip_pf_uadt                TOKEN(hash_ip, PF, _uadt)
-#define hash_ip_pf_destroy     TOKEN(hash_ip, PF, _destroy)
-#define hash_ip_pf_flush       TOKEN(hash_ip, PF, _flush)
-#define hash_ip_pf_timeout_gc  TOKEN(hash_ip, PF, _timeout_gc)
-#define hash_ip_pf_gc_init     TOKEN(hash_ip, PF, _gc_init)
-#define ip_pf_hash             TOKEN(ip, PF, _hash)
-#define ip_pf_cmp              TOKEN(ip, PF, _cmp)
-#define ip_pf_null             TOKEN(ip, PF, _null)
-#define ip_pf_cpy              TOKEN(ip, PF, _cpy)
-#define ip_pf_zero_out         TOKEN(ip, PF, _zero_out)
-#define ip_pf_elem             TOKEN(ip, PF, _elem)
-#define ip_pf_elem_timeout     TOKEN(ip, PF, _elem_timeout)
-#define ip_pf_get_elem_timeout TOKEN(get_ip, PF, _elem_timeout)
-
-static inline bool
-hash_ip_pf_timeout(const struct hash_ip *map, uint32_t id)
-{
-       struct ip_pf_elem_timeout *elem = hash_ip_elem(map, id);
-
-       return ip_set_timeout_test(elem->timeout);
-}
-
-static inline bool
-hash_ip_pf_expired(const struct hash_ip *map, uint32_t id)
-{
-       struct ip_pf_elem_timeout *elem = hash_ip_elem(map, id);
-
-       return ip_set_timeout_expired(elem->timeout);
-}
-
-static inline bool
-hash_ip_pf_elem_test(const struct hash_ip *map, bool with_timeout,
-                    uint32_t id, struct ip_pf_elem * ip)
-{
-       struct ip_pf_elem *elem = hash_ip_elem(map, id);
-
-       return ip_pf_cmp(elem, ip)
-               && (!with_timeout || hash_ip_pf_timeout(map, id));
-}
-
-static inline bool
-hash_ip_pf_elem_exist(const struct hash_ip *map, bool with_timeout,
-                     uint32_t id)
-{
-       struct ip_pf_elem *elem = hash_ip_elem(map, id);
-
-       return !(ip_pf_null(elem)
-                || (with_timeout && hash_ip_pf_expired(map, id)));
-}
-
-static inline bool
-hash_ip_pf_elem_expired(const struct hash_ip *map, bool with_timeout,
-                       uint32_t id)
-{
-       struct ip_pf_elem *elem = hash_ip_elem(map, id);
-
-       return ip_pf_null(elem)
-              || (with_timeout && hash_ip_pf_expired(map, id));
-}
-
-static inline uint32_t
-hash_ip_pf_test(const struct hash_ip *map, bool with_timeout,
-               struct ip_pf_elem * ip)
-{
-       uint32_t id;
-       uint8_t i;
-
-       for (i = 0; i < map->probes; i++) {
-               id = ip_pf_hash(ip, *(map->initval + i), map->hashsize);
-               if (hash_ip_pf_elem_test(map, with_timeout, id, ip))
-                       return id + 1;
-               /* No shortcut - there can be deleted entries. */
-       }
-       return 0;
-}
-
-static void
-hash_ip_pf_map_expired(struct hash_ip *map)
-{
-       struct ip_pf_elem_timeout *table = map->members;
-       uint32_t i;
-
-       /* We run parallel with other readers (test element)
-        * but adding/deleting new entries is locked out */
-       for (i = 0; i < map->hashsize; i++)
-               if (ip_set_timeout_expired(table[i].timeout)) {
-                       ip_pf_zero_out((struct ip_pf_elem *)&table[i]);
-                       table[i].timeout = IPSET_ELEM_UNSET;
-                       map->elements--;
-               }
-}
-
-static inline void
-hash_ip_pf_set_expired(struct ip_set *set)
-{
-       /* We run parallel with other readers (test element)
-        * but adding/deleting new entries is locked out */
-       read_lock_bh(&set->lock);
-       hash_ip_pf_map_expired(set->data);
-       read_unlock_bh(&set->lock);
-}
-
-static int
-hash_ip_pf_add(struct hash_ip *map, bool with_timeout,
-              struct ip_pf_elem *ip, uint32_t timeout)
-{
-       uint32_t id, empty = 0;
-       uint8_t i;
-       
-       if (map->elements >= map->maxelem) {
-               if (with_timeout) {
-                       hash_ip_pf_map_expired(map);
-                       if (map->elements < map->maxelem)
-                               goto doit;
-               }
-               return -IPSET_ERR_HASH_FULL;
-       }
-
-doit:
-       for (i = 0; i < map->probes; i++) {
-               id = ip_pf_hash(ip, *(map->initval + i), map->hashsize);
-               if (hash_ip_pf_elem_test(map, with_timeout, id, ip))
-                       return -IPSET_ERR_EXIST;        
-               if (empty == 0
-                   && hash_ip_pf_elem_expired(map, with_timeout, id))
-                       empty = id + 1;
-               /* There can be deleted entries, must check all slots */
-       }
-       if (!empty)
-               /* Trigger rehashing */
-               return -EAGAIN;
-
-       if (with_timeout) {
-               struct ip_pf_elem_timeout *e = hash_ip_elem(map, empty - 1);
-               e->timeout = ip_set_timeout_set(timeout);
-               D("add with timeout: %u (%lu)", timeout, e->timeout);
-               ip_pf_cpy((struct ip_pf_elem *)e, ip); 
-       } else {
-               struct ip_pf_elem *e = hash_ip_elem(map, empty - 1);
-               ip_pf_cpy(e, ip);
-       }
-       map->elements++;
-       return 0;
-}
-
-static int
-hash_ip_pf_readd(struct hash_ip *map, bool with_timeout, struct ip_pf_elem *ip)
-{
-       uint32_t id, empty = 0;
-       uint8_t i;
-       
-       for (i = 0; empty == 0 && i < map->probes; i++) {
-               id = ip_pf_hash(ip, *(map->initval + i), map->hashsize);
-               if (ip_pf_null(hash_ip_elem(map, id)))
-                       empty = id + 1;
-       }
-       if (!empty)
-               /* Trigger rehashing */
-               return -EAGAIN;
-
-       if (with_timeout) {
-               struct ip_pf_elem_timeout *e = hash_ip_elem(map, empty - 1);
-               e->timeout = ip_pf_get_elem_timeout(ip);
-               ip_pf_cpy((struct ip_pf_elem *)e, ip); 
-       } else {
-               struct ip_pf_elem *e = hash_ip_elem(map, empty - 1);
-               ip_pf_cpy(e, ip);
-       }
-       map->elements++;
-       return 0;
-}
-
-static int
-hash_ip_pf_del(struct hash_ip *map, bool with_timeout, struct ip_pf_elem *ip)
-{
-       struct ip_pf_elem *e;
-       uint32_t id, found = 0;
-       uint8_t i;
-
-       for (i = 0; i < map->probes; i++) {
-               id = ip_pf_hash(ip, *(map->initval + i), map->hashsize);
-               if (hash_ip_pf_elem_test(map, with_timeout, id, ip)) {
-                       found = id + 1;
-                       break;
-               }
-       }
-       if (!found)
-               return -IPSET_ERR_EXIST;
-               
-       e = hash_ip_elem(map, found - 1);
-       ip_pf_zero_out(e);
-       if (with_timeout)
-               ((struct ip_pf_elem_timeout *)e)->timeout = IPSET_ELEM_UNSET;
-
-       map->elements--;
-
-       return 0;
-}
-
-static int
-hash_ip_pf_head(struct ip_set *set, struct sk_buff *skb)
-{
-       const struct hash_ip *map = set->data;
-       struct nlattr *nested;
-       
-       if (set->flags & IP_SET_FLAG_TIMEOUT)
-               hash_ip_pf_set_expired(set);
-
-       nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
-       if (!nested)
-               goto nla_put_failure;
-       NLA_PUT_NET32(skb, IPSET_ATTR_HASHSIZE, htonl(map->hashsize));
-       NLA_PUT_NET32(skb, IPSET_ATTR_MAXELEM, htonl(map->maxelem));
-       if (map->netmask != HOST_MASK)
-               NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
-       NLA_PUT_U8(skb, IPSET_ATTR_PROBES, map->probes);
-       NLA_PUT_U8(skb, IPSET_ATTR_RESIZE, map->resize);
-       NLA_PUT_NET32(skb, IPSET_ATTR_ELEMENTS, htonl(map->elements));
-       NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
-                     htonl(atomic_read(&set->ref) - 1));
-       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
-                     htonl(map->hashsize * map->elem_size));
-       if (set->flags & IP_SET_FLAG_TIMEOUT)
-               NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
-       ipset_nest_end(skb, nested);
-       
-       return 0;
-nla_put_failure:
-       return -EFAULT;
-}
-
-static int
-hash_ip_pf_list(struct ip_set *set,
-               struct sk_buff *skb, struct netlink_callback *cb)
-{
-       const struct hash_ip *map = set->data;
-       struct nlattr *atd, *nested;
-       struct ip_pf_elem *elem;
-       uint32_t id, first = cb->args[2];
-       bool with_timeout = set->flags & IP_SET_FLAG_TIMEOUT;
-
-       atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
-       if (!atd)
-               return -EFAULT;
-       for (; cb->args[2] < map->hashsize; cb->args[2]++) {
-               id = cb->args[2];
-               if (hash_ip_pf_elem_expired(map, with_timeout, id))
-                       continue;
-               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
-               if (!nested) {
-                       if (id == first) {
-                               nla_nest_cancel(skb, atd);
-                               return -EFAULT;
-                       } else
-                               goto nla_put_failure;
-               }
-               elem = hash_ip_elem(map, id);
-               NLA_PUT_ADDR(skb, &elem->ip);
-               if (map->netmask != HOST_MASK)
-                       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, map->netmask);
-               if (with_timeout) {
-                       unsigned long timeout = ip_pf_get_elem_timeout(elem);
-                       D("list with timeout: %u (%lu)",
-                         ip_set_timeout_get(timeout), timeout);
-                       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
-                                     htonl(ip_set_timeout_get(timeout)));
-               }
-               ipset_nest_end(skb, nested);
-       }
-       ipset_nest_end(skb, atd);
-       /* Set listing finished */
-       cb->args[2] = 0;
-       
-       return 0;
-
-nla_put_failure:
-       nla_nest_cancel(skb, nested);
-       ipset_nest_end(skb, atd);
-       return 0;
-}
-
-static int
-hash_ip_pf_resize(struct ip_set *set, uint8_t retried)
-{
-       struct hash_ip *map = set->data, *tmp;
-       void *members;
-       uint32_t i, hashsize = map->hashsize;
-       uint8_t oflags, flags = set->flags;
-       bool with_timeout = flags & IP_SET_FLAG_TIMEOUT;
-       int ret;
-       
-       if (map->resize == 0)
-               return -IPSET_ERR_HASH_FULL;
-
-       /* Try to cleanup first */
-       if (retried == 0 && with_timeout) {
-               i = map->elements;
-               hash_ip_pf_set_expired(set);
-               if (map->elements < i)
-                       return 0;
-       }
-
-again:
-       ret = 0;
-       
-       /* Calculate new hash size */
-       hashsize += (hashsize * map->resize)/100;
-       if (hashsize == map->hashsize)
-               hashsize++;
-       if (hashsize >= map->maxelem)
-               return -IPSET_ERR_HASH_FULL;
-       
-       printk("Rehashing of set %s triggered: hash grows from %lu to %lu\n",
-              set->name,
-              (long unsigned)map->hashsize,
-              (long unsigned)hashsize);
-
-       tmp = kmalloc(sizeof(struct hash_ip)
-                     + map->probes * sizeof(initval_t), GFP_ATOMIC);
-       if (!tmp)
-               return -ENOMEM;
-
-       memcpy(tmp, map, sizeof(*map) + map->probes * sizeof(initval_t));
-       tmp->elements = 0;
-       tmp->hashsize = hashsize;
-       tmp->members = ip_set_alloc(hashsize * map->elem_size,
-                                   GFP_ATOMIC, &flags);
-       if (!tmp->members) {
-               kfree(tmp);
-               return -ENOMEM;
-       }
-       
-       write_lock_bh(&set->lock);
-       map = set->data; /* Play safe */
-       for (i = 0; i < map->hashsize && ret == 0; i++) {
-               if (hash_ip_pf_elem_exist(map, with_timeout, i))
-                       ret = hash_ip_pf_readd(tmp, with_timeout,
-                                              hash_ip_elem(map, i));
-       }
-       if (ret) {
-               /* Failure, try again */
-               write_unlock_bh(&set->lock);
-               ip_set_free(tmp->members, flags);
-               kfree(tmp);
-               goto again;
-       }
-       
-       /* Success at resizing! */
-       members = map->members;
-       oflags = set->flags;
-       
-       map->hashsize = tmp->hashsize;
-       map->members = tmp->members;
-       map->elements = tmp->elements;
-       set->flags = flags;
-       write_unlock_bh(&set->lock);
-       
-       ip_set_free(members, oflags);
-       kfree(tmp);
-       
-       return 0;
-}
-
-static int
-hash_ip_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
-               enum ipset_adt adt, uint8_t pf, const uint8_t *flags);
-static int
-hash_ip_pf_uadt(struct ip_set *set, struct nlattr *head, int len,
-               enum ipset_adt adt, uint32_t *lineno, uint32_t flags);
-
-static const struct ip_set_type_variant hash_ip_pf __read_mostly = {
-       .kadt   = hash_ip_pf_kadt,
-       .uadt   = hash_ip_pf_uadt,
-       .destroy = hash_ip_pf_destroy,
-       .flush  = hash_ip_pf_flush,
-       .head   = hash_ip_pf_head,
-       .list   = hash_ip_pf_list,
-       .resize = hash_ip_pf_resize,
-};
-
-static void
-hash_ip_pf_timeout_gc(unsigned long ul_set)
-{
-       struct ip_set *set = (struct ip_set *) ul_set;
-       struct hash_ip *map = set->data;
-
-       hash_ip_pf_set_expired(set);
-
-       map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
-       add_timer(&map->gc);
-}
-
-static inline void
-hash_ip_pf_gc_init(struct ip_set *set)
-{
-       struct hash_ip *map = set->data;
-       
-       init_timer(&map->gc);
-       map->gc.data = (unsigned long) set;
-       map->gc.function = hash_ip_pf_timeout_gc;
-       map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
-       add_timer(&map->gc);
-}
-
-#undef HOST_MASK
-#undef NLA_PUT_ADDR
-#undef hash_ip_pf_timeout
-#undef hash_ip_pf_expired
-#undef hash_ip_pf_elem_test
-#undef hash_ip_pf_elem_exist
-#undef hash_ip_pf_elem_expired
-#undef hash_ip_pf_test
-#undef hash_ip_pf_add
-#undef hash_ip_pf_readd
-#undef hash_ip_pf_del
-#undef hash_ip_pf_map_expired
-#undef hash_ip_pf_set_expired
-#undef hash_ip_pf_head
-#undef hash_ip_pf_list
-#undef hash_ip_pf_resize
-#undef hash_ip_pf
-#undef hash_ip_pf_kadt
-#undef hash_ip_pf_uadt
-#undef hash_ip_pf_destroy
-#undef hash_ip_pf_flush
-#undef hash_ip_pf_timeout_gc
-#undef hash_ip_pf_gc_init
-#undef ip_pf_hash
-#undef ip_pf_cmp
-#undef ip_pf_null
-#undef ip_pf_cpy
-#undef ip_pf_zero_out
-#undef ip_pf_elem
-#undef ip_pf_elem_timeout
-#undef ip_pf_get_elem_timeout
index 36e68b0887a70b2e2e320a432b2eebc0849e0959..8210f67555bb1813f7b35194378deddc13a7ca49 100644 (file)
-/* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2010 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 hash set */
+/* Kernel module implementing an IP set type: the hash:ip,port type */
 
+#include <linux/netfilter/ip_set_kernel.h>
+#include <linux/netfilter/ip_set_jhash.h>
 #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/netfilter_ipv4/ip_set_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 <net/ipv6.h>
+#include <net/netlink.h>
+#include <net/pfxlen.h>
 
-#include <linux/netfilter_ipv4/ip_set_ipporthash.h>
-#include <linux/netfilter_ipv4/ip_set_getport.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/ip_set.h>
+#include <linux/netfilter/ip_set_timeout.h>
+#include <linux/netfilter/ip_set_getport.h>
+#include <linux/netfilter/ip_set_hash.h>
 
-static int limit = MAX_RANGE;
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("hash:ip,port type of IP sets");
+MODULE_ALIAS("ip_set_hash:ip,port");
+
+/* Type specific function prefix */
+#define TYPE           hash_ipport
+
+static bool
+hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b);
+
+#define hash_ipport4_same_set  hash_ipport_same_set
+#define hash_ipport6_same_set  hash_ipport_same_set
+
+/* The type variant functions: IPv4 */
+
+/* Member elements without timeout */
+struct hash_ipport4_elem {
+       u32 ip;
+       u16 port;
+       u16 match;
+};
+
+/* Member elements with timeout support */
+struct hash_ipport4_telem {
+       u32 ip;
+       u16 port;
+       u16 match;
+       unsigned long timeout;
+};
+
+static inline bool
+hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
+                       const struct hash_ipport4_elem *ip2)
+{
+       return ip1->ip == ip2->ip && ip1->port == ip2->port;
+}
 
-static inline __u32
-ipporthash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port)
+static inline bool
+hash_ipport4_data_isnull(const struct hash_ipport4_elem *elem)
 {
-       struct ip_set_ipporthash *map = set->data;
-       __u32 id;
-       u_int16_t i;
-       ip_set_ip_t *elem;
+       return elem->match == 0;
+}
 
-       ip = pack_ip_port(map, ip, port);
-               
-       if (!ip)
-               return UINT_MAX;
-       
-       for (i = 0; i < map->probes; i++) {
-               id = jhash_ip(map, i, ip) % map->hashsize;
-               DP("hash key: %u", id);
-               elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
-               if (*elem == ip)
-                       return id;
-               /* No shortcut - there can be deleted entries. */
-       }
-       return UINT_MAX;
+static inline void
+hash_ipport4_data_copy(struct hash_ipport4_elem *dst,
+                      const struct hash_ipport4_elem *src)
+{
+       dst->ip = src->ip;
+       dst->port = src->port;
+       dst->match = 1;
 }
 
-static inline int
-ipporthash_test(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port)
+static inline void
+hash_ipport4_data_swap(struct hash_ipport4_elem *dst,
+                      struct hash_ipport4_elem *src)
 {
-       struct ip_set_ipporthash *map = set->data;
-       
-       if (ip < map->first_ip || ip > map->last_ip)
-               return -ERANGE;
-
-       return (ipporthash_id(set, ip, port) != UINT_MAX);
-}
-
-#define KADT_CONDITION                                         \
-       ip_set_ip_t port;                                       \
-                                                               \
-       if (flags[1] == 0)                                      \
-               return 0;                                       \
-                                                               \
-       port = get_port(skb, flags++);                          \
-                                                               \
-       if (port == INVALID_PORT)                               \
-               return 0;
-
-UADT(ipporthash, test, req->port)
-KADT(ipporthash, test, ipaddr, port)
-
-static inline int
-__ipporthash_add(struct ip_set_ipporthash *map, ip_set_ip_t *ip)
-{
-       __u32 probe;
-       u_int16_t i;
-       ip_set_ip_t *elem, *slot = NULL;
-
-       for (i = 0; i < map->probes; i++) {
-               probe = jhash_ip(map, i, *ip) % map->hashsize;
-               elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
-               if (*elem == *ip)
-                       return -EEXIST;
-               if (!(slot || *elem))
-                       slot = elem;
-               /* There can be deleted entries, must check all slots */
+       swap(dst->ip, src->ip);
+       swap(dst->port, src->port);
+}
+
+static inline void
+hash_ipport4_data_zero_out(struct hash_ipport4_elem *elem)
+{
+       elem->match = 0;
+}
+
+static inline bool
+hash_ipport4_data_list(struct sk_buff *skb,
+                      const struct hash_ipport4_elem *data)
+{
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+       return 0;
+
+nla_put_failure:
+       return 1;
+}
+
+static inline bool
+hash_ipport4_data_tlist(struct sk_buff *skb,
+                       const struct hash_ipport4_elem *data)
+{
+       const struct hash_ipport4_telem *tdata =
+               (const struct hash_ipport4_telem *)data;
+
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
+       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                     htonl(ip_set_timeout_get(tdata->timeout)));
+
+       return 0;
+
+nla_put_failure:
+       return 1;
+}
+
+#define PF             4
+#define HOST_MASK      32
+#include <linux/netfilter/ip_set_chash.h>
+
+static int
+hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
+                 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+{
+       struct chash *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipport4_elem data = {};
+
+       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
+       if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
+               return -EINVAL;
+
+       return adtfn(set, &data, GFP_ATOMIC, h->timeout);
+}
+
+static const struct nla_policy
+hash_ipport4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+       [IPSET_ATTR_IP]         = { .type = NLA_U32 },
+       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
+
+static int
+hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
+                 enum ipset_adt adt, u32 *lineno, u32 flags)
+{
+       struct chash *h = set->data;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX];
+       bool eexist = flags & IPSET_FLAG_EXIST;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipport4_elem data = {};
+       u32 timeout = h->timeout;
+       int ret;
+
+       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
+                     hash_ipport4_adt_policy))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP])
+               data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_PORT])
+               data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!with_timeout(h->timeout))
+                       return -IPSET_ERR_TIMEOUT;
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
-       if (slot) {
-               *slot = *ip;
-               map->elements++;
-               return 0;
+
+       ret = adtfn(set, &data, GFP_KERNEL, timeout);
+
+       if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
+               if (tb[IPSET_ATTR_LINENO])
+                       *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
        }
-       /* Trigger rehashing */
-       return -EAGAIN;
+       return ret;
 }
 
-static inline int
-ipporthash_add(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port)
+static bool
+hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b)
 {
-       struct ip_set_ipporthash *map = set->data;
-       if (map->elements > limit)
-               return -ERANGE;
-       if (ip < map->first_ip || ip > map->last_ip)
-               return -ERANGE;
+       struct chash *x = a->data;
+       struct chash *y = b->data;
+       
+       return x->maxelem == y->maxelem
+              && x->timeout == y->timeout
+              && x->htable_bits == y->htable_bits      /* resizing ? */
+              && x->array_size == y->array_size
+              && x->chain_limit == y->chain_limit;
+}
 
-       ip = pack_ip_port(map, ip, port);
+/* The type variant functions: IPv6 */
 
-       if (!ip)
-               return -ERANGE;
-       
-       return __ipporthash_add(map, &ip);
+struct hash_ipport6_elem {
+       union nf_inet_addr ip;
+       u16 port;
+       u16 match;
+};
+
+struct hash_ipport6_telem {
+       union nf_inet_addr ip;
+       u16 port;
+       u16 match;
+       unsigned long timeout;
+};
+
+static inline bool
+hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
+                       const struct hash_ipport6_elem *ip2)
+{
+       return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
+              && ip1->port == ip2->port;
 }
 
-UADT(ipporthash, add, req->port)
-KADT(ipporthash, add, ipaddr, port)
+static inline bool
+hash_ipport6_data_isnull(const struct hash_ipport6_elem *elem)
+{
+       return elem->match == 0;
+}
 
 static inline void
-__ipporthash_retry(struct ip_set_ipporthash *tmp,
-                  struct ip_set_ipporthash *map)
+hash_ipport6_data_copy(struct hash_ipport6_elem *dst,
+                      const struct hash_ipport6_elem *src)
 {
-       tmp->first_ip = map->first_ip;
-       tmp->last_ip = map->last_ip;
+       memcpy(dst, src, sizeof(*dst));
+       dst->match = 1;
 }
 
-HASH_RETRY(ipporthash, ip_set_ip_t)
-
-static inline int
-ipporthash_del(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port)
+static inline void
+hash_ipport6_data_swap(struct hash_ipport6_elem *dst,
+                      struct hash_ipport6_elem *src)
 {
-       struct ip_set_ipporthash *map = set->data;
-       ip_set_ip_t id;
-       ip_set_ip_t *elem;
+       struct hash_ipport6_elem tmp;
 
-       if (ip < map->first_ip || ip > map->last_ip)
-               return -ERANGE;
+       memcpy(&tmp, dst, sizeof(tmp));
+       memcpy(dst, src, sizeof(tmp));
+       memcpy(src, &tmp, sizeof(tmp));
+}
 
-       id = ipporthash_id(set, ip, port);
+static inline void
+hash_ipport6_data_zero_out(struct hash_ipport6_elem *elem)
+{
+       elem->match = 0;
+}
 
-       if (id == UINT_MAX)
-               return -EEXIST;
-               
-       elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
-       *elem = 0;
-       map->elements--;
+static inline bool
+hash_ipport6_data_list(struct sk_buff *skb,
+                      const struct hash_ipport6_elem *data)
+{
+       NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+       return 0;
 
+nla_put_failure:
+       return 1;
+}
+
+static inline bool
+hash_ipport6_data_tlist(struct sk_buff *skb,
+                       const struct hash_ipport6_elem *data)
+{
+       const struct hash_ipport6_telem *e = 
+               (const struct hash_ipport6_telem *)data;
+       
+       NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                     htonl(ip_set_timeout_get(e->timeout)));
        return 0;
+
+nla_put_failure:
+       return 1;
 }
 
-UADT(ipporthash, del, req->port)
-KADT(ipporthash, del, ipaddr, port)
+#undef PF
+#undef HOST_MASK
+
+#define PF             6
+#define HOST_MASK      128
+#include <linux/netfilter/ip_set_chash.h>
+
+static int
+hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
+                 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+{
+       struct chash *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipport6_elem data = {};
+
+       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+       if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
+               return -EINVAL;
+
+       return adtfn(set, &data, GFP_ATOMIC, h->timeout);
+}
 
-static inline int
-__ipporthash_create(const struct ip_set_req_ipporthash_create *req,
-                   struct ip_set_ipporthash *map)
+static const struct nla_policy
+hash_ipport6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+       [IPSET_ATTR_IP]         = { .type = NLA_BINARY,
+                                   .len = sizeof(struct in6_addr) },
+       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
+
+static int
+hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
+                 enum ipset_adt adt, u32 *lineno, u32 flags)
 {
-       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;
+       struct chash *h = set->data;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX];
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipport6_elem data = {};
+       u32 timeout = h->timeout;
+
+       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
+                     hash_ipport6_adt_policy))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP])
+               memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
+                      sizeof(struct in6_addr));
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_PORT])
+               data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!with_timeout(h->timeout))
+                       return -IPSET_ERR_TIMEOUT;
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
-       map->first_ip = req->from;
-       map->last_ip = req->to;
-       return 0;
+
+       return adtfn(set, &data, GFP_KERNEL, timeout);
 }
 
-HASH_CREATE(ipporthash, ip_set_ip_t)
-HASH_DESTROY(ipporthash)
-HASH_FLUSH(ipporthash, ip_set_ip_t)
+/* Create hash:ip type of sets */
 
-static inline void
-__ipporthash_list_header(const struct ip_set_ipporthash *map,
-                        struct ip_set_req_ipporthash_create *header)
+static const struct nla_policy
+hash_ipport_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
+       [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+       [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+       [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+       [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
+
+static int
+hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
 {
-       header->from = map->first_ip;
-       header->to = map->last_ip;
-}
+       struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
+       u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+       struct chash *h;
 
-HASH_LIST_HEADER(ipporthash)
-HASH_LIST_MEMBERS_SIZE(ipporthash, ip_set_ip_t)
-HASH_LIST_MEMBERS(ipporthash, ip_set_ip_t)
+       if (!(set->family == AF_INET || set->family == AF_INET6))
+               return -IPSET_ERR_INVALID_FAMILY;
 
-IP_SET_RTYPE(ipporthash, IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_DATA_DOUBLE)
+       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
+                     hash_ipport_create_policy))
+               return -IPSET_ERR_PROTOCOL;
 
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-MODULE_DESCRIPTION("ipporthash type of IP sets");
-module_param(limit, int, 0600);
-MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
+       if (tb[IPSET_ATTR_HASHSIZE]) {
+               hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
+               if (hashsize < IPSET_MIMINAL_HASHSIZE)
+                       hashsize = IPSET_MIMINAL_HASHSIZE;
+       }
+
+       if (tb[IPSET_ATTR_MAXELEM])
+               maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
+
+       h = kzalloc(sizeof(*h), GFP_KERNEL);
+       if (!h)
+               return -ENOMEM;
+
+       h->maxelem = maxelem;
+       h->htable_bits = htable_bits(hashsize);
+       h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
+       h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
+       get_random_bytes(&h->initval, sizeof(h->initval));
+       h->timeout = IPSET_NO_TIMEOUT;
+
+       h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
+                                GFP_KERNEL, &set->flags);
+       if (!h->htable) {
+               kfree(h);
+               return -ENOMEM;
+       }
+
+       set->data = h;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+               
+               set->variant = set->family == AF_INET
+                       ? &hash_ipport4_tvariant : &hash_ipport6_tvariant;
+
+               if (set->family == AF_INET)
+                       hash_ipport4_gc_init(set);
+               else
+                       hash_ipport6_gc_init(set);
+       } else {
+               set->variant = set->family == AF_INET
+                       ? &hash_ipport4_variant : &hash_ipport6_variant;
+       }
+       
+       pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
+                set->name, jhash_size(h->htable_bits),
+                h->htable_bits, h->maxelem, set->data, h->htable);
+          
+       return 0;
+}
+
+static struct ip_set_type hash_ipport_type = {
+       .name           = "hash:ip,port",
+       .protocol       = IPSET_PROTOCOL,
+       .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT,
+       .dimension      = IPSET_DIM_TWO,
+       .family         = AF_UNSPEC,
+       .revision       = 0,
+       .create         = hash_ipport_create,
+       .me             = THIS_MODULE,
+};
+
+static int __init
+hash_ipport_init(void)
+{
+       return ip_set_type_register(&hash_ipport_type);
+}
+
+static void __exit
+hash_ipport_fini(void)
+{
+       ip_set_type_unregister(&hash_ipport_type);
+}
 
-REGISTER_MODULE(ipporthash)
+module_init(hash_ipport_init);
+module_exit(hash_ipport_fini);
index 8b8f2a2a6f1f30a097df46126fb1a0e9f6bf96fb..fbf278010b40ed9f753b07b7e9b20386d10d714e 100644 (file)
-/* Copyright (C) 2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2010 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 */
+/* Kernel module implementing an IP set type: the hash:ip,port,ip type */
 
+#include <linux/netfilter/ip_set_kernel.h>
+#include <linux/netfilter/ip_set_jhash.h>
 #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/netfilter_ipv4/ip_set_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 <net/ipv6.h>
+#include <net/netlink.h>
+#include <net/pfxlen.h>
 
-#include <linux/netfilter_ipv4/ip_set_ipportiphash.h>
-#include <linux/netfilter_ipv4/ip_set_getport.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/ip_set.h>
+#include <linux/netfilter/ip_set_timeout.h>
+#include <linux/netfilter/ip_set_getport.h>
+#include <linux/netfilter/ip_set_hash.h>
 
-static int limit = MAX_RANGE;
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("hash:ip,port,ip type of IP sets");
+MODULE_ALIAS("ip_set_hash:ip,port,ip");
+
+/* Type specific function prefix */
+#define TYPE           hash_ipportip
+
+static bool
+hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b);
+
+#define hash_ipportip4_same_set        hash_ipportip_same_set
+#define hash_ipportip6_same_set        hash_ipportip_same_set
+
+/* The type variant functions: IPv4 */
+
+/* Member elements without timeout */
+struct hash_ipportip4_elem {
+       u32 ip;
+       u32 ip2;
+       u16 port;
+       u16 match;
+};
+
+/* Member elements with timeout support */
+struct hash_ipportip4_telem {
+       u32 ip;
+       u32 ip2;
+       u16 port;
+       u16 match;
+       unsigned long timeout;
+};
+
+static inline bool
+hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
+                         const struct hash_ipportip4_elem *ip2)
+{
+       return ip1->ip == ip2->ip
+              && ip1->ip2 == ip2->ip2
+              && ip1->port == ip2->port;
+}
 
-#define jhash_ip2(map, i, ipport, ip1)         \
-       jhash_2words(ipport, ip1, *(map->initval + i))
+static inline bool
+hash_ipportip4_data_isnull(const struct hash_ipportip4_elem *elem)
+{
+       return elem->match == 0;
+}
 
-static inline __u32
-ipportiphash_id(struct ip_set *set,
-               ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+static inline void
+hash_ipportip4_data_copy(struct hash_ipportip4_elem *dst,
+                        const struct hash_ipportip4_elem *src)
 {
-       struct ip_set_ipportiphash *map = set->data;
-       __u32 id;
-       u_int16_t i;
-       struct ipportip *elem;
+       memcpy(dst, src, sizeof(*dst));
+       dst->match = 1;
+}
 
-       ip = pack_ip_port(map, ip, port);
-       if (!(ip || ip1))
-               return UINT_MAX;
-       
-       for (i = 0; i < map->probes; i++) {
-               id = jhash_ip2(map, i, ip, ip1) % map->hashsize;
-               DP("hash key: %u", id);
-               elem = HARRAY_ELEM(map->members, struct ipportip *, id);
-               if (elem->ip == ip && elem->ip1 == ip1)
-                       return id;
-               /* No shortcut - there can be deleted entries. */
-       }
-       return UINT_MAX;
+static inline void
+hash_ipportip4_data_swap(struct hash_ipportip4_elem *dst,
+                        struct hash_ipportip4_elem *src)
+{
+       struct hash_ipportip4_elem tmp;
+
+       memcpy(&tmp, dst, sizeof(tmp));
+       memcpy(dst, src, sizeof(tmp));
+       memcpy(src, &tmp, sizeof(tmp));
 }
 
-static inline int
-ipportiphash_test(struct ip_set *set,
-                 ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+static inline void
+hash_ipportip4_data_zero_out(struct hash_ipportip4_elem *elem)
 {
-       struct ip_set_ipportiphash *map = set->data;
+       elem->match = 0;
+}
+
+static inline bool
+hash_ipportip4_data_list(struct sk_buff *skb,
+                      const struct hash_ipportip4_elem *data)
+{
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP2, data->ip2);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+       return 0;
+
+nla_put_failure:
+       return 1;
+}
+
+static inline bool
+hash_ipportip4_data_tlist(struct sk_buff *skb,
+                       const struct hash_ipportip4_elem *data)
+{
+       const struct hash_ipportip4_telem *tdata =
+               (const struct hash_ipportip4_telem *)data;
+
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP2, tdata->ip2);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
+       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                     htonl(ip_set_timeout_get(tdata->timeout)));
+
+       return 0;
+
+nla_put_failure:
+       return 1;
+}
+
+#define PF             4
+#define HOST_MASK      32
+#include <linux/netfilter/ip_set_chash.h>
+
+static int
+hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
+                   enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+{
+       struct chash *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipportip4_elem data = {};
        
-       if (ip < map->first_ip || ip > map->last_ip)
-               return -ERANGE;
-
-       return (ipportiphash_id(set, ip, port, ip1) != UINT_MAX);
-}
-
-#define KADT_CONDITION                                         \
-       ip_set_ip_t port, ip1;                                  \
-                                                               \
-       if (flags[2] == 0)                                      \
-               return 0;                                       \
-                                                               \
-       port = get_port(skb, flags++);                          \
-       ip1 = ipaddr(skb, flags++);                             \
-                                                               \
-       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 ip, ip_set_ip_t ip1)
-{
-       __u32 probe;
-       u_int16_t i;
-       struct ipportip *elem, *slot = NULL;
-
-       for (i = 0; i < map->probes; i++) {
-               probe = jhash_ip2(map, i, ip, ip1) % map->hashsize;
-               elem = HARRAY_ELEM(map->members, struct ipportip *, probe);
-               if (elem->ip == ip && elem->ip1 == ip1)
-                       return -EEXIST;
-               if (!(slot || elem->ip || elem->ip1))
-                       slot = elem;
-               /* There can be deleted entries, must check all slots */
+       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
+       if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
+               return -EINVAL;
+       ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
+
+       return adtfn(set, &data, GFP_ATOMIC, h->timeout);
+}
+
+static const struct nla_policy
+hash_ipportip4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+       [IPSET_ATTR_IP]         = { .type = NLA_U32 },
+       [IPSET_ATTR_IP2]        = { .type = NLA_U32 },
+       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
+
+static int
+hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
+                   enum ipset_adt adt, u32 *lineno, u32 flags)
+{
+       struct chash *h = set->data;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX];
+       bool eexist = flags & IPSET_FLAG_EXIST;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipportip4_elem data = {};
+       u32 timeout = h->timeout;
+       int ret;
+
+       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
+                     hash_ipportip4_adt_policy))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP])
+               data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP2])
+               data.ip2 = ip_set_get_n32(tb[IPSET_ATTR_IP2]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_PORT])
+               data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!with_timeout(h->timeout))
+                       return -IPSET_ERR_TIMEOUT;
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
-       if (slot) {
-               slot->ip = ip;
-               slot->ip1 = ip1;
-               map->elements++;
-               return 0;
+
+       ret = adtfn(set, &data, GFP_KERNEL, timeout);
+
+       if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
+               if (tb[IPSET_ATTR_LINENO])
+                       *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
        }
-       /* Trigger rehashing */
-       return -EAGAIN;
+       return ret;
 }
 
-static inline int
-__ipportiphash_add(struct ip_set_ipportiphash *map,
-                  struct ipportip *elem)
+static bool
+hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b)
 {
-       return __ipportip_add(map, elem->ip, elem->ip1);
+       struct chash *x = a->data;
+       struct chash *y = b->data;
+       
+       return x->maxelem == y->maxelem
+              && x->timeout == y->timeout
+              && x->htable_bits == y->htable_bits      /* resizing ? */
+              && x->array_size == y->array_size
+              && x->chain_limit == y->chain_limit;
 }
 
-static inline int
-ipportiphash_add(struct ip_set *set,
-                ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+/* The type variant functions: IPv6 */
+
+struct hash_ipportip6_elem {
+       union nf_inet_addr ip;
+       union nf_inet_addr ip2;
+       u16 port;
+       u16 match;
+};
+
+struct hash_ipportip6_telem {
+       union nf_inet_addr ip;
+       union nf_inet_addr ip2;
+       u16 port;
+       u16 match;
+       unsigned long timeout;
+};
+
+static inline bool
+hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
+                         const struct hash_ipportip6_elem *ip2)
 {
-       struct ip_set_ipportiphash *map = set->data;
-       
-       if (map->elements > limit)
-               return -ERANGE;
-       if (ip < map->first_ip || ip > map->last_ip)
-               return -ERANGE;
-
-       ip = pack_ip_port(map, ip, port);
-       if (!(ip || ip1))
-               return -ERANGE;
-       
-       return __ipportip_add(map, ip, ip1);
+       return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
+              && ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0
+              && ip1->port == ip2->port;
 }
 
-UADT(ipportiphash, add, req->port, req->ip1)
-KADT(ipportiphash, add, ipaddr, port, ip1)
+static inline bool
+hash_ipportip6_data_isnull(const struct hash_ipportip6_elem *elem)
+{
+       return elem->match == 0;
+}
 
 static inline void
-__ipportiphash_retry(struct ip_set_ipportiphash *tmp,
-                    struct ip_set_ipportiphash *map)
+hash_ipportip6_data_copy(struct hash_ipportip6_elem *dst,
+                        const struct hash_ipportip6_elem *src)
 {
-       tmp->first_ip = map->first_ip;
-       tmp->last_ip = map->last_ip;
+       memcpy(dst, src, sizeof(*dst));
+       dst->match = 1;
 }
 
-HASH_RETRY2(ipportiphash, struct ipportip)
-
-static inline int
-ipportiphash_del(struct ip_set *set,
-              ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+static inline void
+hash_ipportip6_data_swap(struct hash_ipportip6_elem *dst,
+                        struct hash_ipportip6_elem *src)
 {
-       struct ip_set_ipportiphash *map = set->data;
-       ip_set_ip_t id;
-       struct ipportip *elem;
+       struct hash_ipportip6_elem tmp;
+       
+       memcpy(&tmp, dst, sizeof(tmp));
+       memcpy(dst, src, sizeof(tmp));
+       memcpy(src, &tmp, sizeof(tmp));
+}
 
-       if (ip < map->first_ip || ip > map->last_ip)
-               return -ERANGE;
+static inline void
+hash_ipportip6_data_zero_out(struct hash_ipportip6_elem *elem)
+{
+       elem->match = 0;
+}
 
-       id = ipportiphash_id(set, ip, port, ip1);
+static inline bool
+hash_ipportip6_data_list(struct sk_buff *skb,
+                        const struct hash_ipportip6_elem *data)
+{
+       NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
+       NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+       return 0;
 
-       if (id == UINT_MAX)
-               return -EEXIST;
-               
-       elem = HARRAY_ELEM(map->members, struct ipportip *, id);
-       elem->ip = elem->ip1 = 0;
-       map->elements--;
+nla_put_failure:
+       return 1;
+}
 
+static inline bool
+hash_ipportip6_data_tlist(struct sk_buff *skb,
+                         const struct hash_ipportip6_elem *data)
+{
+       const struct hash_ipportip6_telem *e = 
+               (const struct hash_ipportip6_telem *)data;
+       
+       NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
+       NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                     htonl(ip_set_timeout_get(e->timeout)));
        return 0;
+
+nla_put_failure:
+       return 1;
 }
 
-UADT(ipportiphash, del, req->port, req->ip1)
-KADT(ipportiphash, del, ipaddr, port, ip1)
+#undef PF
+#undef HOST_MASK
+
+#define PF             6
+#define HOST_MASK      128
+#include <linux/netfilter/ip_set_chash.h>
+
+static int
+hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
+                   enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+{
+       struct chash *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipportip6_elem data = {};
+
+       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+       if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
+               return -EINVAL;
+       ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
+
+       return adtfn(set, &data, GFP_ATOMIC, h->timeout);
+}
 
-static inline int
-__ipportiphash_create(const struct ip_set_req_ipportiphash_create *req,
-                     struct ip_set_ipportiphash *map)
+static const struct nla_policy
+hash_ipportip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+       [IPSET_ATTR_IP]         = { .type = NLA_BINARY,
+                                   .len = sizeof(struct in6_addr) },
+       [IPSET_ATTR_IP2]        = { .type = NLA_BINARY,
+                                   .len = sizeof(struct in6_addr) },
+       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
+
+static int
+hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
+                   enum ipset_adt adt, u32 *lineno, u32 flags)
 {
-       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;
+       struct chash *h = set->data;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX];
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipportip6_elem data = {};
+       u32 timeout = h->timeout;
+
+       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
+                     hash_ipportip6_adt_policy))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP])
+               memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
+                      sizeof(struct in6_addr));
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP2])
+               memcpy(&data.ip2, nla_data(tb[IPSET_ATTR_IP2]),
+                      sizeof(struct in6_addr));
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_PORT])
+               data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!with_timeout(h->timeout))
+                       return -IPSET_ERR_TIMEOUT;
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
-       map->first_ip = req->from;
-       map->last_ip = req->to;
-       return 0;
+
+       return adtfn(set, &data, GFP_KERNEL, timeout);
 }
 
-HASH_CREATE(ipportiphash, struct ipportip)
-HASH_DESTROY(ipportiphash)
-HASH_FLUSH(ipportiphash, struct ipportip)
+/* Create hash:ip type of sets */
 
-static inline void
-__ipportiphash_list_header(const struct ip_set_ipportiphash *map,
-                          struct ip_set_req_ipportiphash_create *header)
+static const struct nla_policy
+hash_ipportip_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
+       [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+       [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+       [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+       [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
+
+static int
+hash_ipportip_create(struct ip_set *set, struct nlattr *head,
+                    int len, u32 flags)
 {
-       header->from = map->first_ip;
-       header->to = map->last_ip;
-}
+       struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
+       u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+       struct chash *h;
 
-HASH_LIST_HEADER(ipportiphash)
-HASH_LIST_MEMBERS_SIZE(ipportiphash, struct ipportip)
-HASH_LIST_MEMBERS_MEMCPY(ipportiphash, struct ipportip,
-                        (elem->ip || elem->ip1))
+       if (!(set->family == AF_INET || set->family == AF_INET6))
+               return -IPSET_ERR_INVALID_FAMILY;
 
-IP_SET_RTYPE(ipportiphash, IPSET_TYPE_IP | IPSET_TYPE_PORT
-                          | IPSET_TYPE_IP1 | IPSET_DATA_TRIPLE)
+       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
+                     hash_ipportip_create_policy))
+               return -IPSET_ERR_PROTOCOL;
 
-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");
+       if (tb[IPSET_ATTR_HASHSIZE]) {
+               hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
+               if (hashsize < IPSET_MIMINAL_HASHSIZE)
+                       hashsize = IPSET_MIMINAL_HASHSIZE;
+       }
+
+       if (tb[IPSET_ATTR_MAXELEM])
+               maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
+
+       h = kzalloc(sizeof(*h), GFP_KERNEL);
+       if (!h)
+               return -ENOMEM;
+
+       h->maxelem = maxelem;
+       h->htable_bits = htable_bits(hashsize);
+       h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
+       h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
+       get_random_bytes(&h->initval, sizeof(h->initval));
+       h->timeout = IPSET_NO_TIMEOUT;
+
+       h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
+                                GFP_KERNEL, &set->flags);
+       if (!h->htable) {
+               kfree(h);
+               return -ENOMEM;
+       }
+
+       set->data = h;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+               
+               set->variant = set->family == AF_INET
+                       ? &hash_ipportip4_tvariant : &hash_ipportip6_tvariant;
+
+               if (set->family == AF_INET)
+                       hash_ipportip4_gc_init(set);
+               else
+                       hash_ipportip6_gc_init(set);
+       } else {
+               set->variant = set->family == AF_INET
+                       ? &hash_ipportip4_variant : &hash_ipportip6_variant;
+       }
+       
+       pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
+                set->name, jhash_size(h->htable_bits),
+                h->htable_bits, h->maxelem, set->data, h->htable);
+          
+       return 0;
+}
+
+static struct ip_set_type hash_ipportip_type = {
+       .name           = "hash:ip,port,ip",
+       .protocol       = IPSET_PROTOCOL,
+       .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
+       .dimension      = IPSET_DIM_THREE,
+       .family         = AF_UNSPEC,
+       .revision       = 0,
+       .create         = hash_ipportip_create,
+       .me             = THIS_MODULE,
+};
+
+static int __init
+hash_ipportip_init(void)
+{
+       return ip_set_type_register(&hash_ipportip_type);
+}
+
+static void __exit
+hash_ipportip_fini(void)
+{
+       ip_set_type_unregister(&hash_ipportip_type);
+}
 
-REGISTER_MODULE(ipportiphash)
+module_init(hash_ipportip_init);
+module_exit(hash_ipportip_fini);
index e0bb352942ad36bec2603294be6b5443b7c5096a..dfe934898b6ab7fc8f3e6c00d966c1fcccb1bae2 100644 (file)
-/* Copyright (C) 2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2010 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 */
+/* Kernel module implementing an IP set type: the hash:ip,port,net type */
 
+#include <linux/netfilter/ip_set_kernel.h>
+#include <linux/netfilter/ip_set_jhash.h>
 #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/netfilter_ipv4/ip_set_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 <net/ipv6.h>
+#include <net/netlink.h>
+#include <net/pfxlen.h>
 
-#include <linux/netfilter_ipv4/ip_set_ipportnethash.h>
-#include <linux/netfilter_ipv4/ip_set_getport.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/ip_set.h>
+#include <linux/netfilter/ip_set_timeout.h>
+#include <linux/netfilter/ip_set_getport.h>
+#include <linux/netfilter/ip_set_hash.h>
 
-static int limit = MAX_RANGE;
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("hash:ip,port,net type of IP sets");
+MODULE_ALIAS("ip_set_hash:ip,port,net");
+
+/* Type specific function prefix */
+#define TYPE           hash_ipportnet
+
+static bool
+hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b);
+
+#define hash_ipportnet4_same_set       hash_ipportnet_same_set
+#define hash_ipportnet6_same_set       hash_ipportnet_same_set
+
+/* The type variant functions: IPv4 */
+
+/* Member elements without timeout */
+struct hash_ipportnet4_elem {
+       u32 ip;
+       u32 ip2;
+       u16 port;
+       u8 cidr;
+       u8 match;
+};
+
+/* Member elements with timeout support */
+struct hash_ipportnet4_telem {
+       u32 ip;
+       u32 ip2;
+       u16 port;
+       u8 cidr;
+       u8 match;
+       unsigned long timeout;
+};
+
+static inline bool
+hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
+                          const struct hash_ipportnet4_elem *ip2)
+{
+       return ip1->ip == ip2->ip
+              && ip1->ip2 == ip2->ip2
+              && ip1->cidr == ip2->cidr
+              && ip1->port == ip2->port;
+}
 
-#define jhash_ip2(map, i, ipport, ip1)         \
-       jhash_2words(ipport, ip1, *(map->initval + i))
+static inline bool
+hash_ipportnet4_data_isnull(const struct hash_ipportnet4_elem *elem)
+{
+       return elem->match == 0;
+}
 
-static inline __u32
-ipportnethash_id_cidr(struct ip_set *set,
-                     ip_set_ip_t ip, ip_set_ip_t port,
-                     ip_set_ip_t ip1, uint8_t cidr)
+static inline void
+hash_ipportnet4_data_copy(struct hash_ipportnet4_elem *dst,
+                         const struct hash_ipportnet4_elem *src)
 {
-       struct ip_set_ipportnethash *map = set->data;
-       __u32 id;
-       u_int16_t i;
-       struct ipportip *elem;
-
-       ip = pack_ip_port(map, ip, port);
-       ip1 = pack_ip_cidr(ip1, cidr);
-       if (!(ip || ip1))
-               return UINT_MAX;
-       
-       for (i = 0; i < map->probes; i++) {
-               id = jhash_ip2(map, i, ip, ip1) % map->hashsize;
-               DP("hash key: %u", id);
-               elem = HARRAY_ELEM(map->members, struct ipportip *, id);
-               if (elem->ip == ip && elem->ip1 == ip1)
-                       return id;
-               /* No shortcut - there can be deleted entries. */
-       }
-       return UINT_MAX;
+       memcpy(dst, src, sizeof(*dst));
+       dst->match = 1;
 }
 
-static inline __u32
-ipportnethash_id(struct ip_set *set,
-                ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+static inline void
+hash_ipportnet4_data_swap(struct hash_ipportnet4_elem *dst,
+                         struct hash_ipportnet4_elem *src)
 {
-       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, ip, port, ip1, map->cidr[i]);
-               if (id != UINT_MAX)
-                       break;
-       }
-       return id;
+       struct hash_ipportnet4_elem tmp;
+
+       memcpy(&tmp, dst, sizeof(tmp));
+       memcpy(dst, src, sizeof(tmp));
+       memcpy(src, &tmp, sizeof(tmp));
+}
+
+static inline void
+hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
+{
+       elem->ip2 &= NETMASK(cidr);
+       elem->cidr = cidr;
 }
 
-static inline int
-ipportnethash_test_cidr(struct ip_set *set,
-                       ip_set_ip_t ip, ip_set_ip_t port,
-                       ip_set_ip_t ip1, uint8_t cidr)
+static inline void
+hash_ipportnet4_data_zero_out(struct hash_ipportnet4_elem *elem)
 {
-       struct ip_set_ipportnethash *map = set->data;
-       
-       if (ip < map->first_ip || ip > map->last_ip)
-               return -ERANGE;
+       elem->match = 0;
+}
+
+static inline bool
+hash_ipportnet4_data_list(struct sk_buff *skb,
+                         const struct hash_ipportnet4_elem *data)
+{
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP2, data->ip2);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+       return 0;
 
-       return (ipportnethash_id_cidr(set, ip, port, ip1, cidr) != UINT_MAX);
+nla_put_failure:
+       return 1;
 }
 
-static inline int
-ipportnethash_test(struct ip_set *set,
-                 ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
+static inline bool
+hash_ipportnet4_data_tlist(struct sk_buff *skb,
+                          const struct hash_ipportnet4_elem *data)
 {
-       struct ip_set_ipportnethash *map = set->data;
-       
-       if (ip < map->first_ip || ip > map->last_ip)
-               return -ERANGE;
+       const struct hash_ipportnet4_telem *tdata =
+               (const struct hash_ipportnet4_telem *)data;
+
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP2, tdata->ip2);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                     htonl(ip_set_timeout_get(tdata->timeout)));
 
-       return (ipportnethash_id(set, ip, port, ip1) != UINT_MAX);
+       return 0;
+
+nla_put_failure:
+       return 1;
 }
 
+#define IP_SET_HASH_WITH_NETS
+
+#define PF             4
+#define HOST_MASK      32
+#include <linux/netfilter/ip_set_chash.h>
+
 static int
-ipportnethash_utest(struct ip_set *set, const void *data, u_int32_t size)
+hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
+                    enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
-       const struct ip_set_req_ipportnethash *req = data;
+       struct chash *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipportnet4_elem data =
+               { .cidr = h->nets[0].cidr || HOST_MASK };
+       
+       if (data.cidr == 0)
+               return -EINVAL;
+       if (adt == IPSET_TEST)
+               data.cidr = HOST_MASK;
 
-       if (req->cidr <= 0 || req->cidr > 32)
+       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
+       if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
                return -EINVAL;
-       return (req->cidr == 32 
-               ? ipportnethash_test(set, req->ip, req->port, req->ip1)
-               : ipportnethash_test_cidr(set, req->ip, req->port,
-                                         req->ip1, req->cidr));
+       ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
+       data.ip2 &= NETMASK(data.cidr);
+
+       return adtfn(set, &data, GFP_ATOMIC, h->timeout);
 }
 
-#define KADT_CONDITION                                         \
-       ip_set_ip_t port, ip1;                                  \
-                                                               \
-       if (flags[2] == 0)                                      \
-               return 0;                                       \
-                                                               \
-       port = get_port(skb, flags++);                          \
-       ip1 = ipaddr(skb, flags++);                             \
-                                                               \
-       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 ip, ip_set_ip_t ip1)
+static const struct nla_policy
+hash_ipportnet4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+       [IPSET_ATTR_IP]         = { .type = NLA_U32 },
+       [IPSET_ATTR_IP2]        = { .type = NLA_U32 },
+       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+       [IPSET_ATTR_CIDR2]      = { .type = NLA_U8 },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
+
+static int
+hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
+                    enum ipset_adt adt, u32 *lineno, u32 flags)
 {
-       __u32 probe;
-       u_int16_t i;
-       struct ipportip *elem, *slot = NULL;
-
-       for (i = 0; i < map->probes; i++) {
-               probe = jhash_ip2(map, i, ip, ip1) % map->hashsize;
-               elem = HARRAY_ELEM(map->members, struct ipportip *, probe);
-               if (elem->ip == ip && elem->ip1 == ip1)
-                       return -EEXIST;
-               if (!(slot || elem->ip || elem->ip1))
-                       slot = elem;
-               /* There can be deleted entries, must check all slots */
+       struct chash *h = set->data;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX];
+       bool eexist = flags & IPSET_FLAG_EXIST;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
+       u32 timeout = h->timeout;
+       int ret;
+
+       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
+                     hash_ipportnet4_adt_policy))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP])
+               data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP2])
+               data.ip2 = ip_set_get_n32(tb[IPSET_ATTR_IP2]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_CIDR2])
+               data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
+
+       if (!data.cidr)
+               return -IPSET_ERR_INVALID_CIDR;
+
+       data.ip2 &= NETMASK(data.cidr);
+
+       if (tb[IPSET_ATTR_PORT])
+               data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!with_timeout(h->timeout))
+                       return -IPSET_ERR_TIMEOUT;
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
-       if (slot) {
-               slot->ip = ip;
-               slot->ip1 = ip1;
-               map->elements++;
-               return 0;
+
+       ret = adtfn(set, &data, GFP_KERNEL, timeout);
+
+       if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
+               if (tb[IPSET_ATTR_LINENO])
+                       *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
        }
-       /* Trigger rehashing */
-       return -EAGAIN;
+       return ret;
 }
 
-static inline int
-__ipportnethash_add(struct ip_set_ipportnethash *map,
-                   struct ipportip *elem)
+static bool
+hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b)
 {
-       return __ipportnet_add(map, elem->ip, elem->ip1);
+       struct chash *x = a->data;
+       struct chash *y = b->data;
+       
+       return x->maxelem == y->maxelem
+              && x->timeout == y->timeout
+              && x->htable_bits == y->htable_bits      /* resizing ? */
+              && x->array_size == y->array_size
+              && x->chain_limit == y->chain_limit;
 }
 
-static inline int
-ipportnethash_add(struct ip_set *set,
-                ip_set_ip_t ip, ip_set_ip_t port,
-                ip_set_ip_t ip1, uint8_t cidr)
+/* The type variant functions: IPv6 */
+
+struct hash_ipportnet6_elem {
+       union nf_inet_addr ip;
+       union nf_inet_addr ip2;
+       u16 port;
+       u8 cidr;
+       u8 match;
+};
+
+struct hash_ipportnet6_telem {
+       union nf_inet_addr ip;
+       union nf_inet_addr ip2;
+       u16 port;
+       u8 cidr;
+       u8 match;
+       unsigned long timeout;
+};
+
+static inline bool
+hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
+                          const struct hash_ipportnet6_elem *ip2)
 {
-       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;
+       return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
+              && ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0
+              && ip1->cidr == ip2->cidr
+              && ip1->port == ip2->port;
+}
 
-       ip = pack_ip_port(map, ip, port);
-       ip1 = pack_ip_cidr(ip1, cidr);
-       if (!(ip || ip1))
-               return -ERANGE;
-       
-       ret =__ipportnet_add(map, ip, ip1);
-       if (ret == 0) {
-               if (!map->nets[cidr-1]++)
-                       add_cidr_size(map->cidr, cidr);
-       }
-       return ret;
+static inline bool
+hash_ipportnet6_data_isnull(const struct hash_ipportnet6_elem *elem)
+{
+       return elem->match == 0;
 }
 
-#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[2] == 0)                                              \
-               return 0;                                               \
-                                                                       \
-       port = get_port(skb, flags++);                                  \
-       ip1 = ipaddr(skb, flags++);                                     \
-                                                                       \
-       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
+hash_ipportnet6_data_copy(struct hash_ipportnet6_elem *dst,
+                         const struct hash_ipportnet6_elem *src)
+{
+       memcpy(dst, src, sizeof(*dst));
+       dst->match = 1;
+}
 
 static inline void
-__ipportnethash_retry(struct ip_set_ipportnethash *tmp,
-                     struct ip_set_ipportnethash *map)
+hash_ipportnet6_data_swap(struct hash_ipportnet6_elem *dst,
+                        struct hash_ipportnet6_elem *src)
 {
-       tmp->first_ip = map->first_ip;
-       tmp->last_ip = map->last_ip;
-       memcpy(tmp->cidr, map->cidr, sizeof(tmp->cidr));
-       memcpy(tmp->nets, map->nets, sizeof(tmp->nets));
+       struct hash_ipportnet6_elem tmp;
+       
+       memcpy(&tmp, dst, sizeof(tmp));
+       memcpy(dst, src, sizeof(tmp));
+       memcpy(src, &tmp, sizeof(tmp));
 }
 
-HASH_RETRY2(ipportnethash, struct ipportip)
+static inline void
+hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem)
+{
+       elem->match = 0;
+}
 
-static inline int
-ipportnethash_del(struct ip_set *set,
-                 ip_set_ip_t ip, ip_set_ip_t port,
-                 ip_set_ip_t ip1, uint8_t cidr)
+static inline void
+ip6_netmask(union nf_inet_addr *ip, u8 prefix)
 {
-       struct ip_set_ipportnethash *map = set->data;
-       ip_set_ip_t id;
-       struct ipportip *elem;
+       ip->ip6[0] &= NETMASK6(prefix)[0];
+       ip->ip6[1] &= NETMASK6(prefix)[1];
+       ip->ip6[2] &= NETMASK6(prefix)[2];
+       ip->ip6[3] &= NETMASK6(prefix)[3];
+}
 
-       if (ip < map->first_ip || ip > map->last_ip)
-               return -ERANGE;
-       if (!ip)
-               return -ERANGE;
-       if (cidr <= 0 || cidr >= 32)
-               return -EINVAL; 
+static inline void
+hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr)
+{
+       ip6_netmask(&elem->ip2, cidr);
+       elem->cidr = cidr;
+}
 
-       id = ipportnethash_id_cidr(set, ip, port, ip1, cidr);
+static inline bool
+hash_ipportnet6_data_list(struct sk_buff *skb,
+                         const struct hash_ipportnet6_elem *data)
+{
+       NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
+       NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+       return 0;
 
-       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);
+nla_put_failure:
+       return 1;
+}
 
+static inline bool
+hash_ipportnet6_data_tlist(struct sk_buff *skb,
+                          const struct hash_ipportnet6_elem *data)
+{
+       const struct hash_ipportnet6_telem *e = 
+               (const struct hash_ipportnet6_telem *)data;
+       
+       NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
+       NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
+       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                     htonl(ip_set_timeout_get(e->timeout)));
        return 0;
+
+nla_put_failure:
+       return 1;
 }
 
-UADT(ipportnethash, del, req->port, req->ip1, req->cidr)
-KADT(ipportnethash, del, ipaddr, port, ip1, cidr)
+#undef PF
+#undef HOST_MASK
+
+#define PF             6
+#define HOST_MASK      128
+#include <linux/netfilter/ip_set_chash.h>
 
-static inline int
-__ipportnethash_create(const struct ip_set_req_ipportnethash_create *req,
-                      struct ip_set_ipportnethash *map)
+static int
+hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
+                    enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
-       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, sizeof(map->cidr));
-       memset(map->nets, 0, sizeof(map->nets));
-       return 0;
+       struct chash *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipportnet6_elem data =
+               { .cidr = h->nets[0].cidr || HOST_MASK };
+
+       if (data.cidr == 0)
+               return -EINVAL;
+       if (adt == IPSET_TEST)
+               data.cidr = HOST_MASK;
+
+       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+       if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
+               return -EINVAL;
+       ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
+       ip6_netmask(&data.ip2, data.cidr);
+
+       return adtfn(set, &data, GFP_ATOMIC, h->timeout);
 }
 
-HASH_CREATE(ipportnethash, struct ipportip)
-HASH_DESTROY(ipportnethash)
-HASH_FLUSH_CIDR(ipportnethash, struct ipportip);
+static const struct nla_policy
+hash_ipportnet6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+       [IPSET_ATTR_IP]         = { .type = NLA_BINARY,
+                                   .len = sizeof(struct in6_addr) },
+       [IPSET_ATTR_IP2]        = { .type = NLA_BINARY,
+                                   .len = sizeof(struct in6_addr) },
+       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+       [IPSET_ATTR_CIDR2]      = { .type = NLA_U8 },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
 
-static inline void
-__ipportnethash_list_header(const struct ip_set_ipportnethash *map,
-                           struct ip_set_req_ipportnethash_create *header)
+static int
+hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
+                    enum ipset_adt adt, u32 *lineno, u32 flags)
 {
-       header->from = map->first_ip;
-       header->to = map->last_ip;
+       struct chash *h = set->data;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX];
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
+       u32 timeout = h->timeout;
+
+       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
+                     hash_ipportnet6_adt_policy))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP])
+               memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
+                      sizeof(struct in6_addr));
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP2])
+               memcpy(&data.ip2, nla_data(tb[IPSET_ATTR_IP2]),
+                      sizeof(struct in6_addr));
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_CIDR2])
+               data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
+
+       if (!data.cidr)
+               return -IPSET_ERR_INVALID_CIDR;
+
+       ip6_netmask(&data.ip2, data.cidr);
+
+       if (tb[IPSET_ATTR_PORT])
+               data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!with_timeout(h->timeout))
+                       return -IPSET_ERR_TIMEOUT;
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+       }
+
+       return adtfn(set, &data, GFP_KERNEL, timeout);
 }
 
-HASH_LIST_HEADER(ipportnethash)
+/* Create hash:ip type of sets */
+
+static const struct nla_policy
+hash_ipportnet_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
+       [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+       [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+       [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+       [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
+
+static int
+hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
+                    int len, u32 flags)
+{
+       struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
+       u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+       struct chash *h;
 
-HASH_LIST_MEMBERS_SIZE(ipportnethash, struct ipportip)
-HASH_LIST_MEMBERS_MEMCPY(ipportnethash, struct ipportip,
-                        (elem->ip || elem->ip1))
+       if (!(set->family == AF_INET || set->family == AF_INET6))
+               return -IPSET_ERR_INVALID_FAMILY;
 
-IP_SET_RTYPE(ipportnethash, IPSET_TYPE_IP | IPSET_TYPE_PORT
-                           | IPSET_TYPE_IP1 | IPSET_DATA_TRIPLE)
+       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
+                     hash_ipportnet_create_policy))
+               return -IPSET_ERR_PROTOCOL;
 
-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");
+       if (tb[IPSET_ATTR_HASHSIZE]) {
+               hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
+               if (hashsize < IPSET_MIMINAL_HASHSIZE)
+                       hashsize = IPSET_MIMINAL_HASHSIZE;
+       }
+
+       if (tb[IPSET_ATTR_MAXELEM])
+               maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
+
+       h = kzalloc(sizeof(*h)
+                   + sizeof(struct chash_nets)
+                     * (set->family == AF_INET ? 31 : 127), GFP_KERNEL);
+       if (!h)
+               return -ENOMEM;
+
+       h->maxelem = maxelem;
+       h->htable_bits = htable_bits(hashsize);
+       h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
+       h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
+       get_random_bytes(&h->initval, sizeof(h->initval));
+       h->timeout = IPSET_NO_TIMEOUT;
+
+       h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
+                                GFP_KERNEL, &set->flags);
+       if (!h->htable) {
+               kfree(h);
+               return -ENOMEM;
+       }
+
+       set->data = h;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+               
+               set->variant = set->family == AF_INET
+                       ? &hash_ipportnet4_tvariant : &hash_ipportnet6_tvariant;
+
+               if (set->family == AF_INET)
+                       hash_ipportnet4_gc_init(set);
+               else
+                       hash_ipportnet6_gc_init(set);
+       } else {
+               set->variant = set->family == AF_INET
+                       ? &hash_ipportnet4_variant : &hash_ipportnet6_variant;
+       }
+       
+       pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
+                set->name, jhash_size(h->htable_bits),
+                h->htable_bits, h->maxelem, set->data, h->htable);
+          
+       return 0;
+}
+
+static struct ip_set_type hash_ipportnet_type = {
+       .name           = "hash:ip,port,net",
+       .protocol       = IPSET_PROTOCOL,
+       .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
+       .dimension      = IPSET_DIM_THREE,
+       .family         = AF_UNSPEC,
+       .revision       = 0,
+       .create         = hash_ipportnet_create,
+       .me             = THIS_MODULE,
+};
+
+static int __init
+hash_ipportnet_init(void)
+{
+       return ip_set_type_register(&hash_ipportnet_type);
+}
+
+static void __exit
+hash_ipportnet_fini(void)
+{
+       ip_set_type_unregister(&hash_ipportnet_type);
+}
 
-REGISTER_MODULE(ipportnethash)
+module_init(hash_ipportnet_init);
+module_exit(hash_ipportnet_fini);
index e3b09e0cc52c37ed953faaa6271f0c30431e700c..a8611c25eb83ec7ba7e1656b929b382894972ae3 100644 (file)
-/* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2010 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 a cidr nethash set */
+/* Kernel module implementing an IP set type: the hash:net type */
 
+#include <linux/netfilter/ip_set_kernel.h>
+#include <linux/netfilter/ip_set_jhash.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/ip.h>
 #include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ip_set_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 <net/ipv6.h>
+#include <net/netlink.h>
+#include <net/pfxlen.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter/ip_set.h>
+#include <linux/netfilter/ip_set_timeout.h>
+#include <linux/netfilter/ip_set_hash.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("hash:net type of IP sets");
+MODULE_ALIAS("ip_set_hash:net");
+
+/* Type specific function prefix */
+#define TYPE           hash_net
+
+static bool
+hash_net_same_set(const struct ip_set *a, const struct ip_set *b);
+
+#define hash_net4_same_set     hash_net_same_set
+#define hash_net6_same_set     hash_net_same_set
 
-#include <linux/netfilter_ipv4/ip_set_nethash.h>
+/* The type variant functions: IPv4 */
 
-static int limit = MAX_RANGE;
+/* Member elements without timeout */
+struct hash_net4_elem {
+       u32 ip;
+       u8 cidr;        /* Not hashed, zero for null value */
+};
 
-static inline __u32
-nethash_id_cidr(const struct ip_set_nethash *map,
-               ip_set_ip_t ip,
-               uint8_t cidr)
+/* Member elements with timeout support */
+struct hash_net4_telem {
+       u32 ip;
+       u8 cidr;        /* Not hashed, zero for null value */
+       unsigned long timeout;
+};
+
+static inline bool
+hash_net4_data_equal(const struct hash_net4_elem *ip1,
+                   const struct hash_net4_elem *ip2)
 {
-       __u32 id;
-       u_int16_t i;
-       ip_set_ip_t *elem;
+       /* We don't have to check the cidr equality
+        * because overlapping nets cannot be added to the set
+        */
+       return ip1->ip == ip2->ip;
+}
 
-       ip = pack_ip_cidr(ip, cidr);
-       if (!ip)
-               return MAX_RANGE;
-       
-       for (i = 0; i < map->probes; i++) {
-               id = jhash_ip(map, i, ip) % map->hashsize;
-               DP("hash key: %u", id);
-               elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
-               if (*elem == ip)
-                       return id;
-               /* No shortcut - there can be deleted entries. */
-       }
-       return UINT_MAX;
+static inline bool
+hash_net4_data_isnull(const struct hash_net4_elem *elem)
+{
+       return elem->cidr == 0;
 }
 
-static inline __u32
-nethash_id(struct ip_set *set, ip_set_ip_t ip)
+static inline void
+hash_net4_data_copy(struct hash_net4_elem *dst,
+                   const struct hash_net4_elem *src)
 {
-       const struct ip_set_nethash *map = set->data;
-       __u32 id = UINT_MAX;
-       int i;
+       dst->ip = src->ip;
+       dst->cidr = src->cidr;
+}
 
-       for (i = 0; i < 30 && map->cidr[i]; i++) {
-               id = nethash_id_cidr(map, ip, map->cidr[i]);
-               if (id != UINT_MAX)
-                       break;
-       }
-       return id;
+static inline void
+hash_net4_data_swap(struct hash_net4_elem *dst,
+                   struct hash_net4_elem *src)
+{
+       swap(dst->ip, src->ip);
+       swap(dst->cidr, src->cidr);
 }
 
-static inline int
-nethash_test_cidr(struct ip_set *set, ip_set_ip_t ip, uint8_t cidr)
+static inline void
+hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
 {
-       const struct ip_set_nethash *map = set->data;
+       elem->ip &= NETMASK(cidr);
+       elem->cidr = cidr;
+}
 
-       return (nethash_id_cidr(map, ip, cidr) != UINT_MAX);
+/* Zero CIDR values cannot be stored */
+static inline void
+hash_net4_data_zero_out(struct hash_net4_elem *elem)
+{
+       elem->cidr = 0;
 }
 
-static inline int
-nethash_test(struct ip_set *set, ip_set_ip_t ip)
+static inline bool
+hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
 {
-       return (nethash_id(set, ip) != UINT_MAX);
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+       return 0;
+
+nla_put_failure:
+       return 1;
 }
 
-static int
-nethash_utest(struct ip_set *set, const void *data, u_int32_t size)
+static inline bool
+hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data)
 {
-       const struct ip_set_req_nethash *req = data;
+       const struct hash_net4_telem *tdata =
+               (const struct hash_net4_telem *)data;
 
-       if (req->cidr <= 0 || req->cidr > 32)
-               return -EINVAL;
-       return (req->cidr == 32 ? nethash_test(set, req->ip)
-               : nethash_test_cidr(set, req->ip, req->cidr));
+       NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, tdata->cidr);
+       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                     htonl(ip_set_timeout_get(tdata->timeout)));
+
+       return 0;
+
+nla_put_failure:
+       return 1;
 }
 
-#define KADT_CONDITION
+#define IP_SET_HASH_WITH_NETS
 
-KADT(nethash, test, ipaddr)
+#define PF             4
+#define HOST_MASK      32
+#include <linux/netfilter/ip_set_chash.h>
 
-static inline int
-__nethash_add(struct ip_set_nethash *map, ip_set_ip_t *ip)
+static int
+hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
+              enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
-       __u32 probe;
-       u_int16_t i;
-       ip_set_ip_t *elem, *slot = NULL;
+       struct chash *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_net4_elem data = { .cidr = h->nets[0].cidr || HOST_MASK };
        
-       for (i = 0; i < map->probes; i++) {
-               probe = jhash_ip(map, i, *ip) % map->hashsize;
-               elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
-               if (*elem == *ip)
-                       return -EEXIST;
-               if (!(slot || *elem))
-                       slot = elem;
-               /* There can be deleted entries, must check all slots */
-       }
-       if (slot) {
-               *slot = *ip;
-               map->elements++;
-               return 0;
-       }
-       /* Trigger rehashing */
-       return -EAGAIN;
+       if (data.cidr == 0)
+               return -EINVAL;
+       if (adt == IPSET_TEST)
+               data.cidr = HOST_MASK;
+
+       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
+       data.ip &= NETMASK(data.cidr);
+
+       return adtfn(set, &data, GFP_ATOMIC, h->timeout);
 }
 
-static inline int
-nethash_add(struct ip_set *set, ip_set_ip_t ip, uint8_t cidr)
+static const struct nla_policy
+hash_net4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+       [IPSET_ATTR_IP]         = { .type = NLA_U32 },
+       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
+
+static int
+hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len,
+              enum ipset_adt adt, u32 *lineno, u32 flags)
 {
-       struct ip_set_nethash *map = set->data;
+       struct chash *h = set->data;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX];
+       bool eexist = flags & IPSET_FLAG_EXIST;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_net4_elem data = { .cidr = HOST_MASK };
+       u32 timeout = h->timeout;
        int ret;
-       
-       if (map->elements >= limit || map->nets[cidr-1] == UINT16_MAX)
-               return -ERANGE; 
-       if (cidr <= 0 || cidr >= 32)
-               return -EINVAL;
 
-       ip = pack_ip_cidr(ip, cidr);
-       if (!ip)
-               return -ERANGE;
-       
-       ret = __nethash_add(map, &ip);
-       if (ret == 0) {
-               if (!map->nets[cidr-1]++)
-                       add_cidr_size(map->cidr, cidr);
+       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
+                     hash_net4_adt_policy))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP])
+               data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_CIDR])
+               data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+
+       if (!data.cidr)
+               return -IPSET_ERR_INVALID_CIDR;
+
+       data.ip &= NETMASK(data.cidr);
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!with_timeout(h->timeout))
+                       return -IPSET_ERR_TIMEOUT;
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+       }
+
+       ret = adtfn(set, &data, GFP_KERNEL, timeout);
+
+       if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
+               if (tb[IPSET_ATTR_LINENO])
+                       *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
        }
-       
        return ret;
 }
 
-#undef KADT_CONDITION
-#define KADT_CONDITION                                                 \
-       struct ip_set_nethash *map = set->data;                         \
-       uint8_t cidr = map->cidr[0] ? map->cidr[0] : 31;
+static bool
+hash_net_same_set(const struct ip_set *a, const struct ip_set *b)
+{
+       struct chash *x = a->data;
+       struct chash *y = b->data;
+       
+       return x->maxelem == y->maxelem
+              && x->timeout == y->timeout
+              && x->htable_bits == y->htable_bits      /* resizing ? */
+              && x->array_size == y->array_size
+              && x->chain_limit == y->chain_limit;
+}
+
+/* The type variant functions: IPv6 */
+
+struct hash_net6_elem {
+       union nf_inet_addr ip;
+       u8 cidr;        /* Not hashed */
+};
 
-UADT(nethash, add, req->cidr)
-KADT(nethash, add, ipaddr, cidr)
+struct hash_net6_telem {
+       union nf_inet_addr ip;
+       u8 cidr;        /* Not hashed */
+       unsigned long timeout;
+};
+
+static inline bool
+hash_net6_data_equal(const struct hash_net6_elem *ip1,
+                    const struct hash_net6_elem *ip2)
+{
+       return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0;
+}
+
+static inline bool
+hash_net6_data_isnull(const struct hash_net6_elem *elem)
+{
+       return elem->cidr == 0;
+}
 
 static inline void
-__nethash_retry(struct ip_set_nethash *tmp, struct ip_set_nethash *map)
+hash_net6_data_copy(struct hash_net6_elem *dst,
+                   const struct hash_net6_elem *src)
 {
-       memcpy(tmp->cidr, map->cidr, sizeof(tmp->cidr));
-       memcpy(tmp->nets, map->nets, sizeof(tmp->nets));
+       ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
+       dst->cidr = src->cidr;
 }
 
-HASH_RETRY(nethash, ip_set_ip_t)
+static inline void
+hash_net6_data_swap(struct hash_net6_elem *dst, struct hash_net6_elem *src)
+{
+       struct hash_net6_elem tmp;
+
+       memcpy(&tmp, dst, sizeof(tmp));
+       memcpy(dst, src, sizeof(tmp));
+       memcpy(src, &tmp, sizeof(tmp));
+}
 
-static inline int
-nethash_del(struct ip_set *set, ip_set_ip_t ip, uint8_t cidr)
+static inline void
+hash_net6_data_zero_out(struct hash_net6_elem *elem)
 {
-       struct ip_set_nethash *map = set->data;
-       ip_set_ip_t id, *elem;
+       elem->cidr = 0;
+}
 
-       if (cidr <= 0 || cidr >= 32)
-               return -EINVAL; 
-       
-       id = nethash_id_cidr(map, 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 inline void
+ip6_netmask(union nf_inet_addr *ip, u8 prefix)
+{
+       ip->ip6[0] &= NETMASK6(prefix)[0];
+       ip->ip6[1] &= NETMASK6(prefix)[1];
+       ip->ip6[2] &= NETMASK6(prefix)[2];
+       ip->ip6[3] &= NETMASK6(prefix)[3];
 }
 
-UADT(nethash, del, req->cidr)
-KADT(nethash, del, ipaddr, cidr)
+static inline void
+hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
+{
+       ip6_netmask(&elem->ip, cidr);
+       elem->cidr = cidr;
+}
 
-static inline int
-__nethash_create(const struct ip_set_req_nethash_create *req,
-                struct ip_set_nethash *map)
+static inline bool
+hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
 {
-       memset(map->cidr, 0, sizeof(map->cidr));
-       memset(map->nets, 0, sizeof(map->nets));
+       NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+       return 0;
+
+nla_put_failure:
+       return 1;
+}
+
+static inline bool
+hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data)
+{
+       const struct hash_net6_telem *e = 
+               (const struct hash_net6_telem *)data;
        
+       NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
+       NLA_PUT_U8(skb, IPSET_ATTR_CIDR, e->cidr);
+       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                     htonl(ip_set_timeout_get(e->timeout)));
        return 0;
+
+nla_put_failure:
+       return 1;
 }
 
-HASH_CREATE(nethash, ip_set_ip_t)
-HASH_DESTROY(nethash)
+#undef PF
+#undef HOST_MASK
 
-HASH_FLUSH_CIDR(nethash, ip_set_ip_t)
+#define PF             6
+#define HOST_MASK      128
+#include <linux/netfilter/ip_set_chash.h>
 
-static inline void
-__nethash_list_header(const struct ip_set_nethash *map,
-                     struct ip_set_req_nethash_create *header)
-{    
+static int
+hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
+              enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+{
+       struct chash *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_net6_elem data = { .cidr = h->nets[0].cidr || HOST_MASK };
+
+       if (data.cidr == 0)
+               return -EINVAL;
+       if (adt == IPSET_TEST)
+               data.cidr = HOST_MASK;
+
+       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+       ip6_netmask(&data.ip, data.cidr);
+
+       return adtfn(set, &data, GFP_ATOMIC, h->timeout);
+}
+
+static const struct nla_policy
+hash_net6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+       [IPSET_ATTR_IP]         = { .type = NLA_BINARY,
+                                   .len = sizeof(struct in6_addr) },
+       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
+
+static int
+hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len,
+              enum ipset_adt adt, u32 *lineno, u32 flags)
+{
+       struct chash *h = set->data;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX];
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_net6_elem data = { .cidr = HOST_MASK };
+       u32 timeout = h->timeout;
+
+       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
+                     hash_net6_adt_policy))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_IP])
+               memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
+                      sizeof(struct in6_addr));
+       else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_CIDR])
+               data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+
+       if (!data.cidr)
+               return -IPSET_ERR_INVALID_CIDR;
+
+       ip6_netmask(&data.ip, data.cidr);
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!with_timeout(h->timeout))
+                       return -IPSET_ERR_TIMEOUT;
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+       }
+
+       return adtfn(set, &data, GFP_KERNEL, timeout);
 }
 
-HASH_LIST_HEADER(nethash)
-HASH_LIST_MEMBERS_SIZE(nethash, ip_set_ip_t)
-HASH_LIST_MEMBERS(nethash, ip_set_ip_t)
+/* Create hash:ip type of sets */
 
-IP_SET_RTYPE(nethash, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
+static const struct nla_policy
+hash_net_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
+       [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+       [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+       [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+       [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
 
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-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
+hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
+{
+       struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
+       u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+       struct chash *h;
+
+       if (!(set->family == AF_INET || set->family == AF_INET6))
+               return -IPSET_ERR_INVALID_FAMILY;
+
+       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
+                     hash_net_create_policy))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_HASHSIZE]) {
+               hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
+               if (hashsize < IPSET_MIMINAL_HASHSIZE)
+                       hashsize = IPSET_MIMINAL_HASHSIZE;
+       }
+
+       if (tb[IPSET_ATTR_MAXELEM])
+               maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
+
+       h = kzalloc(sizeof(*h)
+                   + sizeof(struct chash_nets)
+                     * (set->family == AF_INET ? 31 : 127), GFP_KERNEL);
+       if (!h)
+               return -ENOMEM;
+
+       h->maxelem = maxelem;
+       h->htable_bits = htable_bits(hashsize);
+       h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
+       h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
+       get_random_bytes(&h->initval, sizeof(h->initval));
+       h->timeout = IPSET_NO_TIMEOUT;
+
+       h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
+                                GFP_KERNEL, &set->flags);
+       if (!h->htable) {
+               kfree(h);
+               return -ENOMEM;
+       }
+
+       set->data = h;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+               
+               set->variant = set->family == AF_INET
+                       ? &hash_net4_tvariant : &hash_net6_tvariant;
+
+               if (set->family == AF_INET)
+                       hash_net4_gc_init(set);
+               else
+                       hash_net6_gc_init(set);
+       } else {
+               set->variant = set->family == AF_INET
+                       ? &hash_net4_variant : &hash_net6_variant;
+       }
+       
+       pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
+                set->name, jhash_size(h->htable_bits),
+                h->htable_bits, h->maxelem, set->data, h->htable);
+          
+       return 0;
+}
+
+static struct ip_set_type hash_net_type = {
+       .name           = "hash:net",
+       .protocol       = IPSET_PROTOCOL,
+       .features       = IPSET_TYPE_IP,
+       .dimension      = IPSET_DIM_ONE,
+       .family         = AF_UNSPEC,
+       .revision       = 0,
+       .create         = hash_net_create,
+       .me             = THIS_MODULE,
+};
+
+static int __init
+hash_net_init(void)
+{
+       return ip_set_type_register(&hash_net_type);
+}
+
+static void __exit
+hash_net_fini(void)
+{
+       ip_set_type_unregister(&hash_net_type);
+}
 
-REGISTER_MODULE(nethash)
+module_init(hash_net_init);
+module_exit(hash_net_fini);
diff --git a/kernel/ip_set_iptreemap.c b/kernel/ip_set_iptreemap.c
deleted file mode 100644 (file)
index 02f657e..0000000
+++ /dev/null
@@ -1,700 +0,0 @@
-/* Copyright (C) 2007 Sven Wegener <sven.wegener@stealer.net>
- *
- * 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.
- */
-
-/* This modules implements the iptreemap ipset type. It uses bitmaps to
- * represent every single IPv4 address as a bit. The bitmaps are managed in a
- * tree structure, where the first three octets of an address are used as an
- * index to find the bitmap and the last octet is used as the bit number.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ip.h>
-#include <linux/jiffies.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#include <linux/spinlock.h>
-#include <linux/timer.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)
-#define IPTREEMAP_DESTROY_SLEEP (100)
-
-static __KMEM_CACHE_T__ *cachep_b;
-static __KMEM_CACHE_T__ *cachep_c;
-static __KMEM_CACHE_T__ *cachep_d;
-
-static struct ip_set_iptreemap_d *fullbitmap_d;
-static struct ip_set_iptreemap_c *fullbitmap_c;
-static struct ip_set_iptreemap_b *fullbitmap_b;
-
-#if defined(__LITTLE_ENDIAN)
-#define ABCD(a, b, c, d, addr) \
-       do { \
-               a = ((unsigned char *)addr)[3]; \
-               b = ((unsigned char *)addr)[2]; \
-               c = ((unsigned char *)addr)[1]; \
-               d = ((unsigned char *)addr)[0]; \
-       } while (0)
-#elif defined(__BIG_ENDIAN)
-#define ABCD(a,b,c,d,addrp) do {               \
-       a = ((unsigned char *)addrp)[0];        \
-       b = ((unsigned char *)addrp)[1];        \
-       c = ((unsigned char *)addrp)[2];        \
-       d = ((unsigned char *)addrp)[3];        \
-} while (0)
-#else
-#error "Please fix asm/byteorder.h"
-#endif /* __LITTLE_ENDIAN */
-
-#define TESTIP_WALK(map, elem, branch, full) \
-       do { \
-               branch = (map)->tree[elem]; \
-               if (!branch) \
-                       return 0; \
-               else if (branch == full) \
-                       return 1; \
-       } while (0)
-
-#define ADDIP_WALK(map, elem, branch, type, cachep, full) \
-       do { \
-               branch = (map)->tree[elem]; \
-               if (!branch) { \
-                       branch = (type *) kmem_cache_alloc(cachep, GFP_ATOMIC); \
-                       if (!branch) \
-                               return -ENOMEM; \
-                       memset(branch, 0, sizeof(*branch)); \
-                       (map)->tree[elem] = branch; \
-               } else if (branch == full) { \
-                       return -EEXIST; \
-               } \
-       } while (0)
-
-#define ADDIP_RANGE_LOOP(map, a, a1, a2, hint, branch, full, cachep, free) \
-       for (a = a1; a <= a2; a++) { \
-               branch = (map)->tree[a]; \
-               if (branch != full) { \
-                       if ((a > a1 && a < a2) || (hint)) { \
-                               if (branch) \
-                                       free(branch); \
-                               (map)->tree[a] = full; \
-                               continue; \
-                       } else if (!branch) { \
-                               branch = kmem_cache_alloc(cachep, GFP_ATOMIC); \
-                               if (!branch) \
-                                       return -ENOMEM; \
-                               memset(branch, 0, sizeof(*branch)); \
-                               (map)->tree[a] = branch; \
-                       }
-
-#define ADDIP_RANGE_LOOP_END() \
-               } \
-       }
-
-#define DELIP_WALK(map, elem, branch, cachep, full, flags) \
-       do { \
-               branch = (map)->tree[elem]; \
-               if (!branch) { \
-                       return -EEXIST; \
-               } else if (branch == full) { \
-                       branch = kmem_cache_alloc(cachep, flags); \
-                       if (!branch) \
-                               return -ENOMEM; \
-                       memcpy(branch, full, sizeof(*full)); \
-                       (map)->tree[elem] = branch; \
-               } \
-       } while (0)
-
-#define DELIP_RANGE_LOOP(map, a, a1, a2, hint, branch, full, cachep, free, flags) \
-       for (a = a1; a <= a2; a++) { \
-               branch = (map)->tree[a]; \
-               if (branch) { \
-                       if ((a > a1 && a < a2) || (hint)) { \
-                               if (branch != full) \
-                                       free(branch); \
-                               (map)->tree[a] = NULL; \
-                               continue; \
-                       } else if (branch == full) { \
-                               branch = kmem_cache_alloc(cachep, flags); \
-                               if (!branch) \
-                                       return -ENOMEM; \
-                               memcpy(branch, full, sizeof(*branch)); \
-                               (map)->tree[a] = branch; \
-                       }
-
-#define DELIP_RANGE_LOOP_END() \
-               } \
-       }
-
-#define LOOP_WALK_BEGIN(map, i, branch) \
-       for (i = 0; i < 256; i++) { \
-               branch = (map)->tree[i]; \
-               if (likely(!branch)) \
-                       continue;
-
-#define LOOP_WALK_END() \
-       }
-
-#define LOOP_WALK_BEGIN_GC(map, i, branch, full, cachep, count) \
-       count = -256; \
-       for (i = 0; i < 256; i++) { \
-               branch = (map)->tree[i]; \
-               if (likely(!branch)) \
-                       continue; \
-               count++; \
-               if (branch == full) { \
-                       count++; \
-                       continue; \
-               }
-
-#define LOOP_WALK_END_GC(map, i, branch, full, cachep, count) \
-               if (-256 == count) { \
-                       kmem_cache_free(cachep, branch); \
-                       (map)->tree[i] = NULL; \
-               } else if (256 == count) { \
-                       kmem_cache_free(cachep, branch); \
-                       (map)->tree[i] = full; \
-               } \
-       }
-
-#define LOOP_WALK_BEGIN_COUNT(map, i, branch, inrange, count) \
-       for (i = 0; i < 256; i++) { \
-               if (!(map)->tree[i]) { \
-                       if (inrange) { \
-                               count++; \
-                               inrange = 0; \
-                       } \
-                       continue; \
-               } \
-               branch = (map)->tree[i];
-
-#define LOOP_WALK_END_COUNT() \
-       }
-
-#define GETVALUE1(a, a1, b1, r) \
-       (a == a1 ? b1 : r)
-
-#define GETVALUE2(a, b, a1, b1, c1, r) \
-       (a == a1 && b == b1 ? c1 : r)
-
-#define GETVALUE3(a, b, c, a1, b1, c1, d1, r) \
-       (a == a1 && b == b1 && c == c1 ? d1 : r)
-
-#define CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2) \
-       ( \
-               GETVALUE1(a, a1, b1, 0) == 0 \
-               && GETVALUE1(a, a2, b2, 255) == 255 \
-               && c1 == 0 \
-               && c2 == 255 \
-               && d1 == 0 \
-               && d2 == 255 \
-       )
-
-#define CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2) \
-       ( \
-               GETVALUE2(a, b, a1, b1, c1, 0) == 0 \
-               && GETVALUE2(a, b, a2, b2, c2, 255) == 255 \
-               && d1 == 0 \
-               && d2 == 255 \
-       )
-
-#define CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2) \
-       ( \
-               GETVALUE3(a, b, c, a1, b1, c1, d1, 0) == 0 \
-               && GETVALUE3(a, b, c, a2, b2, c2, d2, 255) == 255 \
-       )
-
-
-static inline void
-free_d(struct ip_set_iptreemap_d *map)
-{
-       kmem_cache_free(cachep_d, map);
-}
-
-static inline void
-free_c(struct ip_set_iptreemap_c *map)
-{
-       struct ip_set_iptreemap_d *dtree;
-       unsigned int i;
-
-       LOOP_WALK_BEGIN(map, i, dtree) {
-               if (dtree != fullbitmap_d)
-                       free_d(dtree);
-       } LOOP_WALK_END();
-
-       kmem_cache_free(cachep_c, map);
-}
-
-static inline void
-free_b(struct ip_set_iptreemap_b *map)
-{
-       struct ip_set_iptreemap_c *ctree;
-       unsigned int i;
-
-       LOOP_WALK_BEGIN(map, i, ctree) {
-               if (ctree != fullbitmap_c)
-                       free_c(ctree);
-       } LOOP_WALK_END();
-
-       kmem_cache_free(cachep_b, map);
-}
-
-static inline int
-iptreemap_test(struct ip_set *set, ip_set_ip_t ip)
-{
-       struct ip_set_iptreemap *map = set->data;
-       struct ip_set_iptreemap_b *btree;
-       struct ip_set_iptreemap_c *ctree;
-       struct ip_set_iptreemap_d *dtree;
-       unsigned char a, b, c, d;
-
-       ABCD(a, b, c, d, &ip);
-
-       TESTIP_WALK(map, a, btree, fullbitmap_b);
-       TESTIP_WALK(btree, b, ctree, fullbitmap_c);
-       TESTIP_WALK(ctree, c, dtree, fullbitmap_d);
-
-       return !!test_bit(d, (void *) dtree->bitmap);
-}
-
-#define KADT_CONDITION
-
-UADT(iptreemap, test)
-KADT(iptreemap, test, ipaddr)
-
-static inline int
-__addip_single(struct ip_set *set, ip_set_ip_t ip)
-{
-       struct ip_set_iptreemap *map = (struct ip_set_iptreemap *) set->data;
-       struct ip_set_iptreemap_b *btree;
-       struct ip_set_iptreemap_c *ctree;
-       struct ip_set_iptreemap_d *dtree;
-       unsigned char a, b, c, d;
-
-       ABCD(a, b, c, d, &ip);
-
-       ADDIP_WALK(map, a, btree, struct ip_set_iptreemap_b, cachep_b, fullbitmap_b);
-       ADDIP_WALK(btree, b, ctree, struct ip_set_iptreemap_c, cachep_c, fullbitmap_c);
-       ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreemap_d, cachep_d, fullbitmap_d);
-
-       if (__test_and_set_bit(d, (void *) dtree->bitmap))
-               return -EEXIST;
-
-       __set_bit(b, (void *) btree->dirty);
-
-       return 0;
-}
-
-static inline int
-iptreemap_add(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end)
-{
-       struct ip_set_iptreemap *map = set->data;
-       struct ip_set_iptreemap_b *btree;
-       struct ip_set_iptreemap_c *ctree;
-       struct ip_set_iptreemap_d *dtree;
-       unsigned int a, b, c, d;
-       unsigned char a1, b1, c1, d1;
-       unsigned char a2, b2, c2, d2;
-
-       if (start == end)
-               return __addip_single(set, start);
-
-       ABCD(a1, b1, c1, d1, &start);
-       ABCD(a2, b2, c2, d2, &end);
-
-       /* This is sooo ugly... */
-       ADDIP_RANGE_LOOP(map, a, a1, a2, CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2), btree, fullbitmap_b, cachep_b, free_b) {
-               ADDIP_RANGE_LOOP(btree, b, GETVALUE1(a, a1, b1, 0), GETVALUE1(a, a2, b2, 255), CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2), ctree, fullbitmap_c, cachep_c, free_c) {
-                       ADDIP_RANGE_LOOP(ctree, c, GETVALUE2(a, b, a1, b1, c1, 0), GETVALUE2(a, b, a2, b2, c2, 255), CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2), dtree, fullbitmap_d, cachep_d, free_d) {
-                               for (d = GETVALUE3(a, b, c, a1, b1, c1, d1, 0); d <= GETVALUE3(a, b, c, a2, b2, c2, d2, 255); d++)
-                                       __set_bit(d, (void *) dtree->bitmap);
-                               __set_bit(b, (void *) btree->dirty);
-                       } ADDIP_RANGE_LOOP_END();
-               } ADDIP_RANGE_LOOP_END();
-       } ADDIP_RANGE_LOOP_END();
-
-       return 0;
-}
-
-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, gfp_t flags)
-{
-       struct ip_set_iptreemap *map = set->data;
-       struct ip_set_iptreemap_b *btree;
-       struct ip_set_iptreemap_c *ctree;
-       struct ip_set_iptreemap_d *dtree;
-       unsigned char a,b,c,d;
-
-       ABCD(a, b, c, d, &ip);
-
-       DELIP_WALK(map, a, btree, cachep_b, fullbitmap_b, flags);
-       DELIP_WALK(btree, b, ctree, cachep_c, fullbitmap_c, flags);
-       DELIP_WALK(ctree, c, dtree, cachep_d, fullbitmap_d, flags);
-
-       if (!__test_and_clear_bit(d, (void *) dtree->bitmap))
-               return -EEXIST;
-
-       __set_bit(b, (void *) btree->dirty);
-
-       return 0;
-}
-
-static inline int
-iptreemap_del(struct ip_set *set,
-             ip_set_ip_t start, ip_set_ip_t end, gfp_t flags)
-{
-       struct ip_set_iptreemap *map = set->data;
-       struct ip_set_iptreemap_b *btree;
-       struct ip_set_iptreemap_c *ctree;
-       struct ip_set_iptreemap_d *dtree;
-       unsigned int a, b, c, d;
-       unsigned char a1, b1, c1, d1;
-       unsigned char a2, b2, c2, d2;
-
-       if (start == end)
-               return __delip_single(set, start, flags);
-
-       ABCD(a1, b1, c1, d1, &start);
-       ABCD(a2, b2, c2, d2, &end);
-
-       /* This is sooo ugly... */
-       DELIP_RANGE_LOOP(map, a, a1, a2, CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2), btree, fullbitmap_b, cachep_b, free_b, flags) {
-               DELIP_RANGE_LOOP(btree, b, GETVALUE1(a, a1, b1, 0), GETVALUE1(a, a2, b2, 255), CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2), ctree, fullbitmap_c, cachep_c, free_c, flags) {
-                       DELIP_RANGE_LOOP(ctree, c, GETVALUE2(a, b, a1, b1, c1, 0), GETVALUE2(a, b, a2, b2, c2, 255), CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2), dtree, fullbitmap_d, cachep_d, free_d, flags) {
-                               for (d = GETVALUE3(a, b, c, a1, b1, c1, d1, 0); d <= GETVALUE3(a, b, c, a2, b2, c2, d2, 255); d++)
-                                       __clear_bit(d, (void *) dtree->bitmap);
-                               __set_bit(b, (void *) btree->dirty);
-                       } DELIP_RANGE_LOOP_END();
-               } DELIP_RANGE_LOOP_END();
-       } DELIP_RANGE_LOOP_END();
-
-       return 0;
-}
-
-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
- *  1 == all bits set
- *  0 == anything else
- */
-static inline int
-bitmap_status(struct ip_set_iptreemap_d *dtree)
-{
-       unsigned char first = dtree->bitmap[0];
-       int a;
-
-       for (a = 1; a < 32; a++)
-               if (dtree->bitmap[a] != first)
-                       return 0;
-
-       return (first == 0 ? -1 : (first == 255 ? 1 : 0));
-}
-
-static void
-gc(unsigned long addr)
-{
-       struct ip_set *set = (struct ip_set *) addr;
-       struct ip_set_iptreemap *map = set->data;
-       struct ip_set_iptreemap_b *btree;
-       struct ip_set_iptreemap_c *ctree;
-       struct ip_set_iptreemap_d *dtree;
-       unsigned int a, b, c;
-       int i, j, k;
-
-       write_lock_bh(&set->lock);
-
-       LOOP_WALK_BEGIN_GC(map, a, btree, fullbitmap_b, cachep_b, i) {
-               LOOP_WALK_BEGIN_GC(btree, b, ctree, fullbitmap_c, cachep_c, j) {
-                       if (!__test_and_clear_bit(b, (void *) btree->dirty))
-                               continue;
-                       LOOP_WALK_BEGIN_GC(ctree, c, dtree, fullbitmap_d, cachep_d, k) {
-                               switch (bitmap_status(dtree)) {
-                                       case -1:
-                                               kmem_cache_free(cachep_d, dtree);
-                                               ctree->tree[c] = NULL;
-                                               k--;
-                                       break;
-                                       case 1:
-                                               kmem_cache_free(cachep_d, dtree);
-                                               ctree->tree[c] = fullbitmap_d;
-                                               k++;
-                                       break;
-                               }
-                       } LOOP_WALK_END();
-               } LOOP_WALK_END_GC(btree, b, ctree, fullbitmap_c, cachep_c, k);
-       } LOOP_WALK_END_GC(map, a, btree, fullbitmap_b, cachep_b, j);
-
-       write_unlock_bh(&set->lock);
-
-       map->gc.expires = jiffies + map->gc_interval * HZ;
-       add_timer(&map->gc);
-}
-
-static inline void
-init_gc_timer(struct ip_set *set)
-{
-       struct ip_set_iptreemap *map = set->data;
-
-       init_timer(&map->gc);
-       map->gc.data = (unsigned long) set;
-       map->gc.function = gc;
-       map->gc.expires = jiffies + map->gc_interval * HZ;
-       add_timer(&map->gc);
-}
-
-static int
-iptreemap_create(struct ip_set *set, const void *data, u_int32_t size)
-{
-       const struct ip_set_req_iptreemap_create *req = data;
-       struct ip_set_iptreemap *map;
-
-       map = kzalloc(sizeof(*map), GFP_KERNEL);
-       if (!map)
-               return -ENOMEM;
-
-       map->gc_interval = req->gc_interval ? req->gc_interval : IPTREEMAP_DEFAULT_GC_TIME;
-       set->data = map;
-
-       init_gc_timer(set);
-
-       return 0;
-}
-
-static inline void
-__flush(struct ip_set_iptreemap *map)
-{
-       struct ip_set_iptreemap_b *btree;
-       unsigned int a;
-
-       LOOP_WALK_BEGIN(map, a, btree);
-               if (btree != fullbitmap_b)
-                       free_b(btree);
-       LOOP_WALK_END();
-}
-
-static void
-iptreemap_destroy(struct ip_set *set)
-{
-       struct ip_set_iptreemap *map = set->data;
-
-       while (!del_timer(&map->gc))
-               msleep(IPTREEMAP_DESTROY_SLEEP);
-
-       __flush(map);
-       kfree(map);
-
-       set->data = NULL;
-}
-
-static void
-iptreemap_flush(struct ip_set *set)
-{
-       struct ip_set_iptreemap *map = set->data;
-       unsigned int gc_interval = map->gc_interval;
-
-       while (!del_timer(&map->gc))
-               msleep(IPTREEMAP_DESTROY_SLEEP);
-
-       __flush(map);
-
-       memset(map, 0, sizeof(*map));
-       map->gc_interval = gc_interval;
-
-       init_gc_timer(set);
-}
-
-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;
-
-       header->gc_interval = map->gc_interval;
-}
-
-static int
-iptreemap_list_members_size(const struct ip_set *set, char dont_align)
-{
-       struct ip_set_iptreemap *map = set->data;
-       struct ip_set_iptreemap_b *btree;
-       struct ip_set_iptreemap_c *ctree;
-       struct ip_set_iptreemap_d *dtree;
-       unsigned int a, b, c, d, inrange = 0, count = 0;
-
-       LOOP_WALK_BEGIN_COUNT(map, a, btree, inrange, count) {
-               LOOP_WALK_BEGIN_COUNT(btree, b, ctree, inrange, count) {
-                       LOOP_WALK_BEGIN_COUNT(ctree, c, dtree, inrange, count) {
-                               for (d = 0; d < 256; d++) {
-                                       if (test_bit(d, (void *) dtree->bitmap)) {
-                                               inrange = 1;
-                                       } else if (inrange) {
-                                               count++;
-                                               inrange = 0;
-                                       }
-                               }
-                       } LOOP_WALK_END_COUNT();
-               } LOOP_WALK_END_COUNT();
-       } LOOP_WALK_END_COUNT();
-
-       if (inrange)
-               count++;
-
-       return (count * IPSET_VALIGN(sizeof(struct ip_set_req_iptreemap), dont_align));
-}
-
-static inline void
-add_member(void *data, size_t offset, ip_set_ip_t start, ip_set_ip_t end)
-{
-       struct ip_set_req_iptreemap *entry = data + offset;
-
-       entry->ip = start;
-       entry->end = end;
-}
-
-static void
-iptreemap_list_members(const struct ip_set *set, void *data, char dont_align)
-{
-       struct ip_set_iptreemap *map = set->data;
-       struct ip_set_iptreemap_b *btree;
-       struct ip_set_iptreemap_c *ctree;
-       struct ip_set_iptreemap_d *dtree;
-       unsigned int a, b, c, d, inrange = 0;
-       size_t offset = 0, datasize;
-       ip_set_ip_t start = 0, end = 0, ip;
-
-       datasize = IPSET_VALIGN(sizeof(struct ip_set_req_iptreemap), dont_align);
-       LOOP_WALK_BEGIN(map, a, btree) {
-               LOOP_WALK_BEGIN(btree, b, ctree) {
-                       LOOP_WALK_BEGIN(ctree, c, dtree) {
-                               for (d = 0; d < 256; d++) {
-                                       if (test_bit(d, (void *) dtree->bitmap)) {
-                                               ip = ((a << 24) | (b << 16) | (c << 8) | d);
-                                               if (!inrange) {
-                                                       inrange = 1;
-                                                       start = ip;
-                                               } else if (end < ip - 1) {
-                                                       add_member(data, offset, start, end);
-                                                       offset += datasize;
-                                                       start = ip;
-                                               }
-                                               end = ip;
-                                       } else if (inrange) {
-                                               add_member(data, offset, start, end);
-                                               offset += datasize;
-                                               inrange = 0;
-                                       }
-                               }
-                       } LOOP_WALK_END();
-               } LOOP_WALK_END();
-       } LOOP_WALK_END();
-
-       if (inrange)
-               add_member(data, offset, start, end);
-}
-
-IP_SET_TYPE(iptreemap, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Sven Wegener <sven.wegener@stealer.net>");
-MODULE_DESCRIPTION("iptreemap type of IP sets");
-
-static int __init ip_set_iptreemap_init(void)
-{
-       int ret = -ENOMEM;
-       int a;
-
-       cachep_b = KMEM_CACHE_CREATE("ip_set_iptreemap_b",
-                                    sizeof(struct ip_set_iptreemap_b));
-       if (!cachep_b) {
-               ip_set_printk("Unable to create ip_set_iptreemap_b slab cache");
-               goto out;
-       }
-
-       cachep_c = KMEM_CACHE_CREATE("ip_set_iptreemap_c",
-                                    sizeof(struct ip_set_iptreemap_c));
-       if (!cachep_c) {
-               ip_set_printk("Unable to create ip_set_iptreemap_c slab cache");
-               goto outb;
-       }
-
-       cachep_d = KMEM_CACHE_CREATE("ip_set_iptreemap_d",
-                                    sizeof(struct ip_set_iptreemap_d));
-       if (!cachep_d) {
-               ip_set_printk("Unable to create ip_set_iptreemap_d slab cache");
-               goto outc;
-       }
-
-       fullbitmap_d = kmem_cache_alloc(cachep_d, GFP_KERNEL);
-       if (!fullbitmap_d)
-               goto outd;
-
-       fullbitmap_c = kmem_cache_alloc(cachep_c, GFP_KERNEL);
-       if (!fullbitmap_c)
-               goto outbitmapd;
-
-       fullbitmap_b = kmem_cache_alloc(cachep_b, GFP_KERNEL);
-       if (!fullbitmap_b)
-               goto outbitmapc;
-
-       ret = ip_set_register_set_type(&ip_set_iptreemap);
-       if (0 > ret)
-               goto outbitmapb;
-
-       /* Now init our global bitmaps */
-       memset(fullbitmap_d->bitmap, 0xff, sizeof(fullbitmap_d->bitmap));
-
-       for (a = 0; a < 256; a++)
-               fullbitmap_c->tree[a] = fullbitmap_d;
-
-       for (a = 0; a < 256; a++)
-               fullbitmap_b->tree[a] = fullbitmap_c;
-       memset(fullbitmap_b->dirty, 0, sizeof(fullbitmap_b->dirty));
-
-       return 0;
-
-outbitmapb:
-       kmem_cache_free(cachep_b, fullbitmap_b);
-outbitmapc:
-       kmem_cache_free(cachep_c, fullbitmap_c);
-outbitmapd:
-       kmem_cache_free(cachep_d, fullbitmap_d);
-outd:
-       kmem_cache_destroy(cachep_d);
-outc:
-       kmem_cache_destroy(cachep_c);
-outb:
-       kmem_cache_destroy(cachep_b);
-out:
-
-       return ret;
-}
-
-static void __exit ip_set_iptreemap_fini(void)
-{
-       ip_set_unregister_set_type(&ip_set_iptreemap);
-       kmem_cache_free(cachep_d, fullbitmap_d);
-       kmem_cache_free(cachep_c, fullbitmap_c);
-       kmem_cache_free(cachep_b, fullbitmap_b);
-       kmem_cache_destroy(cachep_d);
-       kmem_cache_destroy(cachep_c);
-       kmem_cache_destroy(cachep_b);
-}
-
-module_init(ip_set_iptreemap_init);
-module_exit(ip_set_iptreemap_fini);
index 3cfdae87f3c577831beb403920ba03decf1ce09c..ce6c4d101af7f2f36cb823c2f5f74a3c35a4fdb5 100644 (file)
-/* Copyright (C) 2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2008-2010 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 */
+/* Kernel module implementing an IP set type: the list:set type */
 
+#include <linux/netfilter/ip_set_kernel.h>
 #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>
+#include <linux/netfilter/ip_set.h>
+#include <linux/netfilter/ip_set_timeout.h>
+#include <linux/netfilter/ip_set_list.h>
 
-/*
- * before ==> index, ref
- * after  ==> ref, index
- */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("list:set type of IP sets");
+MODULE_ALIAS("ip_set_list:set");
+
+/* Member elements without and with timeout */
+struct set_elem {
+       ip_set_id_t id;
+};
+
+struct set_telem {
+       ip_set_id_t id;
+       unsigned long timeout;
+};
+
+/* Type structure */
+struct list_set {
+       size_t dsize;           /* element size */
+       u32 size;               /* size of set list array */
+       u32 timeout;            /* timeout value */
+       struct timer_list gc;   /* garbage collection */
+       struct set_elem members[0]; /* the set members */
+};
+
+static inline struct set_elem *
+list_set_elem(const struct list_set *map, u32 id)
+{
+       return (struct set_elem *)((char *)map->members + id * map->dsize);
+}
+
+static inline bool
+list_set_timeout(const struct list_set *map, u32 id)
+{
+       const struct set_telem *elem =
+               (const struct set_telem *) list_set_elem(map, id);
+       
+       return ip_set_timeout_test(elem->timeout);
+}
+
+static inline bool
+list_set_expired(const struct list_set *map, u32 id)
+{
+       const struct set_telem *elem =
+               (const struct set_telem *) list_set_elem(map, id);
+
+       return ip_set_timeout_expired(elem->timeout);
+}
 
 static inline int
-next_index_eq(const struct ip_set_setlist *map, int i, ip_set_id_t index)
+list_set_exist(const struct set_telem *elem)
 {
-       return i < map->size && map->index[i] == index;
+       return elem->id != IPSET_INVALID_ID
+              && !ip_set_timeout_expired(elem->timeout);
 }
 
+/* Set list without and with timeout */
+
 static int
-setlist_utest(struct ip_set *set, const void *data, u_int32_t size)
+list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
+             enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
-       const struct ip_set_setlist *map = set->data;
-       const struct ip_set_req_setlist *req = data;
-       ip_set_id_t index, ref = IP_SET_INVALID_ID;
-       int i, res = 0;
-       struct ip_set *s;
-       
-       if (req->before && req->ref[0] == '\0')
-               return 0;
-
-       index = __ip_set_get_byname(req->name, &s);
-       if (index == IP_SET_INVALID_ID)
-               return 0;
-       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->index[i] != IP_SET_INVALID_ID; i++) {
-               if (req->before && map->index[i] == index) {
-                       res = next_index_eq(map, i + 1, ref);
-                       break;
-               } else if (!req->before) {
-                       if ((ref == IP_SET_INVALID_ID
-                            && map->index[i] == index)
-                           || (map->index[i] == ref
-                               && next_index_eq(map, i + 1, index))) {
-                               res = 1;
-                               break;
-                       }
+       struct list_set *map = set->data;
+       struct set_elem *elem;
+       u32 i;
+       int ret;
+
+       for (i = 0; i < map->size; i++) {
+               elem = list_set_elem(map, i);
+               if (elem->id == IPSET_INVALID_ID)
+                       return 0;
+               if (with_timeout(map->timeout) && list_set_expired(map, i))
+                       continue;
+               switch (adt) {
+               case IPSET_TEST:
+                       ret = ip_set_test(elem->id, skb, pf, dim, flags);
+                       if (ret > 0)
+                               return ret;
+                       break;
+               case IPSET_ADD:
+                       ret = ip_set_add(elem->id, skb, pf, dim, flags);
+                       if (ret == 0)
+                               return ret;
+                       break;
+               case IPSET_DEL:
+                       ret = ip_set_del(elem->id, skb, pf, dim, flags);
+                       if (ret == 0)
+                               return ret;
+                       break;
+               default:
+                       break;
                }
        }
-       if (ref != IP_SET_INVALID_ID)
-               __ip_set_put_byindex(ref);
-finish:
-       __ip_set_put_byindex(index);
-       return res;
+       return -EINVAL;
+}
+
+static const struct nla_policy
+list_set_adt_policy[IPSET_ATTR_ADT_MAX+1] __read_mostly = {
+       [IPSET_ATTR_NAME]       = { .type = NLA_STRING,
+                                   .len = IPSET_MAXNAMELEN },
+       [IPSET_ATTR_NAMEREF]    = { .type = NLA_STRING,
+                                   .len = IPSET_MAXNAMELEN },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
+};
+
+static inline bool
+next_id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
+{
+       const struct set_elem *elem;
+
+       if (i + 1 < map->size) {
+               elem = list_set_elem(map, i + 1);
+               return !!(elem->id == id
+                         && !(with_timeout(map->timeout)
+                              && list_set_expired(map, i + 1)));
+       }
+
+       return 0;
 }
 
+static inline void
+list_elem_add(struct list_set *map, u32 i, ip_set_id_t id)
+{
+       struct set_elem *e;
+
+       for (; i < map->size; i++) {
+               e = list_set_elem(map, i);
+               swap(e->id, id);
+               if (e->id == IPSET_INVALID_ID)
+                       break;
+       }
+}
+               
+static inline void
+list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id,
+              unsigned long timeout)
+{
+       struct set_telem *e;
+
+       for (; i < map->size; i++) {
+               e = (struct set_telem *)list_set_elem(map, i);
+               swap(e->id, id);
+               if (e->id == IPSET_INVALID_ID)
+                       break;
+               swap(e->timeout, timeout);
+       }
+}
+               
 static int
-setlist_ktest(struct ip_set *set,
-             const struct sk_buff *skb,
-             const u_int32_t *flags)
+list_set_add(struct list_set *map, u32 i, ip_set_id_t id,
+            unsigned long timeout)
 {
-       struct ip_set_setlist *map = set->data;
-       int i, res = 0;
+       struct set_elem *e = list_set_elem(map, i);
+
+       if (i == map->size - 1 && e->id != IPSET_INVALID_ID)
+               /* Last element replaced: e.g. add new,before,last */
+               ip_set_put_byindex(e->id);
+       if (with_timeout(map->timeout))
+               list_elem_tadd(map, i, id, timeout);
+       else
+               list_elem_add(map, i, id);
        
-       for (i = 0; i < map->size
-                   && map->index[i] != IP_SET_INVALID_ID
-                   && res == 0; i++)
-               res = ip_set_testip_kernel(map->index[i], skb, flags);
-       return res;
+       return 0;
 }
 
-static inline int
-insert_setlist(struct ip_set_setlist *map, int i, ip_set_id_t index)
+static int
+list_set_del(struct list_set *map, ip_set_id_t id, u32 i)
 {
-       ip_set_id_t tmp;
-       int j;
+       struct set_elem *a = list_set_elem(map, i), *b;
 
-       DP("i: %u, last %u\n", i, map->index[map->size - 1]);   
-       if (i >= map->size || map->index[map->size - 1] != IP_SET_INVALID_ID)
-               return -ERANGE;
-       
-       for (j = i; j < map->size
-                   && index != IP_SET_INVALID_ID; j++) {
-               tmp = map->index[j];
-               map->index[j] = index;
-               index = tmp;
+       ip_set_put_byindex(id);
+
+       for (; i < map->size - 1; i++) {
+               b = list_set_elem(map, i + 1);
+               a->id = b->id;
+               if (with_timeout(map->timeout))
+                       ((struct set_telem *)a)->timeout =
+                               ((struct set_telem *)b)->timeout;
+               a = b;
+               if (a->id == IPSET_INVALID_ID)
+                       break;
        }
+       /* Last element */
+       a->id = IPSET_INVALID_ID;
        return 0;
 }
 
 static int
-setlist_uadd(struct ip_set *set, const void *data, u_int32_t size)
+list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
+             enum ipset_adt adt, u32 *lineno, u32 flags)
 {
-       struct ip_set_setlist *map = set->data;
-       const struct ip_set_req_setlist *req = data;
-       ip_set_id_t index, ref = IP_SET_INVALID_ID;
-       int i, res = -ERANGE;
+       struct list_set *map = set->data;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX];
+       bool eexist = flags & IPSET_FLAG_EXIST,
+            with_timeout = with_timeout(map->timeout);
+       int before = 0;
+       u32 timeout = map->timeout;
+       ip_set_id_t id, refid = IPSET_INVALID_ID;
+       struct set_elem *elem;
        struct ip_set *s;
-       
-       if (req->before && req->ref[0] == '\0')
-               return -EINVAL;
-
-       index = __ip_set_get_byname(req->name, &s);
-       if (index == IP_SET_INVALID_ID)
-               return -EEXIST;
-       /* "Loop detection" */
-       if (strcmp(s->type->typename, "setlist") == 0)
+       u32 i;
+       int ret = 0;
+
+       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
+                     list_set_adt_policy))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_NAME]) {
+               id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
+               if (id == IPSET_INVALID_ID)
+                       return -IPSET_ERR_NAME;
+               /* "Loop detection" */
+               if (s->type->features & IPSET_TYPE_NAME) {
+                       ret = -IPSET_ERR_LOOP;
+                       goto finish;
+               }
+       } else
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_CADT_FLAGS]) {
+               u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+               before = f & IPSET_FLAG_BEFORE;
+       }
+
+       if (before && !tb[IPSET_ATTR_NAMEREF]) {
+               ret = -IPSET_ERR_BEFORE;
                goto finish;
+       }
 
-       if (req->ref[0] != '\0') {
-               ref = __ip_set_get_byname(req->ref, &s);
-               if (ref == IP_SET_INVALID_ID) {
-                       res = -EEXIST;
+       if (tb[IPSET_ATTR_NAMEREF]) {
+               refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]), &s);
+               if (refid == IPSET_INVALID_ID) {
+                       ret = -IPSET_ERR_NAMEREF;
                        goto finish;
                }
+               if (!before)
+                       before = -1;
        }
-       for (i = 0; i < map->size; i++) {
-               if (map->index[i] != ref)
-                       continue;
-               if (req->before) 
-                       res = insert_setlist(map, i, index);
-               else
-                       res = insert_setlist(map,
-                               ref == IP_SET_INVALID_ID ? i : i + 1,
-                               index);
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!with_timeout) {
+                       ret = -IPSET_ERR_TIMEOUT;
+                       goto finish;
+               }
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+       }
+       
+       switch (adt) {
+       case IPSET_TEST:
+               for (i = 0; i < map->size && !ret; i++) {
+                       elem = list_set_elem(map, i);
+                       if (elem->id == IPSET_INVALID_ID
+                           || (before != 0 && i + 1 >= map->size))
+                               break;
+                       else if (with_timeout && list_set_expired(map, i))
+                               continue;
+                       else if (before > 0 && elem->id == id)
+                               ret = next_id_eq(map, i, refid);
+                       else if (before < 0 && elem->id == refid)
+                               ret = next_id_eq(map, i, id);
+                       else if (before == 0 && elem->id == id)
+                               ret = 1;
+               }
+               break;
+       case IPSET_ADD:
+               for (i = 0; i < map->size && !ret; i++) {
+                       elem = list_set_elem(map, i);
+                       if (elem->id == id
+                           && !(with_timeout && list_set_expired(map, i)))
+                               ret = -IPSET_ERR_EXIST;
+               }
+               if (ret == -IPSET_ERR_EXIST)
+                       break;
+               ret = -IPSET_ERR_LIST_FULL;
+               for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
+                       elem = list_set_elem(map, i);
+                       if (elem->id == IPSET_INVALID_ID)
+                               ret = before != 0 ? -IPSET_ERR_REF_EXIST
+                                       : list_set_add(map, i, id, timeout);
+                       else if (elem->id != refid)
+                               continue;
+                       else if (with_timeout && list_set_expired(map, i))
+                               ret = -IPSET_ERR_REF_EXIST;
+                       else if (before)
+                               ret = list_set_add(map, i, id, timeout);
+                       else if (i + 1 < map->size)
+                               ret = list_set_add(map, i + 1, id, timeout);
+               }
+               break;
+       case IPSET_DEL:
+               ret = -IPSET_ERR_EXIST;
+               for (i = 0; i < map->size && ret == -IPSET_ERR_EXIST; i++) {
+                       elem = list_set_elem(map, i);
+                       if (elem->id == IPSET_INVALID_ID) {
+                               ret = before != 0 ? -IPSET_ERR_REF_EXIST
+                                                 : -IPSET_ERR_EXIST;
+                               break;
+                       } else if (with_timeout && list_set_expired(map, i))
+                               continue;
+                       else if (elem->id == id
+                                && (before == 0
+                                    || (before > 0 && next_id_eq(map, i, refid))))
+                               ret = list_set_del(map, id, i);
+                       else if (before < 0 && elem->id == refid
+                                && next_id_eq(map, i, id))
+                               ret = list_set_del(map, id, i + 1);
+               }
+               break;
+       default:
                break;
        }
-       if (ref != IP_SET_INVALID_ID)
-               __ip_set_put_byindex(ref);
-       /* In case of success, we keep the reference to the set */
+
 finish:
-       if (res != 0)
-               __ip_set_put_byindex(index);
-       return res;
+       if (refid != IPSET_INVALID_ID)
+               ip_set_put_byindex(refid);
+       if (adt != IPSET_ADD || ret)
+               ip_set_put_byindex(id);
+
+       if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
+               if (tb[IPSET_ATTR_LINENO])
+                       *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+               return ret;
+       }
+       return ret;
 }
 
-static int
-setlist_kadd(struct ip_set *set,
-            const struct sk_buff *skb,
-            const u_int32_t *flags)
+static void
+list_set_flush(struct ip_set *set)
 {
-       struct ip_set_setlist *map = set->data;
-       int i, res = -EINVAL;
+       struct list_set *map = set->data;
+       struct set_elem *elem;
+       u32 i;
+
+       for (i = 0; i < map->size; i++) {
+               elem = list_set_elem(map, i);
+               if (elem->id != IPSET_INVALID_ID) {
+                       ip_set_put_byindex(elem->id);
+                       elem->id = IPSET_INVALID_ID;
+               }
+       }
+}
+
+static void
+list_set_destroy(struct ip_set *set)
+{
+       struct list_set *map = set->data;
+
+       if (with_timeout(map->timeout))
+               del_timer_sync(&map->gc);
+       list_set_flush(set);
+       kfree(map);
        
-       for (i = 0; i < map->size
-                   && map->index[i] != IP_SET_INVALID_ID
-                   && res != 0; i++)
-               res = ip_set_addip_kernel(map->index[i], skb, flags);
-       return res;
+       set->data = NULL;
 }
 
-static inline int
-unshift_setlist(struct ip_set_setlist *map, int i)
+static int
+list_set_head(struct ip_set *set, struct sk_buff *skb)
 {
-       int j;
+       const struct list_set *map = set->data;
+       struct nlattr *nested;
+
+       nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+       if (!nested)
+               goto nla_put_failure;
+       NLA_PUT_NET32(skb, IPSET_ATTR_SIZE, htonl(map->size));
+       if (with_timeout(map->timeout))
+               NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
+       NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
+                     htonl(atomic_read(&set->ref) - 1));
+       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
+                     htonl(sizeof(*map) + map->size * map->dsize));
+       ipset_nest_end(skb, nested);
        
-       for (j = i; j < map->size - 1; j++)
-               map->index[j] = map->index[j+1];
-       map->index[map->size-1] = IP_SET_INVALID_ID;
        return 0;
+nla_put_failure:
+       return -EFAULT;
 }
 
 static int
-setlist_udel(struct ip_set *set, const void *data, u_int32_t size)
+list_set_list(struct ip_set *set,
+             struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct ip_set_setlist *map = set->data;
-       const struct ip_set_req_setlist *req = data;
-       ip_set_id_t index, ref = IP_SET_INVALID_ID;
-       int i, res = -EEXIST;
-       struct ip_set *s;
-       
-       if (req->before && req->ref[0] == '\0')
-               return -EINVAL;
-
-       index = __ip_set_get_byname(req->name, &s);
-       if (index == 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)
+       const struct list_set *map = set->data;
+       struct nlattr *atd, *nested;
+       u32 i, first = cb->args[2];
+       const struct set_elem *e;
+
+       atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
+       if (!atd)
+               return -EFAULT;
+       for (; cb->args[2] < map->size; cb->args[2]++) {
+               i = cb->args[2];
+               e = list_set_elem(map, i);
+               if (e->id == IPSET_INVALID_ID)
                        goto finish;
-       }
-       for (i = 0; i < map->size
-                   && map->index[i] != IP_SET_INVALID_ID; i++) {
-               if (req->before) {
-                       if (map->index[i] == index
-                           && next_index_eq(map, i + 1, ref)) {
-                               res = unshift_setlist(map, i);
-                               break;
-                       }
-               } else if (ref == IP_SET_INVALID_ID) {
-                       if (map->index[i] == index) {
-                               res = unshift_setlist(map, i);
-                               break;
-                       }
-               } else if (map->index[i] == ref
-                          && next_index_eq(map, i + 1, index)) {
-                       res = unshift_setlist(map, i + 1);
-                       break;
+               if (with_timeout(map->timeout) && list_set_expired(map, i)) 
+                       continue;
+               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+               if (!nested) {
+                       if (i == first) {
+                               nla_nest_cancel(skb, atd);
+                               return -EFAULT;
+                       } else
+                               goto nla_put_failure;
                }
+               NLA_PUT_STRING(skb, IPSET_ATTR_NAME,
+                              ip_set_name_byindex(e->id));
+               if (with_timeout(map->timeout)) {
+                       const struct set_telem *te =
+                               (const struct set_telem *) e;
+                       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                                     htonl(ip_set_timeout_get(te->timeout)));
+               }
+               ipset_nest_end(skb, nested);
        }
-       if (ref != IP_SET_INVALID_ID)
-               __ip_set_put_byindex(ref);
 finish:
-       __ip_set_put_byindex(index);
-       /* In case of success, release the reference to the set */
-       if (res == 0)
-               __ip_set_put_byindex(index);
-       return res;
+       ipset_nest_end(skb, atd);
+       /* Set listing finished */
+       cb->args[2] = 0;
+       return 0;
+
+nla_put_failure:
+       nla_nest_cancel(skb, nested);
+       ipset_nest_end(skb, atd);
+       return 0;
 }
 
-static int
-setlist_kdel(struct ip_set *set,
-            const struct sk_buff *skb,
-            const u_int32_t *flags)
+static bool
+list_set_same_set(const struct ip_set *a, const struct ip_set *b)
 {
-       struct ip_set_setlist *map = set->data;
-       int i, res = -EINVAL;
+       struct list_set *x = a->data;
+       struct list_set *y = b->data;
        
-       for (i = 0; i < map->size
-                   && map->index[i] != IP_SET_INVALID_ID
-                   && res != 0; i++)
-               res = ip_set_delip_kernel(map->index[i], skb, flags);
-       return res;
+       return x->size == y->size
+              && x->timeout == y->timeout;
 }
 
-static int
-setlist_create(struct ip_set *set, const void *data, u_int32_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->index[i] = IP_SET_INVALID_ID;
-       
-       set->data = map;
-       return 0;
-}                        
+static const struct ip_set_type_variant list_set __read_mostly = {
+       .kadt   = list_set_kadt,
+       .uadt   = list_set_uadt,
+       .destroy = list_set_destroy,
+       .flush  = list_set_flush,
+       .head   = list_set_head,
+       .list   = list_set_list,
+       .same_set = list_set_same_set,
+};
 
 static void
-setlist_destroy(struct ip_set *set)
+list_set_gc(unsigned long ul_set)
 {
-       struct ip_set_setlist *map = set->data;
-       int i;
-       
-       for (i = 0; i < map->size
-                   && map->index[i] != IP_SET_INVALID_ID; i++)
-               __ip_set_put_byindex(map->index[i]);
+       struct ip_set *set = (struct ip_set *) ul_set;
+       struct list_set *map = set->data;
+       struct set_telem *e;
+       u32 i;
 
-       kfree(map);
-       set->data = NULL;
+       /* We run parallel with other readers (test element)
+        * but adding/deleting new entries is locked out */
+       read_lock_bh(&set->lock);
+       for (i = map->size - 1; i >= 0; i--) {
+               e = (struct set_telem *) list_set_elem(map, i);
+               if (e->id != IPSET_INVALID_ID
+                   && list_set_expired(map, i))
+                       list_set_del(map, e->id, i);
+       }
+       read_unlock_bh(&set->lock);
+
+       map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
+       add_timer(&map->gc);
 }
 
-static void
-setlist_flush(struct ip_set *set)
+static inline void
+list_set_gc_init(struct ip_set *set)
 {
-       struct ip_set_setlist *map = set->data;
-       int i;
-       
-       for (i = 0; i < map->size
-                   && map->index[i] != IP_SET_INVALID_ID; i++) {
-               __ip_set_put_byindex(map->index[i]);
-               map->index[i] = IP_SET_INVALID_ID;
-       }
+       struct list_set *map = set->data;
+
+       init_timer(&map->gc);
+       map->gc.data = (unsigned long) set;
+       map->gc.function = list_set_gc;
+       map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
+       add_timer(&map->gc);
 }
 
-static void
-setlist_list_header(const struct ip_set *set, void *data)
+/* Create list:set type of sets */
+
+static const struct nla_policy
+list_set_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
+       [IPSET_ATTR_SIZE]       = { .type = NLA_U32 },
+       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+};
+
+static inline bool
+init_list_set(struct ip_set *set, u32 size, size_t dsize,
+             unsigned long timeout)
 {
-       const struct ip_set_setlist *map = set->data;
-       struct ip_set_req_setlist_create *header = data;
+       struct list_set *map;
+       struct set_elem *e;
+       u32 i;
        
-       header->size = map->size;
+       map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL);
+       if (!map)
+               return false;
+
+       map->size = size;
+       map->dsize = dsize;
+       map->timeout = timeout;
+       set->data = map;
+
+       for (i = 0; i < size; i++) {
+               e = list_set_elem(map, i);
+               e->id = IPSET_INVALID_ID;
+       }
+               
+       return true;
 }
 
 static int
-setlist_list_members_size(const struct ip_set *set, char dont_align)
+list_set_create(struct ip_set *set, struct nlattr *head, int len,
+               u32 flags)
 {
-       const struct ip_set_setlist *map = set->data;
-       
-       return map->size * IPSET_VALIGN(sizeof(ip_set_id_t), dont_align);
-}
+       struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
+       u32 size = IP_SET_LIST_DEFAULT_SIZE;
 
-static void
-setlist_list_members(const struct ip_set *set, void *data, char dont_align)
-{
-       struct ip_set_setlist *map = set->data;
-       ip_set_id_t *d;
-       int i;
+       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
+                     list_set_create_policy))
+               return -IPSET_ERR_PROTOCOL;
        
-       for (i = 0; i < map->size; i++) {
-               d = data + i * IPSET_VALIGN(sizeof(ip_set_id_t), dont_align);
-               *d = ip_set_id(map->index[i]);
+       if (tb[IPSET_ATTR_SIZE])
+               size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
+       if (size < IP_SET_LIST_MIN_SIZE)
+               size = IP_SET_LIST_MIN_SIZE;
+
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!init_list_set(set, size, sizeof(struct set_telem),
+                                  ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT])))
+                       return -ENOMEM;
+               
+               list_set_gc_init(set);
+       } else {        
+               if (!init_list_set(set, size, sizeof(struct set_elem),
+                                  IPSET_NO_TIMEOUT))
+                       return -ENOMEM;
        }
+       set->variant = &list_set;
+       return 0;
 }
 
-IP_SET_TYPE(setlist, IPSET_TYPE_SETNAME | IPSET_DATA_SINGLE)
+static struct ip_set_type list_set_type = {
+       .name           = "list:set",
+       .protocol       = IPSET_PROTOCOL,
+       .features       = IPSET_TYPE_NAME,
+       .dimension      = IPSET_DIM_ONE,
+       .family         = AF_UNSPEC,
+       .revision       = 0,
+       .create         = list_set_create,
+       .me             = THIS_MODULE,
+};
 
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-MODULE_DESCRIPTION("setlist type of IP sets");
+static int __init
+list_set_init(void)
+{
+       return ip_set_type_register(&list_set_type);
+}
+
+static void __exit
+list_set_fini(void)
+{
+       ip_set_type_unregister(&list_set_type);
+}
 
-REGISTER_MODULE(setlist)
+module_init(list_set_init);
+module_exit(list_set_fini);
diff --git a/kernel/ip_set_tree_ip.c b/kernel/ip_set_tree_ip.c
deleted file mode 100644 (file)
index 77eb180..0000000
+++ /dev/null
@@ -1,464 +0,0 @@
-/* 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
- * published by the Free Software Foundation.
- */
-
-/* Kernel module implementing an IP set type: the iptree type */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/ip.h>
-#include <linux/jiffies.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#include <linux/spinlock.h>
-#include <linux/timer.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;
-
-/* Garbage collection interval in seconds: */
-#define IPTREE_GC_TIME         5*60
-/* Sleep so many milliseconds before trying again
- * to delete the gc timer at destroying/flushing a set */
-#define IPTREE_DESTROY_SLEEP   100
-
-static __KMEM_CACHE_T__ *branch_cachep;
-static __KMEM_CACHE_T__ *leaf_cachep;
-
-
-#if defined(__LITTLE_ENDIAN)
-#define ABCD(a,b,c,d,addrp) do {               \
-       a = ((unsigned char *)addrp)[3];        \
-       b = ((unsigned char *)addrp)[2];        \
-       c = ((unsigned char *)addrp)[1];        \
-       d = ((unsigned char *)addrp)[0];        \
-} while (0)
-#elif defined(__BIG_ENDIAN)
-#define ABCD(a,b,c,d,addrp) do {               \
-       a = ((unsigned char *)addrp)[0];        \
-       b = ((unsigned char *)addrp)[1];        \
-       c = ((unsigned char *)addrp)[2];        \
-       d = ((unsigned char *)addrp)[3];        \
-} while (0)
-#else
-#error "Please fix asm/byteorder.h"
-#endif /* __LITTLE_ENDIAN */
-
-#define TESTIP_WALK(map, elem, branch) do {    \
-       if ((map)->tree[elem]) {                \
-               branch = (map)->tree[elem];     \
-       } else                                  \
-               return 0;                       \
-} while (0)
-
-static inline int
-iptree_test(struct ip_set *set, ip_set_ip_t ip)
-{
-       struct ip_set_iptree *map = set->data;
-       struct ip_set_iptreeb *btree;
-       struct ip_set_iptreec *ctree;
-       struct ip_set_iptreed *dtree;
-       unsigned char a,b,c,d;
-
-       if (!ip)
-               return -ERANGE;
-       
-       ABCD(a, b, c, d, &ip);
-       DP("%u %u %u %u timeout %u", a, b, c, d, map->timeout);
-       TESTIP_WALK(map, a, btree);
-       TESTIP_WALK(btree, b, ctree);
-       TESTIP_WALK(ctree, c, dtree);
-       DP("%lu %lu", dtree->expires[d], jiffies);
-       return dtree->expires[d]
-              && (!map->timeout
-                  || time_after(dtree->expires[d], jiffies));
-}
-
-#define KADT_CONDITION
-
-UADT(iptree, test)
-KADT(iptree, test, ipaddr)
-
-#define ADDIP_WALK(map, elem, branch, type, cachep) do {       \
-       if ((map)->tree[elem]) {                                \
-               DP("found %u", elem);                           \
-               branch = (map)->tree[elem];                     \
-       } else {                                                \
-               branch = (type *)                               \
-                       kmem_cache_alloc(cachep, GFP_ATOMIC);   \
-               if (branch == NULL)                             \
-                       return -ENOMEM;                         \
-               memset(branch, 0, sizeof(*branch));             \
-               (map)->tree[elem] = branch;                     \
-               DP("alloc %u", elem);                           \
-       }                                                       \
-} while (0)    
-
-static inline int
-iptree_add(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout)
-{
-       struct ip_set_iptree *map = set->data;
-       struct ip_set_iptreeb *btree;
-       struct ip_set_iptreec *ctree;
-       struct ip_set_iptreed *dtree;
-       unsigned char a,b,c,d;
-       int ret = 0;
-       
-       if (!ip || map->elements >= limit)
-               /* We could call the garbage collector
-                * but it's probably overkill */
-               return -ERANGE;
-       
-       ABCD(a, b, c, d, &ip);
-       DP("%u %u %u %u timeout %u", a, b, c, d, timeout);
-       ADDIP_WALK(map, a, btree, struct ip_set_iptreeb, branch_cachep);
-       ADDIP_WALK(btree, b, ctree, struct ip_set_iptreec, branch_cachep);
-       ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreed, leaf_cachep);
-       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)
-               dtree->expires[d] = 1;
-       DP("%u %lu", d, dtree->expires[d]);
-       if (ret == 0)
-               map->elements++;
-       return ret;
-}
-
-UADT(iptree, add, req->timeout)
-KADT(iptree, add, ipaddr, 0)
-
-#define DELIP_WALK(map, elem, branch) do {     \
-       if ((map)->tree[elem]) {                \
-               branch = (map)->tree[elem];     \
-       } else                                  \
-               return -EEXIST;                 \
-} while (0)
-
-static inline int
-iptree_del(struct ip_set *set, ip_set_ip_t ip)
-{
-       struct ip_set_iptree *map = set->data;
-       struct ip_set_iptreeb *btree;
-       struct ip_set_iptreec *ctree;
-       struct ip_set_iptreed *dtree;
-       unsigned char a,b,c,d;
-       
-       if (!ip)
-               return -ERANGE;
-               
-       ABCD(a, b, c, d, &ip);
-       DELIP_WALK(map, a, btree);
-       DELIP_WALK(btree, b, ctree);
-       DELIP_WALK(ctree, c, dtree);
-
-       if (dtree->expires[d]) {
-               dtree->expires[d] = 0;
-               map->elements--;
-               return 0;
-       }
-       return -EEXIST;
-}
-
-UADT(iptree, del)
-KADT(iptree, del, ipaddr)
-
-#define LOOP_WALK_BEGIN(map, i, branch) \
-       for (i = 0; i < 256; i++) {     \
-               if (!(map)->tree[i])    \
-                       continue;       \
-               branch = (map)->tree[i]
-
-#define LOOP_WALK_END }
-
-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;
-       struct ip_set_iptreeb *btree;
-       struct ip_set_iptreec *ctree;
-       struct ip_set_iptreed *dtree;
-       unsigned int a,b,c,d;
-       unsigned char i,j,k;
-
-       i = j = k = 0;
-       DP("gc: %s", set->name);
-       write_lock_bh(&set->lock);
-       LOOP_WALK_BEGIN(map, a, btree);
-       LOOP_WALK_BEGIN(btree, b, ctree);
-       LOOP_WALK_BEGIN(ctree, c, dtree);
-       for (d = 0; d < 256; d++) {
-               if (dtree->expires[d]) {
-                       DP("gc: %u %u %u %u: expires %lu jiffies %lu",
-                           a, b, c, d,
-                           dtree->expires[d], jiffies);
-                       if (map->timeout
-                           && time_before(dtree->expires[d], jiffies)) {
-                               dtree->expires[d] = 0;
-                               map->elements--;
-                       } else
-                               k = 1;
-               }
-       }
-       if (k == 0) {
-               DP("gc: %s: leaf %u %u %u empty",
-                   set->name, a, b, c);
-               kmem_cache_free(leaf_cachep, dtree);
-               ctree->tree[c] = NULL;
-       } else {
-               DP("gc: %s: leaf %u %u %u not empty",
-                   set->name, a, b, c);
-               j = 1;
-               k = 0;
-       }
-       LOOP_WALK_END;
-       if (j == 0) {
-               DP("gc: %s: branch %u %u empty",
-                   set->name, a, b);
-               kmem_cache_free(branch_cachep, ctree);
-               btree->tree[b] = NULL;
-       } else {
-               DP("gc: %s: branch %u %u not empty",
-                   set->name, a, b);
-               i = 1;
-               j = k = 0;
-       }
-       LOOP_WALK_END;
-       if (i == 0) {
-               DP("gc: %s: branch %u empty",
-                   set->name, a);
-               kmem_cache_free(branch_cachep, btree);
-               map->tree[a] = NULL;
-       } else {
-               DP("gc: %s: branch %u not empty",
-                   set->name, a);
-               i = j = k = 0;
-       }
-       LOOP_WALK_END;
-       write_unlock_bh(&set->lock);
-       
-       map->gc.expires = jiffies + map->gc_interval * HZ;
-       add_timer(&map->gc);
-}
-
-static inline void
-init_gc_timer(struct ip_set *set)
-{
-       struct ip_set_iptree *map = set->data;
-
-       /* Even if there is no timeout for the entries,
-        * we still have to call gc because delete
-        * do not clean up empty branches */
-       map->gc_interval = IPTREE_GC_TIME;
-       init_timer(&map->gc);
-       map->gc.data = (unsigned long) set;
-       map->gc.function = ip_tree_gc;
-       map->gc.expires = jiffies + map->gc_interval * HZ;
-       add_timer(&map->gc);
-}
-
-static int
-iptree_create(struct ip_set *set, const void *data, u_int32_t size)
-{
-       const struct ip_set_req_iptree_create *req = data;
-       struct ip_set_iptree *map;
-
-       if (size != sizeof(struct ip_set_req_iptree_create)) {
-               ip_set_printk("data length wrong (want %zu, have %lu)",
-                             sizeof(struct ip_set_req_iptree_create),
-                             (unsigned long)size);
-               return -EINVAL;
-       }
-
-       map = kmalloc(sizeof(struct ip_set_iptree), GFP_KERNEL);
-       if (!map) {
-               DP("out of memory for %zu bytes",
-                  sizeof(struct ip_set_iptree));
-               return -ENOMEM;
-       }
-       memset(map, 0, sizeof(*map));
-       map->timeout = req->timeout;
-       map->elements = 0;
-       set->data = map;
-
-       init_gc_timer(set);
-
-       return 0;
-}
-
-static inline void
-__flush(struct ip_set_iptree *map)
-{
-       struct ip_set_iptreeb *btree;
-       struct ip_set_iptreec *ctree;
-       struct ip_set_iptreed *dtree;
-       unsigned int a,b,c;
-
-       LOOP_WALK_BEGIN(map, a, btree);
-       LOOP_WALK_BEGIN(btree, b, ctree);
-       LOOP_WALK_BEGIN(ctree, c, dtree);
-       kmem_cache_free(leaf_cachep, dtree);
-       LOOP_WALK_END;
-       kmem_cache_free(branch_cachep, ctree);
-       LOOP_WALK_END;
-       kmem_cache_free(branch_cachep, btree);
-       LOOP_WALK_END;
-       map->elements = 0;
-}
-
-static void
-iptree_destroy(struct ip_set *set)
-{
-       struct ip_set_iptree *map = set->data;
-
-       /* gc might be running */
-       while (!del_timer(&map->gc))
-               msleep(IPTREE_DESTROY_SLEEP);
-       __flush(map);
-       kfree(map);
-       set->data = NULL;
-}
-
-static void
-iptree_flush(struct ip_set *set)
-{
-       struct ip_set_iptree *map = set->data;
-       unsigned int timeout = map->timeout;
-       
-       /* gc might be running */
-       while (!del_timer(&map->gc))
-               msleep(IPTREE_DESTROY_SLEEP);
-       __flush(map);
-       memset(map, 0, sizeof(*map));
-       map->timeout = timeout;
-
-       init_gc_timer(set);
-}
-
-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;
-
-       header->timeout = map->timeout;
-}
-
-static int
-iptree_list_members_size(const struct ip_set *set, char dont_align)
-{
-       const struct ip_set_iptree *map = set->data;
-       struct ip_set_iptreeb *btree;
-       struct ip_set_iptreec *ctree;
-       struct ip_set_iptreed *dtree;
-       unsigned int a,b,c,d;
-       unsigned int count = 0;
-
-       LOOP_WALK_BEGIN(map, a, btree);
-       LOOP_WALK_BEGIN(btree, b, ctree);
-       LOOP_WALK_BEGIN(ctree, c, dtree);
-       for (d = 0; d < 256; d++) {
-               if (dtree->expires[d]
-                   && (!map->timeout || time_after(dtree->expires[d], jiffies)))
-                       count++;
-       }
-       LOOP_WALK_END;
-       LOOP_WALK_END;
-       LOOP_WALK_END;
-
-       DP("members %u", count);
-       return (count * IPSET_VALIGN(sizeof(struct ip_set_req_iptree), dont_align));
-}
-
-static void
-iptree_list_members(const struct ip_set *set, void *data, char dont_align)
-{
-       const struct ip_set_iptree *map = set->data;
-       struct ip_set_iptreeb *btree;
-       struct ip_set_iptreec *ctree;
-       struct ip_set_iptreed *dtree;
-       unsigned int a,b,c,d;
-       size_t offset = 0, datasize;
-       struct ip_set_req_iptree *entry;
-
-       datasize = IPSET_VALIGN(sizeof(struct ip_set_req_iptree), dont_align);
-       LOOP_WALK_BEGIN(map, a, btree);
-       LOOP_WALK_BEGIN(btree, b, ctree);
-       LOOP_WALK_BEGIN(ctree, c, dtree);
-       for (d = 0; d < 256; d++) {
-               if (dtree->expires[d]
-                   && (!map->timeout || time_after(dtree->expires[d], jiffies))) {
-                       entry = data + offset;
-                       entry->ip = ((a << 24) | (b << 16) | (c << 8) | d);
-                       entry->timeout = !map->timeout ? 0
-                               : (dtree->expires[d] - jiffies)/HZ;
-                       offset += datasize;
-               }
-       }
-       LOOP_WALK_END;
-       LOOP_WALK_END;
-       LOOP_WALK_END;
-}
-
-IP_SET_TYPE(iptree, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-MODULE_DESCRIPTION("iptree 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_iptree_init(void)
-{
-       int ret;
-       
-       branch_cachep = KMEM_CACHE_CREATE("ip_set_iptreeb",
-                                         sizeof(struct ip_set_iptreeb));
-       if (!branch_cachep) {
-               printk(KERN_ERR "Unable to create ip_set_iptreeb slab cache\n");
-               ret = -ENOMEM;
-               goto out;
-       }
-       leaf_cachep = KMEM_CACHE_CREATE("ip_set_iptreed",
-                                       sizeof(struct ip_set_iptreed));
-       if (!leaf_cachep) {
-               printk(KERN_ERR "Unable to create ip_set_iptreed slab cache\n");
-               ret = -ENOMEM;
-               goto free_branch;
-       }
-       ret = ip_set_register_set_type(&ip_set_iptree);
-       if (ret == 0)
-               goto out;
-
-       kmem_cache_destroy(leaf_cachep);
-    free_branch:       
-       kmem_cache_destroy(branch_cachep);
-    out:
-       return ret;
-}
-
-static void __exit ip_set_iptree_fini(void)
-{
-       /* FIXME: possible race with ip_set_create() */
-       ip_set_unregister_set_type(&ip_set_iptree);
-       kmem_cache_destroy(leaf_cachep);
-       kmem_cache_destroy(branch_cachep);
-}
-
-module_init(ip_set_iptree_init);
-module_exit(ip_set_iptree_fini);
diff --git a/kernel/ipt_SET.c b/kernel/ipt_SET.c
deleted file mode 100644 (file)
index 6009d64..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/* 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>
- *
- * 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.
- */
-
-/* ipt_SET.c - netfilter target to manipulate IP sets */
-
-#include <linux/module.h>
-#include <linux/ip.h>
-#include <linux/skbuff.h>
-#include <linux/version.h>
-
-#include <linux/netfilter_ipv4.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
-#include <linux/netfilter_ipv4/ip_tables.h>
-#define xt_register_target     ipt_register_target
-#define xt_unregister_target   ipt_unregister_target
-#define xt_target              ipt_target
-#define XT_CONTINUE            IPT_CONTINUE
-#else
-#include <linux/netfilter/x_tables.h>
-#endif
-#include <linux/netfilter_ipv4/ipt_set.h>
-
-static unsigned int
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-target(struct sk_buff **pskb,
-       unsigned int hooknum,
-       const struct net_device *in,
-       const struct net_device *out,
-       const void *targinfo,
-       void *userinfo)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const void *targinfo,
-       void *userinfo)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const struct xt_target *target,
-       const void *targinfo,
-       void *userinfo)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const struct xt_target *target,
-       const void *targinfo)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-target(struct sk_buff *skb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const struct xt_target *target,
-       const void *targinfo)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
-target(struct sk_buff *skb,
-       const struct xt_target_param *par)
-#endif
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-       const struct ipt_set_info_target *info = targinfo;
-#else
-       const struct ipt_set_info_target *info = par->targinfo;
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-       struct sk_buff *skb = *pskb;
-#endif
-
-       
-       if (info->add_set.index != IP_SET_INVALID_ID)
-               ip_set_addip_kernel(info->add_set.index,
-                                   skb,
-                                   info->add_set.flags);
-       if (info->del_set.index != IP_SET_INVALID_ID)
-               ip_set_delip_kernel(info->del_set.index,
-                                   skb,
-                                   info->del_set.flags);
-
-       return XT_CONTINUE;
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
-static int
-checkentry(const char *tablename,
-          const struct ipt_entry *e,
-          void *targinfo,
-          unsigned int targinfosize,
-          unsigned int hook_mask)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-static int
-checkentry(const char *tablename,
-          const void *e,
-          void *targinfo,
-          unsigned int targinfosize,
-          unsigned int hook_mask)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-static int
-checkentry(const char *tablename,
-          const void *e,
-          const struct xt_target *target,
-          void *targinfo,
-          unsigned int targinfosize,
-          unsigned int hook_mask)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-static int
-checkentry(const char *tablename,
-          const void *e,
-          const struct xt_target *target,
-          void *targinfo,
-          unsigned int hook_mask)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-static bool
-checkentry(const char *tablename,
-          const void *e,
-          const struct xt_target *target,
-          void *targinfo,
-          unsigned int hook_mask)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
-static bool
-checkentry(const struct xt_tgchk_param *par)
-#endif
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-       const struct ipt_set_info_target *info = targinfo;
-#else
-       const struct ipt_set_info_target *info = par->targinfo;
-#endif
-       ip_set_id_t index;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-       if (targinfosize != IPT_ALIGN(sizeof(*info))) {
-               DP("bad target info size %u", targinfosize);
-               return 0;
-       }
-#endif
-
-       if (info->add_set.index != IP_SET_INVALID_ID) {
-               index = ip_set_get_byindex(info->add_set.index);
-               if (index == IP_SET_INVALID_ID) {
-                       ip_set_printk("cannot find add_set index %u as target",
-                                     info->add_set.index);
-                       return 0;       /* error */
-               }
-       }
-
-       if (info->del_set.index != IP_SET_INVALID_ID) {
-               index = ip_set_get_byindex(info->del_set.index);
-               if (index == IP_SET_INVALID_ID) {
-                       ip_set_printk("cannot find del_set index %u as target",
-                                     info->del_set.index);
-                       return 0;       /* error */
-               }
-       }
-       if (info->add_set.flags[IP_SET_MAX_BINDINGS] != 0
-           || info->del_set.flags[IP_SET_MAX_BINDINGS] != 0) {
-               ip_set_printk("That's nasty!");
-               return 0;       /* error */
-       }
-
-       return 1;
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-static void destroy(void *targetinfo,
-                   unsigned int targetsize)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-static void destroy(const struct xt_target *target,
-                   void *targetinfo,
-                   unsigned int targetsize)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-static void destroy(const struct xt_target *target,
-                   void *targetinfo)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
-static void destroy(const struct xt_tgdtor_param *par)
-#endif
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-       const struct ipt_set_info_target *info = targetinfo;
-#else
-       const struct ipt_set_info_target *info = par->targinfo;
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-       if (targetsize != IPT_ALIGN(sizeof(struct ipt_set_info_target))) {
-               ip_set_printk("invalid targetsize %d", targetsize);
-               return;
-       }
-#endif
-       if (info->add_set.index != IP_SET_INVALID_ID)
-               ip_set_put_byindex(info->add_set.index);
-       if (info->del_set.index != IP_SET_INVALID_ID)
-               ip_set_put_byindex(info->del_set.index);
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-static struct xt_target SET_target = {
-       .name           = "SET",
-       .target         = target,
-       .checkentry     = checkentry,
-       .destroy        = destroy,
-       .me             = THIS_MODULE
-};
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) */
-static struct xt_target SET_target = {
-       .name           = "SET",
-       .family         = AF_INET,
-       .target         = target,
-       .targetsize     = sizeof(struct ipt_set_info_target),
-       .checkentry     = checkentry,
-       .destroy        = destroy,
-       .me             = THIS_MODULE
-};
-#endif
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-MODULE_DESCRIPTION("iptables IP set target module");
-
-static int __init ipt_SET_init(void)
-{
-       return xt_register_target(&SET_target);
-}
-
-static void __exit ipt_SET_fini(void)
-{
-       xt_unregister_target(&SET_target);
-}
-
-module_init(ipt_SET_init);
-module_exit(ipt_SET_fini);
diff --git a/kernel/ipt_set.c b/kernel/ipt_set.c
deleted file mode 100644 (file)
index 2f97cbb..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/* 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>
- *
- * 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 to match an IP set. */
-
-#include <linux/module.h>
-#include <linux/ip.h>
-#include <linux/skbuff.h>
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
-#include <linux/netfilter_ipv4/ip_tables.h>
-#define xt_register_match      ipt_register_match
-#define xt_unregister_match    ipt_unregister_match
-#define xt_match               ipt_match
-#else
-#include <linux/netfilter/x_tables.h>
-#endif
-#include <linux/netfilter_ipv4/ip_set.h>
-#include <linux/netfilter_ipv4/ipt_set.h>
-
-static inline int
-match_set(const struct ipt_set_info *info,
-         const struct sk_buff *skb,
-         int inv)
-{      
-       if (ip_set_testip_kernel(info->index, skb, info->flags))
-               inv = !inv;
-       return inv;
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      const void *hdr,
-      u_int16_t datalen,
-      int *hotdrop) 
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop) 
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const struct xt_match *match,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-static bool
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const struct xt_match *match,
-      const void *matchinfo,
-      int offset, 
-      unsigned int protoff, 
-      bool *hotdrop)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
-static bool
-match(const struct sk_buff *skb,
-      const struct xt_match_param *par)
-#endif
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-       const struct ipt_set_info_match *info = matchinfo;
-#else
-       const struct ipt_set_info_match *info = par->matchinfo;
-#endif
-               
-       return match_set(&info->match_set,
-                        skb,
-                        info->match_set.flags[0] & IPSET_MATCH_INV);
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
-static int
-checkentry(const char *tablename,
-          const struct ipt_ip *ip,
-          void *matchinfo,
-          unsigned int matchsize,
-          unsigned int hook_mask)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-static int
-checkentry(const char *tablename,
-          const void *inf,
-          void *matchinfo,
-          unsigned int matchsize,
-          unsigned int hook_mask)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-static int
-checkentry(const char *tablename,
-          const void *inf,
-          const struct xt_match *match,
-          void *matchinfo,
-          unsigned int matchsize,
-          unsigned int hook_mask)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-static int
-checkentry(const char *tablename,
-          const void *inf,
-          const struct xt_match *match,
-          void *matchinfo,
-          unsigned int hook_mask)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-static bool
-checkentry(const char *tablename,
-          const void *inf,
-          const struct xt_match *match,
-          void *matchinfo,
-          unsigned int hook_mask)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
-static bool
-checkentry(const struct xt_mtchk_param *par)
-#endif
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-       struct ipt_set_info_match *info = matchinfo;
-#else
-       struct ipt_set_info_match *info = par->matchinfo;
-#endif
-       ip_set_id_t index;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
-               ip_set_printk("invalid matchsize %d", matchsize);
-               return 0;
-       }
-#endif
-
-       index = ip_set_get_byindex(info->match_set.index);
-               
-       if (index == IP_SET_INVALID_ID) {
-               ip_set_printk("Cannot find set indentified by id %u to match",
-                             info->match_set.index);
-               return 0;       /* error */
-       }
-       if (info->match_set.flags[IP_SET_MAX_BINDINGS] != 0) {
-               ip_set_printk("That's nasty!");
-               return 0;       /* error */
-       }
-
-       return 1;
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-static void destroy(void *matchinfo,
-                   unsigned int matchsize)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-static void destroy(const struct xt_match *match,
-                   void *matchinfo,
-                   unsigned int matchsize)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-static void destroy(const struct xt_match *match,
-                   void *matchinfo)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
-static void destroy(const struct xt_mtdtor_param *par)
-#endif
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-       struct ipt_set_info_match *info = matchinfo;
-#else
-       struct ipt_set_info_match *info = par->matchinfo;
-#endif
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
-               ip_set_printk("invalid matchsize %d", matchsize);
-               return;
-       }
-#endif
-       ip_set_put_byindex(info->match_set.index);
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-static struct xt_match set_match = {
-       .name           = "set",
-       .match          = &match,
-       .checkentry     = &checkentry,
-       .destroy        = &destroy,
-       .me             = THIS_MODULE
-};
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) */
-static struct xt_match set_match = {
-       .name           = "set",
-       .family         = AF_INET,
-       .match          = &match,
-       .matchsize      = sizeof(struct ipt_set_info_match),
-       .checkentry     = &checkentry,
-       .destroy        = &destroy,
-       .me             = THIS_MODULE
-};
-#endif
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-MODULE_DESCRIPTION("iptables IP set match module");
-
-static int __init ipt_ipset_init(void)
-{
-       return xt_register_match(&set_match);
-}
-
-static void __exit ipt_ipset_fini(void)
-{
-       xt_unregister_match(&set_match);
-}
-
-module_init(ipt_ipset_init);
-module_exit(ipt_ipset_fini);
diff --git a/kernel/xt_set.c b/kernel/xt_set.c
new file mode 100644 (file)
index 0000000..7dfd5ee
--- /dev/null
@@ -0,0 +1,356 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ *                         Patrick Schaaf <bof@bof.de>
+ *                         Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2010 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 which implements the set match and SET target
+ * for netfilter/iptables. */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_set.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("Xtables: IP set match and target module");
+MODULE_ALIAS("xt_SET");
+MODULE_ALIAS("ipt_set");
+MODULE_ALIAS("ipt_SET");
+
+static inline int
+match_set(ip_set_id_t index, const struct sk_buff *skb,
+         u8 pf, u8 dim, u8 flags, int inv)
+{      
+       if (ip_set_test(index, skb, pf, dim, flags))
+               inv = !inv;
+       return inv;
+}
+
+/* Revision 0 interface: backward compatible with netfilter/iptables */
+
+static bool
+set_match_v0(const struct sk_buff *skb, const struct xt_match_param *par)
+{
+       const struct xt_set_info_match_v0 *info = par->matchinfo;
+               
+       return match_set(info->match_set.index, skb, par->family,
+                        info->match_set.u.compat.dim,
+                        info->match_set.u.compat.flags,
+                        info->match_set.u.compat.flags & IPSET_INV_MATCH);
+}
+
+static void
+compat_flags(struct xt_set_info_v0 *info)
+{
+       u_int8_t i;
+
+       /* Fill out compatibility data according to enum ip_set_kopt */
+       info->u.compat.dim = IPSET_DIM_ZERO;
+       if (info->u.flags[0] & IPSET_MATCH_INV)
+               info->u.compat.flags |= IPSET_INV_MATCH;
+       for (i = 0; i < IPSET_DIM_MAX-1 && info->u.flags[i]; i++) {
+               info->u.compat.dim++;
+               if (info->u.flags[i] & IPSET_SRC)
+                       info->u.compat.flags |= (1<<info->u.compat.dim);
+       }
+}
+
+static bool
+set_match_v0_checkentry(const struct xt_mtchk_param *par)
+{
+       struct xt_set_info_match_v0 *info = par->matchinfo;
+       ip_set_id_t index;
+
+       index = ip_set_nfnl_get_byindex(info->match_set.index);
+               
+       if (index == IPSET_INVALID_ID) {
+               pr_warning("Cannot find set indentified by id %u to match",
+                          info->match_set.index);
+               return 0;       /* error */
+       }
+       if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
+               pr_warning("That's nasty!");
+               return 0;       /* error */
+       }
+
+       /* Fill out compatibility data */
+       compat_flags(&info->match_set);
+
+       return 1;
+}
+
+static void
+set_match_v0_destroy(const struct xt_mtdtor_param *par)
+{
+       struct xt_set_info_match *info = par->matchinfo;
+
+
+       ip_set_nfnl_put(info->match_set.index);
+}
+
+static unsigned int
+set_target_v0(struct sk_buff *skb, const struct xt_target_param *par)
+{
+       const struct xt_set_info_target_v0 *info = par->targinfo;
+       
+       if (info->add_set.index != IPSET_INVALID_ID)
+               ip_set_add(info->add_set.index, skb, par->family,
+                          info->add_set.u.compat.dim,
+                          info->add_set.u.compat.flags);
+       if (info->del_set.index != IPSET_INVALID_ID)
+               ip_set_del(info->del_set.index, skb, par->family,
+                          info->del_set.u.compat.dim,
+                          info->del_set.u.compat.flags);
+
+       return XT_CONTINUE;
+}
+
+static bool
+set_target_v0_checkentry(const struct xt_tgchk_param *par)
+{
+       struct xt_set_info_target_v0 *info = par->targinfo;
+       ip_set_id_t index;
+
+       if (info->add_set.index != IPSET_INVALID_ID) {
+               index = ip_set_nfnl_get_byindex(info->add_set.index);
+               if (index == IPSET_INVALID_ID) {
+                       pr_warning("cannot find add_set index %u as target",
+                                  info->add_set.index);
+                       return 0;       /* error */
+               }
+       }
+
+       if (info->del_set.index != IPSET_INVALID_ID) {
+               index = ip_set_nfnl_get_byindex(info->del_set.index);
+               if (index == IPSET_INVALID_ID) {
+                       pr_warning("cannot find del_set index %u as target",
+                                  info->del_set.index);
+                       return 0;       /* error */
+               }
+       }
+       if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0
+           || info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
+               pr_warning("That's nasty!");
+               return 0;       /* error */
+       }
+
+       /* Fill out compatibility data */
+       compat_flags(&info->add_set);
+       compat_flags(&info->del_set);
+
+       return 1;
+}
+
+static void
+set_target_v0_destroy(const struct xt_tgdtor_param *par)
+{
+       const struct xt_set_info_target_v0 *info = par->targinfo;
+
+       if (info->add_set.index != IPSET_INVALID_ID)
+               ip_set_nfnl_put(info->add_set.index);
+       if (info->del_set.index != IPSET_INVALID_ID)
+               ip_set_nfnl_put(info->del_set.index);
+}
+
+/* Revision 1: current interface to netfilter/iptables */
+
+static bool
+set_match(const struct sk_buff *skb, const struct xt_match_param *par)
+{
+       const struct xt_set_info_match *info = par->matchinfo;
+               
+       return match_set(info->match_set.index, skb, par->family,
+                        info->match_set.dim,
+                        info->match_set.flags,
+                        info->match_set.flags & IPSET_INV_MATCH);
+}
+
+static bool
+set_match_checkentry(const struct xt_mtchk_param *par)
+{
+       struct xt_set_info_match *info = par->matchinfo;
+       ip_set_id_t index;
+
+       index = ip_set_nfnl_get_byindex(info->match_set.index);
+               
+       if (index == IPSET_INVALID_ID) {
+               pr_warning("Cannot find set indentified by id %u to match",
+                          info->match_set.index);
+               return 0;       /* error */
+       }
+       if (info->match_set.dim > IPSET_DIM_MAX) {
+               pr_warning("That's nasty!");
+               return 0;       /* error */
+       }
+
+       return 1;
+}
+
+static void
+set_match_destroy(const struct xt_mtdtor_param *par)
+{
+       struct xt_set_info_match *info = par->matchinfo;
+
+
+       ip_set_nfnl_put(info->match_set.index);
+}
+
+/* Set target */
+
+static unsigned int
+set_target(struct sk_buff *skb, const struct xt_target_param *par)
+{
+       const struct xt_set_info_target *info = par->targinfo;
+       
+       if (info->add_set.index != IPSET_INVALID_ID)
+               ip_set_add(info->add_set.index,
+                          skb, par->family,
+                          info->add_set.dim,
+                          info->add_set.flags);
+       if (info->del_set.index != IPSET_INVALID_ID)
+               ip_set_del(info->del_set.index,
+                          skb, par->family,
+                          info->add_set.dim,
+                          info->del_set.flags);
+
+       return XT_CONTINUE;
+}
+
+static bool
+set_target_checkentry(const struct xt_tgchk_param *par)
+{
+       const struct xt_set_info_target *info = par->targinfo;
+       ip_set_id_t index;
+
+       if (info->add_set.index != IPSET_INVALID_ID) {
+               index = ip_set_nfnl_get_byindex(info->add_set.index);
+               if (index == IPSET_INVALID_ID) {
+                       pr_warning("cannot find add_set index %u as target",
+                                  info->add_set.index);
+                       return 0;       /* error */
+               }
+       }
+
+       if (info->del_set.index != IPSET_INVALID_ID) {
+               index = ip_set_nfnl_get_byindex(info->del_set.index);
+               if (index == IPSET_INVALID_ID) {
+                       pr_warning("cannot find del_set index %u as target",
+                                  info->del_set.index);
+                       return 0;       /* error */
+               }
+       }
+       if (info->add_set.dim > IPSET_DIM_MAX
+           || info->del_set.flags > IPSET_DIM_MAX) {
+               pr_warning("That's nasty!");
+               return 0;       /* error */
+       }
+
+       return 1;
+}
+
+static void
+set_target_destroy(const struct xt_tgdtor_param *par)
+{
+       const struct xt_set_info_target *info = par->targinfo;
+
+       if (info->add_set.index != IPSET_INVALID_ID)
+               ip_set_nfnl_put(info->add_set.index);
+       if (info->del_set.index != IPSET_INVALID_ID)
+               ip_set_nfnl_put(info->del_set.index);
+}
+
+static struct xt_match set_matches[] __read_mostly = {
+       {
+               .name           = "set",
+               .family         = NFPROTO_IPV4,
+               .revision       = 0,
+               .match          = set_match_v0,
+               .matchsize      = sizeof(struct xt_set_info_match_v0),
+               .checkentry     = set_match_v0_checkentry,
+               .destroy        = set_match_v0_destroy,
+               .me             = THIS_MODULE
+       },
+       {
+               .name           = "set",
+               .family         = NFPROTO_IPV4,
+               .revision       = 1,
+               .match          = set_match,
+               .matchsize      = sizeof(struct xt_set_info_match),
+               .checkentry     = set_match_checkentry,
+               .destroy        = set_match_destroy,
+               .me             = THIS_MODULE
+       },
+       {
+               .name           = "set",
+               .family         = NFPROTO_IPV6,
+               .revision       = 1,
+               .match          = set_match,
+               .matchsize      = sizeof(struct xt_set_info_match),
+               .checkentry     = set_match_checkentry,
+               .destroy        = set_match_destroy,
+               .me             = THIS_MODULE
+       },
+};
+
+static struct xt_target set_targets[] __read_mostly = {
+       {
+               .name           = "SET",
+               .revision       = 0,
+               .family         = NFPROTO_IPV4,
+               .target         = set_target_v0,
+               .targetsize     = sizeof(struct xt_set_info_target_v0),
+               .checkentry     = set_target_v0_checkentry,
+               .destroy        = set_target_v0_destroy,
+               .me             = THIS_MODULE
+       },
+       {
+               .name           = "SET",
+               .revision       = 1,
+               .family         = NFPROTO_IPV4,
+               .target         = set_target,
+               .targetsize     = sizeof(struct xt_set_info_target),
+               .checkentry     = set_target_checkentry,
+               .destroy        = set_target_destroy,
+               .me             = THIS_MODULE
+       },
+       {
+               .name           = "SET",
+               .revision       = 1,
+               .family         = NFPROTO_IPV6,
+               .target         = set_target,
+               .targetsize     = sizeof(struct xt_set_info_target),
+               .checkentry     = set_target_checkentry,
+               .destroy        = set_target_destroy,
+               .me             = THIS_MODULE
+       },
+};
+
+static int __init xt_set_init(void)
+{
+       int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
+       
+       if (!ret) {
+               ret = xt_register_targets(set_targets,
+                                         ARRAY_SIZE(set_targets));
+               if (ret)
+                       xt_unregister_matches(set_matches,
+                                             ARRAY_SIZE(set_matches));
+       }
+       return ret;
+}
+
+static void __exit xt_set_fini(void)
+{
+       xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
+       xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
+}
+
+module_init(xt_set_init);
+module_exit(xt_set_fini);
index 74b665112186a6854388730003b1f3a55171bf6a..bf4e133b70951db22b7c06570673619c21b8b0fa 100644 (file)
@@ -12,9 +12,7 @@ libipset_la_SOURCES = \
        parse.c \
        print.c \
        session.c \
-       types.c \
-       utils.c
-
+       types.c
 
 #%.o: %.c
 #      ${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} ${CFLAGS} -o $@ -c $<
index e1a139ecf67d3ed71712356079656ddb0a6c6311..6f07445b32918f8232d8107176a09e00e7a1efd9 100644 (file)
@@ -33,7 +33,11 @@ req: msg:    IPSET_CMD_LIST|SAVE
        attr:   IPSET_ATTR_PROTOCOL
                IPSET_ATTR_SETNAME      (optional)
 
-resp:  attr:   IPSET_ATTR_DATA
+resp:  attr:   IPSET_ATTR_SETNAME
+               IPSET_ATTR_TYPENAME
+               IPSET_ATTR_REVISION
+               IPSET_ATTR_FAMILY
+               IPSET_ATTR_DATA
                        create-specific-data
                IPSET_ATTR_ADT
                        IPSET_ATTR_DATA
index 0de91a10abd486e00525693a91a8ce20b69dfffa..f8ff4a9580944c1af3ef914a39f8879bad78e0e5 100644 (file)
@@ -12,6 +12,7 @@
 #include <string.h>                            /* memset */
 
 #include <libipset/linux_ip_set.h>             /* IPSET_MAXNAMELEN */
+#include <libipset/debug.h>                    /* D() */
 #include <libipset/types.h>                    /* struct ipset_type */
 #include <libipset/utils.h>                    /* inXcpy */
 #include <libipset/data.h>                     /* prototypes */
 struct ipset_data {
        /* Option bits: which fields are set */
        uint64_t bits;
+       /* Option bits: which options are ignored */
+       uint64_t ignored;
        /* Setname  */
        char setname[IPSET_MAXNAMELEN];
        const struct ipset_type *type;
        /* Common CADT options */
        uint8_t cidr;
        uint8_t family;
-       uint32_t flags;
+       uint32_t flags;         /* command level flags */
+       uint32_t cadt_flags;    /* data level flags */
        uint32_t timeout;
        union nf_inet_addr ip;
        union nf_inet_addr ip_to;
@@ -78,6 +82,25 @@ copy_addr(uint8_t family, union nf_inet_addr *ip, const void *value)
                in6cpy(&ip->in6, (const struct in6_addr *)value);
 }
 
+/**
+ * ipset_strncpy - copy the string from src to dst
+ * @dst: the target string buffer
+ * @src: the source string buffer
+ * @len: the length of bytes to copy, including the terminating null byte.
+ *
+ * Copy the string from src to destination, but at most len bytes are
+ * copied. The target is unconditionally terminated by the null byte.
+ */
+void
+ipset_strncpy(char *dst, const char *src, size_t len)
+{
+       assert(dst);
+       assert(src);
+
+       strncpy(dst, src, len);
+       dst[len - 1] = '\0';
+}
+
 /**
  * ipset_data_flags_test - test option bits in the data blob
  * @data: data blob
@@ -122,12 +145,37 @@ ipset_data_flags_unset(struct ipset_data *data, uint64_t flags)
        data->bits &= ~flags;
 }
 
-#define flag_type_attr(data, opt, flag)                                \
-do {                                                           \
-       data->flags |= (1 << flag);                             \
-       opt = IPSET_OPT_FLAGS;                                  \
+#define flag_type_attr(data, opt, flag)                \
+do {                                           \
+       data->flags |= flag;                    \
+       opt = IPSET_OPT_FLAGS;                  \
+} while (0)
+
+#define cadt_flag_type_attr(data, opt, flag)   \
+do {                                           \
+       data->cadt_flags |= flag;               \
+       opt = IPSET_OPT_CADT_FLAGS;             \
 } while (0)
 
+/**
+ * ipset_data_ignored - test and set ignored bits in the data blob
+ * @data: data blob
+ * @flags: the option flags which is ignored
+ *
+ * Returns true if the option was not already ignored.
+ */
+bool
+ipset_data_ignored(struct ipset_data *data, enum ipset_opt opt)
+{
+       bool ignored;
+       assert(data);
+       
+       ignored = data->ignored & IPSET_FLAG(opt);
+       data->ignored |= IPSET_FLAG(opt);
+
+       return ignored;
+}
+
 /**
  * ipset_data_set - put data into the data blob
  * @data: data blob
@@ -249,11 +297,14 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
                flag_type_attr(data, opt, IPSET_FLAG_EXIST);
                break;
        case IPSET_OPT_BEFORE:
-               flag_type_attr(data, opt, IPSET_FLAG_BEFORE);
+               cadt_flag_type_attr(data, opt, IPSET_FLAG_BEFORE);
                break;
        case IPSET_OPT_FLAGS:
                data->flags = *(const uint32_t *)value;
                break;
+       case IPSET_OPT_CADT_FLAGS:
+               data->cadt_flags = *(const uint32_t *)value;
+               break;
        default:
                return -1;
        };
@@ -351,8 +402,10 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
        /* flags */
        case IPSET_OPT_FLAGS:
        case IPSET_OPT_EXIST:
-       case IPSET_OPT_BEFORE:
                return &data->flags;
+       case IPSET_OPT_CADT_FLAGS:
+       case IPSET_OPT_BEFORE:
+               return &data->cadt_flags;
        default:
                return NULL;
        }
index 5662a47d7de5179b584090a98da8ca3adf9c1f2a..80564276355d80bae41d8b550eaefb749a79a204 100644 (file)
--- a/lib/mnl.c
+++ b/lib/mnl.c
@@ -8,8 +8,10 @@
 #include <errno.h>                             /* errno */
 #include <stdlib.h>                            /* calloc, free */
 #include <time.h>                              /* time */
+#include <arpa/inet.h>                         /* hto* */
 
 #include <libipset/linux_ip_set.h>             /* enum ipset_cmd */
+#include <libipset/debug.h>                    /* D() */
 #include <libipset/session.h>                  /* ipset_session_handle */
 #include <libipset/ui.h>                       /* IPSET_ENV_EXIST */
 #include <libipset/utils.h>                    /* UNUSED */
index 0e0e7f12fb6e52adb67f47a12081912d08fe2de4..e347c69356e22612a2e587ce7e99cfdcbc99f1ed 100644 (file)
@@ -13,6 +13,7 @@
 #include <sys/socket.h>                                /* getaddrinfo, AF_ */
 #include <net/ethernet.h>                      /* ETH_ALEN */
 
+#include <libipset/debug.h>                    /* D() */
 #include <libipset/data.h>                     /* IPSET_OPT_* */
 #include <libipset/pfxlen.h>                   /* prefixlen_netmask_map */
 #include <libipset/session.h>                  /* ipset_err */
 
 /* Parse input data */
 
-#define ipset_cidr_separator(str)      ipset_strchr(str, IPSET_CIDR_SEPARATOR)
-#define ipset_range_separator(str)     ipset_strchr(str, IPSET_RANGE_SEPARATOR)
-#define ipset_elem_separator(str)      ipset_strchr(str, IPSET_ELEM_SEPARATOR)
-#define ipset_name_separator(str)      ipset_strchr(str, IPSET_NAME_SEPARATOR)
+#define cidr_separator(str)    ipset_strchr(str, IPSET_CIDR_SEPARATOR)
+#define range_separator(str)   ipset_strchr(str, IPSET_RANGE_SEPARATOR)
+#define elem_separator(str)    ipset_strchr(str, IPSET_ELEM_SEPARATOR)
+#define name_separator(str)    ipset_strchr(str, IPSET_NAME_SEPARATOR)
 
 #define syntax_err(fmt, args...) \
        ipset_err(session, "Syntax error: " fmt , ## args)
 
+static char *
+ipset_strchr(const char *str, const char *sep)
+{
+       char *match;
+       
+       assert(str);
+       assert(sep);
+       
+       for (; *sep != '\0'; sep++)
+               if ((match = strchr(str, (int)sep[0])) != NULL
+                   && str[0] != sep[0]
+                   && str[strlen(str)-1] != sep[0])
+                       return match;
+       
+       return NULL;
+}
+
 /* 
  * Parser functions, shamelessly taken from iptables.c, ip6tables.c 
  * and parser.c from libnetfilter_conntrack.
@@ -70,33 +88,53 @@ string_to_number_ll(struct ipset_session *session,
 }
 
 static int
-string_to_number_l(struct ipset_session *session,
-                  const char *str, 
-                  unsigned long min,
-                  unsigned long max,
-                  unsigned long *ret)
+string_to_u8(struct ipset_session *session,
+            const char *str, uint8_t *ret)
 {
        int err;
-       unsigned long long number = 0;
+       unsigned long long num = 0;
 
-       err = string_to_number_ll(session, str, min, max, &number);
-       *ret = (unsigned long) number;
+       err = string_to_number_ll(session, str, 0, 255, &num);
+       *ret = (uint8_t) num;
 
        return err;
 }
 
 static int
-string_to_number(struct ipset_session *session,
-                const char *str, 
-                unsigned int min, 
-                unsigned int max,
-                unsigned int *ret)
+string_to_cidr(struct ipset_session *session,
+              const char *str, uint8_t min, uint8_t max, uint8_t *ret)
+{
+       int err = string_to_u8(session, str, ret);
+       
+       if (!err && (*ret < min || *ret > max))
+               return syntax_err("'%s' is out of range %u-%u",
+                                 str, min, max);
+
+       return err;
+}
+
+static int
+string_to_u16(struct ipset_session *session,
+             const char *str, uint16_t *ret)
+{
+       int err;
+       unsigned long long num = 0;
+
+       err = string_to_number_ll(session, str, 0, USHRT_MAX, &num);
+       *ret = (uint16_t) num;
+
+       return err;
+}
+
+static int
+string_to_u32(struct ipset_session *session,
+             const char *str, uint32_t *ret)
 {
        int err;
-       unsigned long number = 0;
+       unsigned long long num = 0;
 
-       err = string_to_number_l(session, str, min, max, &number);
-       *ret = (unsigned int) number;
+       err = string_to_number_ll(session, str, 0, UINT_MAX, &num);
+       *ret = (uint32_t) num;
 
        return err;
 }
@@ -161,12 +199,6 @@ parse_portname(struct ipset_session *session, const char *str, uint16_t *port)
        return syntax_err("cannot parse '%s' as a (TCP) port", str);
 }
 
-static int
-parse_portnum(struct ipset_session *session, const char *str, uint16_t *port)
-{
-       return string_to_number(session, str, 0, 65535, (unsigned int *)port);
-}
-
 /**
  * ipset_parse_single_port - parse a single (TCP) port number or name
  * @session: session structure
@@ -189,7 +221,7 @@ ipset_parse_single_port(struct ipset_session *session,
        assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO);
        assert(str);
 
-       if ((err = parse_portnum(session, str, &port)) == 0
+       if ((err = string_to_u16(session, str, &port)) == 0
            || (err = parse_portname(session, str, &port)) == 0)
                err = ipset_session_data_set(session, opt, &port);
 
@@ -229,7 +261,7 @@ ipset_parse_port(struct ipset_session *session,
                                 "Cannot allocate memory to duplicate %s.",
                                 str);
 
-       a = ipset_range_separator(tmp);
+       a = range_separator(tmp);
        if (a != NULL) {
                /* port-port */
                *a++ = '\0';
@@ -256,14 +288,20 @@ error:
  * Returns 0 on success or a negative error code.
  */
 int
-ipset_parse_family(struct ipset_session *session, int opt, const char *str)
+ipset_parse_family(struct ipset_session *session,
+                  enum ipset_opt opt, const char *str)
 {
+       struct ipset_data *data;
        uint8_t family;
        
        assert(session);
        assert(opt == IPSET_OPT_FAMILY);
        assert(str);
 
+       data = ipset_session_data(session);
+       if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_FAMILY)))
+               syntax_err("protocol family may not be specified multiple times");
+
        if (STREQ(str, "inet") || STREQ(str, "ipv4") || STREQ(str, "-4"))
                family = AF_INET;
        else if (STREQ(str, "inet6") || STREQ(str, "ipv6") || STREQ(str, "-6"))
@@ -273,7 +311,7 @@ ipset_parse_family(struct ipset_session *session, int opt, const char *str)
        else
                return syntax_err("unknown INET family %s", str);
                                
-       return ipset_session_data_set(session, opt, &family);
+       return ipset_data_set(data, opt, &family);
 }
 
 /*
@@ -316,8 +354,8 @@ get_addrinfo##f(struct ipset_session *session,                              \
         int found;                                                     \
                                                                        \
        if ((*info = get_addrinfo(session, str, family)) == NULL) {     \
-               syntax_err("cannot parse %s: resolving "                \
-                          IP " failed", str);                          \
+               syntax_err("cannot parse %s: " IP " resolving failed",  \
+                          str);                                        \
                return EINVAL;                                          \
        }                                                               \
                                                                        \
@@ -347,7 +385,7 @@ static int                                                          \
 parse_ipv##f(struct ipset_session *session,                            \
             enum ipset_opt opt, const char *str)                       \
 {                                                                      \
-        unsigned int m = mask;                                         \
+        uint8_t m = mask;                                              \
         int aerr = EINVAL, err = 0, range = 0;                         \
         char *saved = strdup(str);                                     \
         char *a, *tmp = saved;                                         \
@@ -361,14 +399,14 @@ parse_ipv##f(struct ipset_session *session,                               \
                return ipset_err(session,                               \
                                 "Cannot allocate memory to duplicate %s.",\
                                 str);                                  \
-       if ((a = ipset_cidr_separator(tmp)) != NULL) {                  \
+       if ((a = cidr_separator(tmp)) != NULL) {                        \
                /* IP/mask */                                           \
                *a++ = '\0';                                            \
                                                                        \
-               if ((err = string_to_number(session, a, 0, m, &m)) != 0 \
+               if ((err = string_to_cidr(session, a, 0, m, &m)) != 0   \
                    || (err = ipset_data_set(data, copt, &m)) != 0)     \
                        goto out;                                       \
-       } else if ((a = ipset_range_separator(tmp)) != NULL) {          \
+       } else if ((a = range_separator(tmp)) != NULL) {                \
                /* IP-IP */                                             \
                *a++ = '\0';                                            \
                D("range %s", a);                                       \
@@ -420,17 +458,17 @@ parse_ip(struct ipset_session *session,
 
        switch (addrtype) {
        case IPADDR_PLAIN:
-               if (ipset_range_separator(str) || ipset_cidr_separator(str))
+               if (range_separator(str) || cidr_separator(str))
                        return syntax_err("plain IP address must be supplied: %s",
                                          str);
                break;
        case IPADDR_NET:
-               if (!ipset_cidr_separator(str) || ipset_range_separator(str))
+               if (!cidr_separator(str) || range_separator(str))
                        return syntax_err("IP/netblock must be supplied: %s",
                                          str);
                break;
        case IPADDR_RANGE:
-               if (!ipset_range_separator(str) || ipset_cidr_separator(str))
+               if (!range_separator(str) || cidr_separator(str))
                        return syntax_err("IP-IP range must supplied: %s",
                                          str);
                break;
@@ -539,7 +577,7 @@ ipset_parse_range(struct ipset_session *session,
                  enum ipset_opt opt, const char *str)
 {
        assert(session);
-       assert(opt == IPSET_OPT_IP);
+       assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
        assert(str);
 
        return parse_ip(session, IPSET_OPT_IP, str, IPADDR_RANGE);
@@ -563,15 +601,118 @@ ipset_parse_netrange(struct ipset_session *session,
                     enum ipset_opt opt, const char *str)
 {
        assert(session);
-       assert(opt == IPSET_OPT_IP);
+       assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
        assert(str);
 
-       if (!(ipset_range_separator(str) || ipset_cidr_separator(str)))
-               return syntax_err("IP/net or IP-IP range must be specified: %s",
+       if (!(range_separator(str) || cidr_separator(str)))
+               return syntax_err("IP/cidr or IP-IP range must be specified: %s",
                                  str);
        return parse_ip(session, opt, str, IPADDR_ANY);
 }
 
+/**
+ * ipset_parse_iprange - parse IPv4|IPv6 address or range
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as an IPv4|IPv6 address pattern or a range
+ * of addresses separated by a dash. If family is not set yet in
+ * the data blob, INET is assumed.
+ * The value is stored in the data blob of the session.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_iprange(struct ipset_session *session,
+                   enum ipset_opt opt, const char *str)
+{
+       assert(session);
+       assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
+       assert(str);
+
+       if (cidr_separator(str))
+               return syntax_err("IP address or IP-IP range must be specified: %s",
+                                 str);
+       return parse_ip(session, opt, str, IPADDR_ANY);
+}
+
+/**
+ * ipset_parse_ipnet - parse IPv4|IPv6 address or address/cidr pattern
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as an IPv4|IPv6 address or address/cidr pattern.
+ * If family is not set yet in the data blob, INET is assumed.
+ * The value is stored in the data blob of the session.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_ipnet(struct ipset_session *session,
+                 enum ipset_opt opt, const char *str)
+{
+       assert(session);
+       assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
+       assert(str);
+
+       if (range_separator(str))
+               return syntax_err("IP address or IP/cidr must be specified: %s",
+                                 str);
+       return parse_ip(session, opt, str, IPADDR_ANY);
+}
+
+/**
+ * ipset_parse_iptimeout - parse IPv4|IPv6 address and timeout
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as an IPv4|IPv6 address and timeout parameter.
+ * If family is not set yet in the data blob, INET is assumed.
+ * The value is stored in the data blob of the session.
+ *
+ * Compatibility parser.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_iptimeout(struct ipset_session *session,
+                     enum ipset_opt opt, const char *str)
+{
+       char *tmp, *saved, *a;
+       int err;
+
+       assert(session);
+       assert(opt == IPSET_OPT_IP);
+       assert(str);
+
+       /* IP,timeout */
+       if (ipset_data_flags_test(ipset_session_data(session),
+                                 IPSET_FLAG(IPSET_OPT_TIMEOUT)))
+               return syntax_err("mixed syntax, timeout already specified");
+                
+       tmp = saved = strdup(str);      
+       if (saved == NULL)
+               return ipset_err(session,
+                                "Cannot allocate memory to duplicate %s.",
+                                str);
+
+       a = elem_separator(tmp);
+       if (a == NULL) {
+               free(saved);
+               return syntax_err("Missing separator from %s", str);
+       }
+       *a++ = '\0';
+       err = parse_ip(session, opt, tmp, IPADDR_ANY);
+       if (!err)
+               err = ipset_parse_uint32(session, IPSET_OPT_TIMEOUT, a);
+
+       free(saved);
+       return err;
+}
+
 #define check_setname(str, saved)                                      \
 do {                                                                   \
     if (strlen(str) > IPSET_MAXNAMELEN - 1) {                          \
@@ -584,7 +725,7 @@ do {                                                                        \
 
 
 /**
- * ipset_parse_name - parse setname as element
+ * ipset_parse_name_compat - parse setname as element
  * @session: session structure
  * @opt: option kind of the data
  * @str: string to parse
@@ -597,8 +738,8 @@ do {                                                                        \
  * Returns 0 on success or a negative error code.
  */
 int
-ipset_parse_name(struct ipset_session *session,
-                enum ipset_opt opt, const char *str)
+ipset_parse_name_compat(struct ipset_session *session,
+                       enum ipset_opt opt, const char *str)
 {
        char *saved;
        char *a = NULL, *b = NULL, *tmp;
@@ -607,25 +748,22 @@ ipset_parse_name(struct ipset_session *session,
        struct ipset_data *data;
 
        assert(session);
-       assert(opt == IPSET_OPT_NAME || opt == IPSET_OPT_SETNAME2);
+       assert(opt == IPSET_OPT_NAME);
        assert(str);
 
        data = ipset_session_data(session);
-       if (opt == IPSET_OPT_SETNAME2) {
-               check_setname(str, NULL);
-               
-               return ipset_data_set(data, opt, str);
-       }
+       if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_NAMEREF)))
+               syntax_err("mixed syntax, before|after option already used");
 
        tmp = saved = strdup(str);      
        if (saved == NULL)
                return ipset_err(session,
                                 "Cannot allocate memory to duplicate %s.",
                                 str);
-       if ((a = ipset_elem_separator(tmp)) != NULL) {
+       if ((a = elem_separator(tmp)) != NULL) {
                /* setname,[before|after,setname */
                *a++ = '\0';
-               if ((b = ipset_elem_separator(a)) != NULL)
+               if ((b = elem_separator(a)) != NULL)
                        *b++ = '\0';
                if (b == NULL
                    || !(STREQ(a, "before") || STREQ(a, "after"))) {
@@ -644,7 +782,7 @@ ipset_parse_name(struct ipset_session *session,
        if ((err = ipset_data_set(data,
                                  IPSET_OPT_NAMEREF, b)) != 0)
                goto out;
-       
+
        if (before)
                err = ipset_data_set(data, IPSET_OPT_BEFORE, &before);
 
@@ -654,12 +792,12 @@ out:
 }
 
 /**
- * ipset_parse_setname - parse name as the name of the (current) set
+ * ipset_parse_setname - parse string as a setname
  * @session: session structure
  * @opt: option kind of the data
  * @str: string to parse
  *
- * Parse string as the name of the (current) set.
+ * Parse string as a setname.
  * The value is stored in the data blob of the session.
  *
  * Returns 0 on success or a negative error code.
@@ -669,7 +807,9 @@ ipset_parse_setname(struct ipset_session *session,
                    enum ipset_opt opt, const char *str)
 {
        assert(session);
-       assert(opt == IPSET_SETNAME);
+       assert(opt == IPSET_SETNAME
+              || opt == IPSET_OPT_NAME
+              || opt == IPSET_OPT_SETNAME2);
        assert(str);
 
        check_setname(str, NULL);
@@ -677,6 +817,67 @@ ipset_parse_setname(struct ipset_session *session,
        return ipset_session_data_set(session, opt, str);
 }
 
+/**
+ * ipset_parse_before - parse string as "before" reference setname
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as a "before" reference setname for list:set
+ * type of sets. The value is stored in the data blob of the session.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_before(struct ipset_session *session,
+                  enum ipset_opt opt, const char *str)
+{
+       struct ipset_data *data;
+
+       assert(session);
+       assert(opt == IPSET_OPT_NAMEREF);
+       assert(str);
+
+       data = ipset_session_data(session);
+       if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_NAMEREF)))
+               syntax_err("mixed syntax, before|after option already used");
+
+       check_setname(str, NULL);
+       ipset_data_set(data, IPSET_OPT_BEFORE, str);
+
+       return ipset_data_set(data, opt, str);
+}
+
+/**
+ * ipset_parse_after - parse string as "after" reference setname
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as a "after" reference setname for list:set
+ * type of sets. The value is stored in the data blob of the session.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_after(struct ipset_session *session,
+                  enum ipset_opt opt, const char *str)
+{
+       struct ipset_data *data;
+
+       assert(session);
+       assert(opt == IPSET_OPT_NAMEREF);
+       assert(str);
+
+       data = ipset_session_data(session);
+       if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_NAMEREF)))
+               syntax_err("mixed syntax, before|after option already used");
+
+       check_setname(str, NULL);
+
+       return ipset_data_set(data, opt, str);
+}
+
 /**
  * ipset_parse_uint32 - parse string as an unsigned integer
  * @session: session structure
@@ -698,7 +899,7 @@ ipset_parse_uint32(struct ipset_session *session,
        assert(session);
        assert(str);
 
-       if ((err = string_to_number(session, str, 0, 0, &value)) == 0)
+       if ((err = string_to_u32(session, str, &value)) == 0)
                return ipset_session_data_set(session, opt, &value);
        
        return err;
@@ -719,13 +920,13 @@ int
 ipset_parse_uint8(struct ipset_session *session,
                  enum ipset_opt opt, const char *str)
 {
-       unsigned int value;
+       uint8_t value;
        int err;
        
        assert(session);
        assert(str);
 
-       if ((err = string_to_number(session, str, 0, 255, &value)) == 0)
+       if ((err = string_to_u8(session, str, &value)) == 0)
                return ipset_session_data_set(session, opt, &value);
 
        return err;
@@ -747,7 +948,7 @@ int
 ipset_parse_netmask(struct ipset_session *session,
                    enum ipset_opt opt, const char *str)
 {
-       unsigned int family, cidr;
+       uint8_t family, cidr;
        struct ipset_data *data;
        int err = 0;
        
@@ -762,10 +963,10 @@ ipset_parse_netmask(struct ipset_session *session,
                ipset_data_set(data, IPSET_OPT_FAMILY, &family);
        }
 
-       err = string_to_number(session, str,
-                              family == AF_INET ? 1 : 4, 
-                              family == AF_INET ? 31 : 124,
-                              &cidr);
+       err = string_to_cidr(session, str,
+                            family == AF_INET ? 1 : 4, 
+                            family == AF_INET ? 31 : 124,
+                            &cidr);
 
        if (err)
                return syntax_err("netmask is out of the inclusive range "
@@ -864,15 +1065,72 @@ ipset_parse_output(struct ipset_session *session,
        return syntax_err("unkown output mode '%s'", str);
 }
 
+/**
+ * ipset_parse_ignored - "parse" ignored option
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Ignore deprecated options. A single warning is generated
+ * for every ignored opton.
+ *
+ * Returns 0.
+ */
+int
+ipset_parse_ignored(struct ipset_session *session,
+                   enum ipset_opt opt, const char *str)
+{
+       assert(session);
+       assert(str);
+
+       if (!ipset_data_ignored(ipset_session_data(session), opt))
+               ipset_warn(session,
+                          "Option %s is ignored. Please upgrade your syntax.", str);
+
+       return 0;
+}
+
+/**
+ * ipset_call_parser - call a parser function
+ * @session: session structure
+ * @parsefn: parser function
+ * @optstr: option name
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Wrapper to call the parser functions so that ignored options
+ * are handled properly.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_call_parser(struct ipset_session *session,
+                 ipset_parsefn parse, const char *optstr,
+                 enum ipset_opt opt, const char *str)
+{
+       if (ipset_data_flags_test(ipset_session_data(session),
+                                 IPSET_FLAG(opt)))
+               syntax_err("%s already specified", optstr);
+
+       return parse(session, opt, parse == ipset_parse_ignored
+                                  ? optstr : str);
+}
+
 #define parse_elem(s, t, d, str)                                       \
 do {                                                                   \
-       if (!t->elem[d].parse)                                          \
+       if (!(t)->elem[d].parse)                                        \
                goto internal;                                          \
-       err = t->elem[d].parse(s, t->elem[d].opt, str);                 \
-       if (err)                                                        \
+       ret = (t)->elem[d].parse(s, (t)->elem[d].opt, str);             \
+       if (ret)                                                        \
                goto out;                                               \
 } while (0)
 
+#define elem_syntax_err(fmt, args...)  \
+do {                                   \
+       free(saved);                    \
+       return syntax_err(fmt , ## args);\
+} while (0)
+
 /**
  * ipset_parse_elem - parse ADT elem, depending on settype
  * @session: session structure
@@ -890,7 +1148,7 @@ ipset_parse_elem(struct ipset_session *session,
 {
        const struct ipset_type *type;
        char *a = NULL, *b = NULL, *tmp, *saved;
-       int err;
+       int ret;
 
        assert(session);
        assert(str);
@@ -906,40 +1164,43 @@ ipset_parse_elem(struct ipset_session *session,
                                 "Cannot allocate memory to duplicate %s.",
                                 str);
 
-       a = ipset_elem_separator(tmp);
+       a = elem_separator(tmp);
        if (type->dimension > IPSET_DIM_ONE) {
                if (a != NULL) {
                        /* elem,elem */
                        *a++ = '\0';
-               } else if (type->dimension > IPSET_DIM_TWO && !optional) {
-                       free(tmp);
-                       return syntax_err("Second element is missing from %s.",
-                                         str);
+               } else if (!optional)
+                       elem_syntax_err("Second element is missing from %s.",
+                                       str);
+       } else if (a != NULL) {
+               if (type->compat_parse_elem) {
+                       ret = type->compat_parse_elem(session,
+                                                     type->elem[IPSET_DIM_ONE].opt,
+                                                     saved);
+                       goto out;
                }
-       } else if (a != NULL)
-               return syntax_err("Elem separator in %s, "
-                                 "but settype %s supports none.",
-                                 str, type->name);
+               elem_syntax_err("Elem separator in %s, "
+                               "but settype %s supports none.",
+                               str, type->name);
+       }
 
        if (a)
-               b = ipset_elem_separator(a);
+               b = elem_separator(a);
        if (type->dimension > IPSET_DIM_TWO) {
                if (b != NULL) {
                        /* elem,elem,elem */
                        *b++ = '\0';
-               } else if (!optional) {
-                       free(tmp);
-                       return syntax_err("Third element is missing from %s.",
-                                         str);
-               }
+               } else if (!optional)
+                       elem_syntax_err("Third element is missing from %s.",
+                                       str);
        } else if (b != NULL)
-               return syntax_err("Two elem separators in %s, "
-                                 "but settype %s supports one.",
-                                 str, type->name);
-       if (b != NULL && ipset_elem_separator(b))
-               return syntax_err("Three elem separators in %s, "
-                                 "but settype %s supports two.",
-                                 str, type->name);
+               elem_syntax_err("Two elem separators in %s, "
+                               "but settype %s supports one.",
+                               str, type->name);
+       if (b != NULL && elem_separator(b))
+               elem_syntax_err("Three elem separators in %s, "
+                               "but settype %s supports two.",
+                               str, type->name);
 
        D("parse elem part one: %s", tmp);
        parse_elem(session, type, IPSET_DIM_ONE, tmp);
@@ -954,10 +1215,10 @@ ipset_parse_elem(struct ipset_session *session,
        goto out;
 
 internal:
-       err = ipset_err(session,
+       ret = ipset_err(session,
                        "Internal error: missing parser function for %s",
                        type->name);
 out:
        free(saved);
-       return err;
+       return ret;
 }
index 4df09058cd5e21653f73b4cef2d9cbe05181c032..d96e643f57c217b8153298d0d6e80aebdb84d52e 100644 (file)
@@ -13,6 +13,7 @@
 #include <arpa/inet.h>                         /* inet_ntop */
 #include <net/ethernet.h>                      /* ETH_ALEN */
 
+#include <libipset/debug.h>                    /* D() */
 #include <libipset/data.h>                     /* ipset_data_* */
 #include <libipset/parse.h>                    /* IPSET_*_SEPARATOR */
 #include <libipset/types.h>                    /* ipset set types */
@@ -86,7 +87,7 @@ ipset_print_ether(char *buf, unsigned int len,
  */
 int
 ipset_print_family(char *buf, unsigned int len,
-                  const struct ipset_data *data, int opt,
+                  const struct ipset_data *data, enum ipset_opt opt,
                   uint8_t env UNUSED)
 {
        uint8_t family;
@@ -172,10 +173,10 @@ snprintf_ipv##f(char *buf, unsigned int len, int flags,                   \
        size = __getnameinfo##f(buf, len, flags, ip);                   \
        SNPRINTF_FAILURE(size, len, offset);                            \
                                                                        \
+       D("cidr %u mask %u", cidr, mask);                               \
        if (cidr == mask)                                               \
                return offset;                                          \
-       if ((unsigned int)(size + 5) < len)                             \
-               return -1;                                              \
+       D("print cidr");                                                \
        size = snprintf(buf + offset, len,                              \
                        "%s%u", IPSET_CIDR_SEPARATOR, cidr);            \
        SNPRINTF_FAILURE(size, len, offset);                            \
@@ -218,9 +219,10 @@ ipset_print_ip(char *buf, unsigned int len,
        D("len: %u", len);
        family = ipset_data_family(data);
        cidropt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR : IPSET_OPT_CIDR2;
-       if (ipset_data_test(data, cidropt))
+       if (ipset_data_test(data, cidropt)) {
                cidr = *(uint8_t *) ipset_data_get(data, cidropt);
-       else
+               D("CIDR: %u", cidr);
+       } else
                cidr = family == AF_INET6 ? 128 : 32;
        flags = env & (1 << IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
        
@@ -373,11 +375,14 @@ ipset_print_name(char *buf, unsigned int len,
        SNPRINTF_FAILURE(size, len, offset);    
 
        if (ipset_data_test(data, IPSET_OPT_NAMEREF)) {
-               bool before = ipset_data_test(data, IPSET_OPT_BEFORE);
+               bool before = false;
+               if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_FLAGS))) {
+                       uint32_t *flags =
+                               (uint32_t *)ipset_data_get(data, IPSET_OPT_FLAGS);
+                       before = (*flags) & IPSET_FLAG_BEFORE;
+               }
                size = snprintf(buf + offset, len,
-                               "%s%s%s%s", IPSET_ELEM_SEPARATOR,
-                               before ? "before" : "after",
-                               IPSET_ELEM_SEPARATOR,
+                               " %s %s", before ? "before" : "after",
                                (const char *) ipset_data_get(data,
                                        IPSET_OPT_NAMEREF));
                SNPRINTF_FAILURE(size, len, offset);    
@@ -468,8 +473,8 @@ ipset_print_elem(char *buf, unsigned int len,
        size = type->elem[IPSET_DIM_ONE].print(buf, len, data,
                        type->elem[IPSET_DIM_ONE].opt, env);
        SNPRINTF_FAILURE(size, len, offset);
-       if (ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt))
-               D("print second elem");
+       IF_D(ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt),
+            "print second elem");
        if (type->dimension == IPSET_DIM_ONE
            || (type->last_elem_optional
                && !ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt)))
index 2c4e39aa5d496fdf8b2fa4da6930e15e6a30aa92..2c85468de07dda91e1445b1f537050b4bcb25f27 100644 (file)
@@ -13,6 +13,7 @@
 #include <unistd.h>                            /* getpagesize */
 #include <net/ethernet.h>                      /* ETH_ALEN */
 
+#include <libipset/debug.h>                    /* D() */
 #include <libipset/data.h>                     /* IPSET_OPT_* */
 #include <libipset/errcode.h>                  /* ipset_errcode */
 #include <libipset/print.h>                    /* ipset_print_* */
@@ -189,6 +190,8 @@ ipset_session_report(struct ipset_session *session,
        
        if (len >= IPSET_ERRORBUFLEN - 1 - offset)
                session->report[IPSET_ERRORBUFLEN - 1] = '\0';
+       if (strlen(session->report) < IPSET_ERRORBUFLEN - 1)
+               strcat(session->report, "\n");
 
        if (type == IPSET_ERROR) {
                session->errmsg = session->report;
@@ -278,6 +281,10 @@ const struct ipset_attr_policy cmd_attrs[] = {
                .type = MNL_TYPE_U8,
                .opt = IPSET_OPT_FAMILY,
        },
+       [IPSET_ATTR_FLAGS] = {
+               .type = MNL_TYPE_U32,
+               .opt = IPSET_OPT_FLAGS,
+       },
        [IPSET_ATTR_DATA] = {
                .type = MNL_TYPE_NESTED,
        },
@@ -320,9 +327,9 @@ const struct ipset_attr_policy create_attrs[] = {
                .type = MNL_TYPE_U32,
                .opt = IPSET_OPT_TIMEOUT,
        },
-       [IPSET_ATTR_FLAGS] = {
+       [IPSET_ATTR_CADT_FLAGS] = {
                .type = MNL_TYPE_U32,
-               .opt = IPSET_OPT_FLAGS,
+               .opt = IPSET_OPT_CADT_FLAGS,
        },
        [IPSET_ATTR_GC] = {
                .type = MNL_TYPE_U32,
@@ -391,9 +398,9 @@ const struct ipset_attr_policy adt_attrs[] = {
                .type = MNL_TYPE_U32,
                .opt = IPSET_OPT_TIMEOUT,
        },
-       [IPSET_ATTR_FLAGS] = {
+       [IPSET_ATTR_CADT_FLAGS] = {
                .type = MNL_TYPE_U32,
-               .opt = IPSET_OPT_FLAGS,
+               .opt = IPSET_OPT_CADT_FLAGS,
        },
        [IPSET_ATTR_LINENO] = {
                .type = MNL_TYPE_U32,
@@ -434,6 +441,7 @@ attr2data(struct ipset_session *session, struct nlattr *nla[],
        struct ipset_data *data = session->data;
        const struct ipset_attr_policy *attr;
        const void *d;
+       int ret;
 
        attr = &attrs[type];
        d = mnl_attr_get_payload(nla[type]);
@@ -480,7 +488,14 @@ attr2data(struct ipset_session *session, struct nlattr *nla[],
                        break;
                }
        }
-       return ipset_data_set(data, attr->opt, d);
+       if (type == IPSET_ATTR_TYPENAME) 
+               D("nla typename %s", (char *) d);
+       ret = ipset_data_set(data, attr->opt, d);
+       if (type == IPSET_ATTR_TYPENAME) 
+               D("nla typename %s",
+                 (char *) ipset_data_get(data, IPSET_OPT_TYPENAME));
+       
+       return ret;
 }
 
 #define ATTR2DATA(session, nla, type, attrs)           \
@@ -579,8 +594,9 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
        const struct ipset_type *type;
        const struct ipset_arg *arg;
        uint8_t family;
-       int i;
-       
+       int i, found = 0;
+
+       D("enter");     
        /* Check and load type, family */
        if (!ipset_data_test(data, IPSET_OPT_TYPE))
                type = ipset_type_get(session, IPSET_CMD_ADD);
@@ -591,6 +607,15 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
                return MNL_CB_ERROR;
        family = ipset_data_family(data);
 
+       for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_ADT_MAX; i++)
+               if (nla[i]) {
+                       found++;
+                       ATTR2DATA(session, nla, i, adt_attrs);
+       }
+       D("attr found %u", found);
+       if (!found)
+               return MNL_CB_OK;
+
        switch (session->mode) {
        case IPSET_LIST_SAVE:
                safe_snprintf(session, "add %s ", ipset_data_setname(data));
@@ -603,10 +628,6 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
                break;
        }
        
-       for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_ADT_MAX; i++)
-               if (nla[i])
-                       ATTR2DATA(session, nla, i, adt_attrs);
-
        safe_dprintf(session, ipset_print_elem, IPSET_OPT_ELEM);
 
        for (arg = type->args[IPSET_ADD]; arg != NULL && arg->print; arg++) {
@@ -646,6 +667,10 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
        return MNL_CB_OK;
 }
 
+#define FAMILY_TO_STR(f)               \
+       ((f) == AF_INET ? "inet" :      \
+        (f) == AF_INET6 ? "inet6" : "any")
+
 static int
 list_create(struct ipset_session *session, struct nlattr *nla[])
 {
@@ -671,33 +696,29 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
                safe_snprintf(session, "create %s %s ",
                              ipset_data_setname(data),
                              type->name);
-               if (family == AF_INET6)
-                       sprintf(session->outbuf, "family inet6 ");
                break;
        case IPSET_LIST_PLAIN:
-               safe_snprintf(session, "Name: %s\nType: %s\n",
+               safe_snprintf(session, "Name: %s\n"
+                             "Type: %s\nHeader: ",
                              ipset_data_setname(data),
                              type->name);
-               if (family == AF_INET6)
-                       safe_snprintf(session, "Family: INET6\n");
-               safe_snprintf(session, "Header: ");
                break;
        case IPSET_LIST_XML:
                safe_snprintf(session,
                              "<ipset name=\"%s\">\n"
-                             "  <type>%s</type>\n",
+                             "  <type>%s</type>\n"
+                             "  <header>\n",
                              ipset_data_setname(data),
                              type->name);
-               if (family == AF_INET6)
-                       safe_snprintf(session, "  <family>INET6</family>\n");
-               safe_snprintf(session, "  <header>\n");
                break;
        default:
                break;
        }
 
-       for (arg = type->args[IPSET_CREATE]; arg != NULL && arg->print; arg++) {
-               if (!ipset_data_test(data, arg->opt))
+       for (arg = type->args[IPSET_CREATE]; arg != NULL && arg->opt; arg++) {
+               if (!arg->print
+                   || !ipset_data_test(data, arg->opt)
+                   || (arg->opt == IPSET_OPT_FAMILY && family == type->family))
                        continue;
                switch (session->mode) {
                case IPSET_LIST_SAVE:
@@ -730,8 +751,6 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
                safe_snprintf(session, "\n");
                break;
        case IPSET_LIST_PLAIN:
-               safe_snprintf(session, "\nElements: ");
-               safe_dprintf(session, ipset_print_number, IPSET_OPT_ELEMENTS);
                safe_snprintf(session, "\nSize in memory: ");
                safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
                safe_snprintf(session, "\nReferences: ");
@@ -739,8 +758,6 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
                safe_snprintf(session, "\nMembers:\n");
                break;
        case IPSET_LIST_XML:
-               safe_snprintf(session, "    <elements>");
-               safe_dprintf(session, ipset_print_number, IPSET_OPT_ELEMENTS);
                safe_snprintf(session, "</elements>\n    <memsize>");
                safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
                safe_snprintf(session, "</memsize>\n    <references>");
@@ -757,7 +774,8 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
 static int
 print_set_done(struct ipset_session *session)
 {
-       D("called");
+       D("called for %s", session->saved_setname[0] == '\0'
+               ? "NONE" : session->saved_setname);
        switch (session->mode) {
        case IPSET_LIST_XML:
                if (session->saved_setname[0] == '\0')
@@ -824,6 +842,7 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
                        cmd2name[cmd]);
 
        ATTR2DATA(session, nla, IPSET_ATTR_SETNAME, cmd_attrs);
+       D("setname %s", ipset_data_setname(data));
        if (STREQ(ipset_data_setname(data), session->saved_setname)) {
                /* Header part already seen */
                if (ipset_data_test(data, IPSET_OPT_TYPE)
@@ -851,12 +870,18 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
                                !nla[IPSET_ATTR_TYPENAME] ? "typename" : 
                                !nla[IPSET_ATTR_FAMILY] ? "family" : "revision");
 
+               /* Reset CREATE specific flags */
+               ipset_data_flags_unset(data, IPSET_CREATE_FLAGS);
+               D("nla typename %s",
+                 (char *) mnl_attr_get_payload(nla[IPSET_ATTR_TYPENAME]));
+               D("nla typename %s",
+                 (char *) mnl_attr_get_payload(nla[IPSET_ATTR_TYPENAME]));
                ATTR2DATA(session, nla, IPSET_ATTR_FAMILY, cmd_attrs);
                ATTR2DATA(session, nla, IPSET_ATTR_TYPENAME, cmd_attrs);
                ATTR2DATA(session, nla, IPSET_ATTR_REVISION, cmd_attrs);
-
-               /* Reset CREATE specific flags */
-               ipset_data_flags_unset(data, IPSET_CREATE_FLAGS);
+               D("head: family %u, typename %s",
+                 ipset_data_family(data),
+                 (char *) ipset_data_get(data, IPSET_OPT_TYPENAME));
                if (mnl_attr_parse_nested(nla[IPSET_ATTR_DATA],
                                          create_attr_cb, cattr) < 0)
                        FAILURE("Broken %s kernel message: "
@@ -869,8 +894,9 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
        
        if (nla[IPSET_ATTR_ADT] != NULL) {
                struct nlattr *tb, *adt[IPSET_ATTR_ADT_MAX+1];
-               
+
                mnl_attr_for_each_nested(tb, nla[IPSET_ATTR_ADT]) {
+                       D("ADT attributes for %s", ipset_data_setname(data));
                        memset(adt, 0, sizeof(adt));
                        /* Reset ADT specific flags */
                        ipset_data_flags_unset(data, IPSET_ADT_FLAGS);
@@ -950,6 +976,7 @@ callback_header(struct ipset_session *session, struct nlattr *nla[])
        ATTR2DATA(session, nla, IPSET_ATTR_TYPENAME, cmd_attrs);
        ATTR2DATA(session, nla, IPSET_ATTR_REVISION, cmd_attrs);
        ATTR2DATA(session, nla, IPSET_ATTR_FAMILY, cmd_attrs);
+       D("got family: %u", ipset_data_family(session->data));
 
        return MNL_CB_STOP;
 }
@@ -1150,7 +1177,8 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
                case IPSET_CMD_CREATE:
                        /* Add successfully created set to the cache */
                        ipset_cache_add(ipset_data_setname(data),
-                                       ipset_data_get(data, IPSET_OPT_TYPE));
+                                       ipset_data_get(data, IPSET_OPT_TYPE),
+                                       ipset_data_family(data));
                        break;
                case IPSET_CMD_DESTROY:
                        /* Delete destroyed sets from the cache */
@@ -1750,7 +1778,7 @@ ipset_session_init(ipset_outfn outfn)
        if (session->data == NULL)
                goto free_session;
 
-       ipset_types_init();
+       ipset_cache_init();
        return session;
 
 free_session:
@@ -1776,7 +1804,7 @@ ipset_session_fini(struct ipset_session *session)
        if (session->data)
                ipset_data_fini(session->data);
 
-       ipset_types_fini();
+       ipset_cache_fini();
        free(session);
        return 0;
 }
index a6476eae912206d528b8bf805fca725cd7a43067..b39a04f5fbe31286e556d90a0ebc4bc066732edd 100644 (file)
@@ -13,6 +13,7 @@
 #include <stdlib.h>                            /* malloc, free */
 #include <stdio.h>                             /* FIXME: debug */
 
+#include <libipset/debug.h>                    /* D() */
 #include <libipset/data.h>                     /* ipset_data_* */
 #include <libipset/session.h>                  /* ipset_cmd */
 #include <libipset/utils.h>                    /* STREQ */
@@ -23,6 +24,7 @@
 struct ipset {
        char name[IPSET_MAXNAMELEN];            /* set name */
        const struct ipset_type *type;          /* set type */
+       uint8_t family;                         /* family */
        struct ipset *next;
 };
 
@@ -40,7 +42,8 @@ static struct ipset *setlist = NULL;          /* cached sets */
  * Returns 0 on success or a negative error code.
  */
 int
-ipset_cache_add(const char *name, const struct ipset_type *type)
+ipset_cache_add(const char *name, const struct ipset_type *type,
+               uint8_t family)
 {
        struct ipset *s, *n;
 
@@ -53,13 +56,14 @@ ipset_cache_add(const char *name, const struct ipset_type *type)
 
        ipset_strncpy(n->name, name, IPSET_MAXNAMELEN);
        n->type = type;
+       n->family = family;
        n->next = NULL; 
 
        if (setlist == NULL) {
                setlist = n;
                return 0;
        }
-       for (s = setlist; s->next == NULL; s = s->next) {
+       for (s = setlist; s->next != NULL; s = s->next) {
                if (STREQ(name, s->name)) {
                        free(n);
                        return -EEXIST;
@@ -171,6 +175,22 @@ ipset_cache_swap(const char *from, const char *to)
 #define MATCH_FAMILY(type, f)  \
        (f == AF_UNSPEC || type->family == f || type->family == AF_INET46)
 
+bool
+ipset_match_typename(const char *name, const struct ipset_type *type)
+{
+       const char * const * alias = type->alias;
+
+       if (STREQ(name, type->name))
+               return true;
+
+       while (alias[0]) {
+               if (STREQ(name, alias[0]))
+                       return true;
+               alias++;
+       }
+       return false;
+} 
+
 static inline const struct ipset_type *
 create_type_get(struct ipset_session *session)
 {
@@ -192,7 +212,7 @@ create_type_get(struct ipset_session *session)
                /* Skip revisions which are unsupported by the kernel */
                if (t->kernel_check == IPSET_KERNEL_MISMATCH)
                        continue;
-               if ((STREQ(typename, t->name) || STREQ(typename, t->alias))
+               if (ipset_match_typename(typename, t)
                    && MATCH_FAMILY(t, family)) {
                        if (match == NULL) {
                                match = t;
@@ -390,8 +410,9 @@ ipset_type_check(struct ipset_session *session)
        for (t = typelist; t != NULL && match == NULL; t = t->next) {
                if (t->kernel_check == IPSET_KERNEL_MISMATCH)
                        continue;
-               if ((STREQ(typename, t->name) || STREQ(typename, t->alias))
-                   && MATCH_FAMILY(t, family) && t->revision == revision)
+               if (ipset_match_typename(typename, t)
+                   && MATCH_FAMILY(t, family)
+                   && t->revision == revision)
                        match = t;
        }
        if (!match)
@@ -503,7 +524,7 @@ ipset_typename_resolve(const char *str)
        const struct ipset_type *t;
 
        for (t = typelist; t != NULL; t = t->next)
-               if (STREQ(str, t->name) || STREQ(str, t->alias))
+               if (ipset_match_typename(str, t))
                        return t->name;
        return NULL;
 }
@@ -523,38 +544,25 @@ ipset_types(void)
 }
 
 /**
- * ipset_types_init - initialize known set types
+ * ipset_cache_init - initialize set cache
  *
- * Initialize the type list with the known, supported set types.
+ * Initialize the set cache in userspace.
  *
  * Returns 0 on success or a negative error code.
  */
 int
-ipset_types_init(void)
+ipset_cache_init(void)
 {
-       if (typelist != NULL)
-               return 0;
-
-       ipset_type_add(&ipset_bitmap_ip0);
-       ipset_type_add(&ipset_bitmap_ipmac0);
-       ipset_type_add(&ipset_bitmap_port0);
-       ipset_type_add(&ipset_hash_ip0);
-       ipset_type_add(&ipset_hash_net0);
-       ipset_type_add(&ipset_hash_ipport0);
-       ipset_type_add(&ipset_hash_ipportip0);
-       ipset_type_add(&ipset_hash_ipportnet0);
-       ipset_type_add(&ipset_tree_ip0);
-       ipset_type_add(&ipset_list_set0);
        return 0;
 }
 
 /**
- * ipset_types_fini - release initialized known set types
+ * ipset_cache_fini - release the set cache
  *
- * Release initialized known set types and remove the set cache.
+ * Release the set cache.
  */
 void
-ipset_types_fini(void)
+ipset_cache_fini(void)
 {
        struct ipset *set;
        
diff --git a/lib/utils.c b/lib/utils.c
deleted file mode 100644 (file)
index bddeb87..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/* Copyright 2007-20010 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.
- */
-#include <assert.h>                            /* assert */
-#include <stdbool.h>                           /* bool */
-#include <stdlib.h>                            /* malloc, free */
-#include <string.h>                            /* memset, str* */
-
-#include <libipset/session.h>                  /* ipset_err */
-#include <libipset/utils.h>                    /* prototypes */
-
-/**
- * ipset_strchr - locate character(s) in string
- * @str: string to locate the character(s) in
- * @sep: string of characters to locate
- *
- * Return a pointer to the first occurence of any of the
- * characters to be located in the string. NULL is returned
- * if no character is found.
- */
-char *
-ipset_strchr(const char *str, const char *sep)
-{
-       char *match;
-       
-       assert(str);
-       assert(sep);
-       
-       for (; *sep != '\0'; sep++)
-               if ((match = strchr(str, (int)sep[0])) != NULL)
-                       return match;
-       
-       return NULL;
-}
-
-/**
- * ipset_name_match - match a string against an array of strings
- * @arg: string
- * @name: array of strings, last one is a NULL pointer
- *
- * Return true if arg matches any of the strings in the array.
- */
-bool
-ipset_name_match(const char *arg, const char * const name[])
-{
-       int i = 0;
-       
-       assert(arg);
-       assert(name);
-       
-       while (name[i]) {
-               if (STREQ(arg, name[i]))
-                       return true;
-               i++;
-       }
-       
-       return false;
-}
-
-/**
- * ipset_shift_argv - shift off an argument
- * @arc: argument count
- * @argv: array of argument strings
- * @from: from where shift off an argument
- *
- * Shift off the argument at "from" from the array of
- * arguments argv of size argc.
- */
-void
-ipset_shift_argv(int *argc, char *argv[], int from)
-{
-       int i;
-       
-       assert(*argc >= from + 1);
-
-       for (i = from + 1; i <= *argc; i++) {
-               argv[i-1] = argv[i];
-       }
-       (*argc)--;
-       return;
-}
-
-/**
- * ipset_strncpy - copy the string from src to dst
- * @dst: the target string buffer
- * @src: the source string buffer
- * @len: the length of bytes to copy, including the terminating null byte.
- *
- * Copy the string from src to destination, but at most len bytes are
- * copied. The target is unconditionally terminated by the null byte.
- */
-void
-ipset_strncpy(char *dst, const char *src, size_t len)
-{
-       assert(dst);
-       assert(src);
-
-       strncpy(dst, src, len);
-       dst[len - 1] = '\0';
-}
index 685cd2377baf8b0288641521629d11aa53eaae7b..344cfc8b5153b46840bf6463f87bbf7174d31dfd 100644 (file)
@@ -37,7 +37,7 @@ index ab5d312..ef8b229 100644
  #define NL_NONROOT_RECV 0x1
  #define NL_NONROOT_SEND 0x2
 diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
-index 19e9800..1b9dbe8 100644
+index 19e9800..7d85d45 100644
 --- a/net/netlink/af_netlink.c
 +++ b/net/netlink/af_netlink.c
 @@ -1714,15 +1714,18 @@ errout:
@@ -64,17 +64,17 @@ index 19e9800..1b9dbe8 100644
  
        cb = kzalloc(sizeof(*cb), GFP_KERNEL);
        if (cb == NULL)
-@@ -1748,6 +1751,10 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
-               sock_put(sk);
-               return -EBUSY;
-       }
+@@ -1733,6 +1736,10 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
+       cb->nlh = nlh;
+       atomic_inc(&skb->users);
+       cb->skb = skb;
 +      va_start(args, init);
 +      for (i = 0; i < init; i++)
-+              cb->args[i] = va_arg(args, unsigned long);
++              cb->args[i] = va_arg(args, long);
 +      va_end(args);
-       nlk->cb = cb;
-       mutex_unlock(nlk->cb_mutex);
  
+       sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).pid);
+       if (sk == NULL) {
 @@ -1759,7 +1766,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
         */
        return -EINTR;
index 28b28fa402b70ef0cbddd22cf6ad40d5f9c0ee44..ebd08a3ea0895c0f9aa62648cc4f8b5e2323b71b 100644 (file)
@@ -12,7 +12,6 @@ ipset_SOURCES = ipset.c \
        ipset_hash_ipportnet.c \
        ipset_hash_net.c \
        ipset_list_set.c \
-       ipset_tree_ip.c \
        ui.c
 ipset_LDADD    = ../lib/libipset.la
 AM_LDFLAGS     = -static
index 34b87a3fa65f9df0d7b13ff6083f72cc589960d8..c30ecb666f0154dd54964bf2ed28f66f2ceef302 100644 (file)
@@ -8,6 +8,7 @@
 #include <errno.h>                             /* errno */
 #include <string.h>                            /* strerror */
 
+#include <libipset/debug.h>                    /* D() */
 #include <libipset/data.h>                     /* ipset_data_get */
 #include <libipset/session.h>                  /* ipset_err */
 #include <libipset/types.h>                    /* struct ipset_type */
@@ -15,6 +16,7 @@
 #include <libipset/errcode.h>                  /* prototypes */
 #include <libipset/linux_ip_set_bitmap.h>      /* bitmap specific errcodes */
 #include <libipset/linux_ip_set_hash.h>                /* hash specific errcodes */
+#include <libipset/linux_ip_set_list.h>                /* list specific errcodes */
 
 /* Core kernel error codes */
 static const struct ipset_errcode_table core_errcode_table[] = {
@@ -45,6 +47,8 @@ static const struct ipset_errcode_table core_errcode_table[] = {
        /* RENAME specific error codes */
        { IPSET_ERR_EXIST_SETNAME2, IPSET_CMD_RENAME,
          "Set cannot be renamed: a set with the new name already exists" },
+       { IPSET_ERR_REFERENCED, IPSET_CMD_RENAME,
+         "Set cannot be renamed: it is in use by another system" },
 
        /* SWAP specific error codes */
        { IPSET_ERR_EXIST_SETNAME2, IPSET_CMD_SWAP,
@@ -101,6 +105,24 @@ static const struct ipset_errcode_table hash_errcode_table[] = {
        { },
 };
 
+/* List type-specific error codes */
+static const struct ipset_errcode_table list_errcode_table[] = {
+       /* Generic (CADT) error codes */
+       { IPSET_ERR_NAME, 0,
+         "Set to be added/deleted/tested as element does not exist." },
+       { IPSET_ERR_LOOP, 0,
+         "Sets with list:set type cannot be added to the set." },
+       { IPSET_ERR_BEFORE, 0,
+         "No reference set specified." },
+       { IPSET_ERR_NAMEREF, 0,
+         "The set to which you referred with 'before' or 'after' does not exist." },
+       { IPSET_ERR_LIST_FULL, 0,
+         "The set is full, more elements cannot be added." },
+       { IPSET_ERR_REF_EXIST, 0,
+         "The set to which you referred with 'before' or 'after' is not added to the set." },
+       { },
+};
+
 #define MATCH_TYPENAME(a, b)   STRNEQ(a, b, strlen(b))
 
 /**
@@ -126,8 +148,10 @@ ipset_errcode(struct ipset_session *session, enum ipset_cmd cmd, int errcode)
                if (type) {
                        if (MATCH_TYPENAME(type->name, "bitmap:"))
                                table = bitmap_errcode_table;
-                       if (MATCH_TYPENAME(type->name, "hash:"))
+                       else if (MATCH_TYPENAME(type->name, "hash:"))
                                table = hash_errcode_table;
+                       else if (MATCH_TYPENAME(type->name, "list:"))
+                               table = list_errcode_table;
                }
        }
 
index fa73298ca1c4cc17a9c7f9d1f3ed81f9baeb8199..661d1b47d0ce1f11cd0349867d992f8c2bf15919 100644 (file)
-.TH IPSET 8 "Feb 05, 2004" "" ""
-.\"
 .\" Man page written by 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 as published by
-.\"    the Free Software Foundation; either version 2 of the License, or
-.\"    (at your option) any later version.
-.\"
-.\"    This program is distributed in the hope that it will be useful,
-.\"    but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\"    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-.\"    GNU General Public License for more details.
-.\"
-.\"    You should have received a copy of the GNU General Public License
-.\"    along with this program; if not, write to the Free Software
-.\"    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-.\"
-.\"
-.SH NAME
+.\" 
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\" 
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\" 
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.TH "IPSET" "8" "Jun 11, 2010" "Jozsef Kadlecsik" ""
+.SH "NAME"
 ipset \(em administration tool for IP sets
-.SH SYNOPSIS
-.PP
-\fBipset \-N\fP \fIset\fP \fItype-specification\fP [\fIoptions\fP...]
-.PP
-\fBipset\fP {\fB\-F\fP|\fB\-H\fP|\fB\-L\fP|\fB\-S\fP|\fB\-X\fP} [\fIset\fP]
-[\fIoptions\fP...]
-.PP
-\fBipset\fP {\fB\-E\fP|\fB\-W\fP} \fIfrom-set\fP \fIto-set\fP
-.PP
-\fBipset\fP {\fB\-A\fP|\fB\-D\fP|\fB\-T\fP} \fIset\fP \fIentry\fP
-.PP
-\fBipset \-R\fP
-.PP
-\fBipset\fP {\fB-V\fP|\fB\-v\fP}
-.SH DESCRIPTION
-.B ipset
+.SH "SYNOPSIS"
+\fBipset\fR [ \fIOPTIONS\fR ] \fICOMMAND\fR [ \fICOMMAND\-OPTIONS\fR ]
+.PP 
+COMMANDS := { \fBcreate\fR | \fBadd\fR | \fBdel\fR | \fBtest\fR | \fBdestroy\fR | \fBlist\fR | \fBsave\fR | \fBrestore\fR | \fBflush\fR | \fBrename\fR | \fBswap\fR | \fBhelp\fR | \fBversion\fR | \fB\-\fR }
+.PP 
+\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR }
+.PP 
+\fBipset\fR \fBcreate\fR \fISETNAME\fR \fITYPENAME\fR [ \fICREATE\-OPTIONS\fR ]
+.PP 
+\fBipset\fR \fBadd\fR \fISETNAME\fR \fIADD\-ENTRY\fR [ \fIADD\-OPTIONS\fR ]
+.PP 
+\fBipset\fR \fBdel\fR \fISETNAME\fR \fIDEL\-ENTRY\fR [ \fIDEL\-OPTIONS\fR ]
+.PP 
+\fBipset\fR \fBtest\fR \fISETNAME\fR \fITEST\-ENTRY\fR [ \fITEST\-OPTIONS\fR ]
+.PP 
+\fBipset\fR \fBdestroy\fR [ \fISETNAME\fR ]
+.PP 
+\fBipset\fR \fBlist\fR [ \fISETNAME\fR ]
+.PP 
+\fBipset\fR \fBsave\fR [ \fISETNAME\fR ]
+.PP 
+\fBipset\fR \fBrestore\fR
+.PP 
+\fBipset\fR \fBflush\fR [ \fISETNAME\fR ]
+.PP 
+\fBipset\fR \fBrename\fR \fISETNAME\-FROM\fR \fISETNAME\-TO\fR
+.PP 
+\fBipset\fR \fBswap\fR \fISETNAME\-FROM\fR \fISETNAME\-TO\fR
+.PP 
+\fBipset\fR \fBhelp\fR [ \fITYPENAME\fR ]
+.PP 
+\fBipset\fR \fBversion\fR
+.PP 
+\fBipset\fR \fB\-\fR
+.SH "DESCRIPTION"
+\fBipset\fR
 is used to set up, maintain and inspect so called IP sets in the Linux
-kernel. Depending on the type, an IP set may store IP addresses, (TCP/UDP)
-port numbers or additional informations besides IP addresses: the word IP 
-means a general term here. See the set type definitions below.
-.P
-Iptables matches and targets referring to sets creates references, which
-protects the given sets in the kernel. A set cannot be removed (destroyed)
+kernel. Depending on the type of the set, an IP set may store IP(v4/v6)
+addresses, (TCP/UDP) port numbers, IP and MAC address pairs, IP address
+and port number pairs, etc. See the set type definitions below.
+.PP 
+\fBIptables\fR
+matches and targets referring to sets creates references, which
+protect the given sets in the kernel. A set cannot be destroyed
 while there is a single reference pointing to it.
-.SH OPTIONS
+.SH "OPTIONS"
 The options that are recognized by
-.B ipset
+\fBipset\fR
 can be divided into several different groups.
 .SS COMMANDS
-These options specify the specific action to perform.  Only one of them
-can be specified on the command line unless otherwise specified
-below.  For all the long versions of the command and option names, you
-need to use only enough letters to ensure that
-.B ipset
-can differentiate it from all other options.
-.TP
-\fB\-N\fP, \fB\-\-create\fP \fIsetname\fP \fItype\fP \fItype-specific-options\fP
-Create a set identified with setname and specified type. 
-Type-specific options must be supplied.
-.TP
-\fB\-X\fP, \fB\-\-destroy\fP [\fIsetname\fP]
+These options specify the desired action to perform.  Only one of them
+can be specified on the command line unless otherwise specified below.
+For all the long versions of the command names, you need to use only enough
+letters to ensure that
+\fBipset\fR
+can differentiate it from all other options. The
+\fBipset\fR
+parser follows the order here when looking for the shortest match
+in the long command names.
+.TP 
+\fBn\fP, \fBcreate\fP \fISETNAME\fP \fITYPENAME\fP [ \fICREATE\-OPTIONS\fP ]
+Create a set identified with setname and specified type. The type may require
+type specific options. If the
+\fB\-exist\fR
+option is specified,
+\fBipset\fR
+ignores the error otherwise raised when the the same set (setname and create parameters
+are identical) already exists.
+.TP 
+\fBadd\fP \fISETNAME\fP \fIADD\-ENTRY\fP [ \fIADD\-OPTIONS\fP ]
+Add a given entry to the set. If the
+\fB\-exist\fR
+option is specified,
+\fBipset\fR
+ignores if the entry already added to the set.
+.TP 
+\fBdel\fP \fISETNAME\fP \fIDEL\-ENTRY\fP [ \fIDEL\-OPTIONS\fP ]
+Delete an entry from a set. If the
+\fB\-exist\fR
+option is specified,
+\fBipset\fR
+ignores if the entry does not added (expired) to the set.
+.TP 
+\fBtest\fP \fISETNAME\fP \fITEST\-ENTRY\fP [ \fITEST\-OPTIONS\fP ]
+Test wether an entry is in a set or not. Exit status number is zero
+if the tested entry is in the set and nonzero if it is missing from
+the set.
+.TP 
+\fBx\fP, \fBdestroy\fP [ \fISETNAME\fP ]
 Destroy the specified set or all the sets if none is given.
 
-If the set has got references, nothing is done.
-.TP
-\fB\-F\fP, \fB\-\-flush\fP [\fIsetname\fP]
-Delete all entries from the specified set or flush
-all sets if none is given.
-.TP
-\fB\-E\fP, \fB\-\-rename\fP \fIfrom-setname\fP \fIto-setname\fP
-Rename a set. Set identified by to-setname must not exist.
-.TP
-\fB\-W\fP, \fB\-\-swap\fP \fIfrom-setname\fP \fIto-setname\fP
-Swap the content of two sets, or in another words, 
-exchange the name of two sets. The referred sets must exist and
-identical type of sets can be swapped only.
-.TP
-\fB\-L\fP, \fB\-\-list\fP [\fIsetname\fP]
-List the entries for the specified set, or for
+If the set has got reference(s), nothing is done and no set destroyed.
+.TP 
+\fBlist\fP [ \fISETNAME\fP ]
+List the header data and the entries for the specified set, or for
 all sets if none is given. The
-\fB\-r\fP/\fB\-\-resolve\fP
+\fB\-\-resolve\fP
 option can be used to force name lookups (which may be slow). When the
-\fB\-s\fP/\fB\-\-sorted\fP
+\fB\-\-sorted\fP
 option is given, the entries are listed sorted (if the given set
-type supports the operation).
-.TP
-\fB\-S\fP, \fB\-\-save\fP [\fIsetname\fP]
+type supports the operation). The option
+\fB\-\-output\fR
+can be used to control the format of the listing:
+\fBplain\fR, \fBsave\fR or \fBxml\fR.
+The default is
+\fBplain\fR. 
+.TP 
+\fBsave\fP [ \fISETNAME\fP ]
 Save the given set, or all sets if none is given
-to stdout in a format that \fB\-\-restore\fP can read.
-.TP
-\fB\-R\fP, \fB\-\-restore\fP
-Restore a saved session generated by \fB\-\-save\fP. The saved session
-can be fed from stdin.
-
-When generating a session file please note that the supported commands
-(create set and add element) must appear in a strict order: first create
-the set, then add all elements. Then create the next set, add all its elements
-and so on. Also, it is a restore operation, so the sets being restored must 
-not exist.
-.TP
-\fB\-A\fP, \fB\-\-add\fP \fIsetname\fP \fIentry\fP
-Add an entry to a set.
-.TP
-\fB\-D\fP, \fB\-\-del\fP \fIsetname\fP \fIentry\fP
-Delete an entry from a set.
-.TP
-\fB-T\fP, \fB\-\-test\fP \fIsetname\fP \fIentry\fP
-Test wether an entry is in a set or not. Exit status number is zero
-if the tested entry is in the set and nonzero if it is missing from
-the set.
-.TP
-\fB\-H\fP, \fB\-\-help\fP [\fIsettype\fP]
-Print help and settype specific help if settype specified.
-.TP
-\fB\-V\fP, \fB\-v\fP, \fB\-\-version\fP
-Print program version and protocol version.
+to stdout in a format that
+\fBrestore\fP
+can read.
+.TP 
+\fBrestore\fP
+Restore a saved session generated by
+\fBsave\fP.
+The saved session can be fed from stdin.
+.TP 
+\fBflush\fP [ \fISETNAME\fP ]
+Flush all entries from the specified set or flush
+all sets if none is given.
+.TP 
+\fBe\fP, \fBrename\fP \fISETNAME\-FROM\fP \fISETNAME\-TO\fP
+Rename a set. Set identified by
+\fISETNAME\-TO\fR
+must not exist.
+.TP 
+\fBw\fP, \fBswap\fP \fISETNAME\-FROM\fP \fISETNAME\-TO\fP
+Swap the content of two sets, or in another words, 
+exchange the name of two sets. The referred sets must exist and
+identical type of sets can be swapped only.
+.TP 
+\fBhelp\fP [ \fITYPENAME\fP ]
+Print help and set type specific help if
+\fITYPENAME\fR
+is specified.
+.TP 
+\fBversion\fP
+Print program version.
+.TP 
+\fB\-\fP
+If a dash is specified as command, then
+\fBipset\fR
+enters a simple interactive mode and the commands are read from the standard input.
+The interactive mode can be finished by entering the pseudo\-command
+\fBquit\fR.
 .P
 .SS "OTHER OPTIONS"
-The following additional options can be specified:
-.TP
-\fB\-r\fP, \fB\-\-resolve\fP
+The following additional options can be specified. The long option names
+cannot be abbreviated.
+.TP 
+\fB\-!\fP, \fB\-exist\fP
+Ignore errors when the exactly the same set is to be created or already
+added entry is added or missing entry is deleted.
+.TP 
+\fB\-o\fP, \fB\-output\fP { \fBplain\fR | \fBsave\fR | \fBxml\fR }
+Select the output format to the
+\fBlist\fR
+command.
+.TP 
+\fB\-q\fP, \fB\-quiet\fP
+Suppress any output to stdout and stderr.
+\fBipset\fR
+will still exit with error if it cannot continue.
+.TP 
+\fB\-r\fP, \fB\-resolve\fP
 When listing sets, enforce name lookup. The 
 program will try to display the IP entries resolved to 
-host names or services (whenever applicable), which can trigger
-.B
-slow
-DNS 
-lookups.
-.TP
-\fB\-s\fP, \fB\-\-sorted\fP
+host names which requires
+\fBslow\fR
+DNS lookups.
+.TP 
+\fB\-s\fP, \fB\-sorted\fP
 Sorted output. When listing sets, entries are listed sorted.
-.TP
-\fB\-n\fP, \fB\-\-numeric\fP
-Numeric output. When listing sets, IP addresses and 
-port numbers will be printed in numeric format. This is the default.
-.TP
-\fB\-q\fP, \fB\-\-quiet\fP
-Suppress any output to stdout and stderr. ipset will still return
-possible errors.
-.SH SET TYPES
-ipset supports the following set types:
-.SS ipmap
-The ipmap set type uses a memory range, where each bit represents
-one IP address. An ipmap set can store up to 65536 (B-class network)
-IP addresses. The ipmap set type is very fast and memory cheap, great
-for use when one want to match certain IPs in a range. If the optional
-\fB\-\-netmask\fP
-parameter is specified with a CIDR netmask value between 1-31 then
-network addresses are stored in the given set: i.e an
-IP address will be in the set if the network address, which is resulted
-by masking the address with the specified netmask, can be found in the set.
-.P
-Options to use when creating an ipmap set:
-.TP
-\fB\-\-from\fP \fIfrom-addr\fP
-.TP
-\fB\-\-to\fP \fIto-addr\fP
-Create an ipmap set from the specified address range.
-.TP
-\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP
-Create an ipmap set from the specified network.
-.TP
-\fB\-\-netmask\fP \fIprefixlen\fP
-When the optional
-\fB\-\-netmask\fP
-parameter specified, network addresses will be 
-stored in the set instead of IP addresses, and the \fIfrom-addr\fP parameter
-must be a network address. The \fIprefixlen\fP value must be between 1-31.
-.PP
-Example:
-.IP
-ipset \-N test ipmap \-\-network 192.168.0.0/16 
-.SS macipmap
-The macipmap set type uses a memory range, where each 8 bytes
-represents one IP and a MAC addresses. A macipmap set type can store
-up to 65536 (B-class network) IP addresses with MAC.
-When adding an entry to a macipmap set, you must specify the entry as
-"\fIaddress\fP\fB,\fP\fImac\fP".
-When deleting or testing macipmap entries, the
-"\fB,\fP\fImac\fP"
-part is not mandatory.
-.P
-Options to use when creating an macipmap set:
-.TP
-\fB\-\-from\fP \fIfrom-addr\fP
-.TP
-\fB\-\-to\fP \fIto-addr\fP
-Create a macipmap set from the specified address range.
-.TP
-\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP
-Create a macipmap set from the specified network.
-.TP
-\fB\-\-matchunset\fP
-When the optional
-\fB\-\-matchunset\fP
-parameter specified, IP addresses which could be stored 
-in the set but not set yet, will always match.
-.P
-Please note, the 
-"set"
-and
-"SET"
-netfilter kernel modules
-.B
-always
-use the source MAC address from the packet to match, add or delete
-entries from a macipmap type of set.
-.SS portmap
-The portmap set type uses a memory range, where each bit represents
-one port. A portmap set type can store up to 65536 ports.
-The portmap set type is very fast and memory cheap.
-.P
-Options to use when creating an portmap set:
-.TP
-\fB\-\-from\fP \fIfrom-port\fP
-.TP
-\fB\-\-to\fP \fIto-port\fP
-Create a portmap set from the specified port range.
-.SS iphash
-The iphash set type uses a hash to store IP addresses.
-In order to avoid clashes in the hash double-hashing, and as a last
-resort, dynamic growing of the hash performed. The iphash set type is
-great to store random addresses. If the optional
-\fB\-\-netmask\fP
-parameter is specified with a CIDR prefix length value between 1-31 then
-network addresses are stored in the given set: i.e an
-IP address will be in the set if the network address, which is resulted
-by masking the address with the specified netmask, can be found in the set.
-.P
-Options to use when creating an iphash set:
-.TP
-\fB\-\-hashsize\fP \fIhashsize\fP
-The initial hash size (default 1024)
-.TP
-\fB\-\-probes\fP \fIprobes\fP
-How many times try to resolve clashing at adding an IP to the hash 
-by double-hashing (default 8).
-.TP
-\fB\-\-resize\fP \fIpercent\fP
-Increase the hash size by this many percent (default 50) when adding
-an IP to the hash could not be performed after
-\fIprobes\fP
-number of double-hashing. 
-.TP
-\fB\-\-netmask\fP \fIprefixlen\fP
-When the optional
-\fB\-\-netmask\fP
-parameter specified, network addresses will be 
-stored in the set instead of IP addresses. The \fIprefixlen\fP value must
-be between 1-31.
-.P
-The iphash type of sets can store up to 65536 entries. If a set is full,
-no new entries can be added to it.
-.P
-Sets created by zero valued resize parameter won't be resized at all.
-The lookup time in an iphash type of set grows approximately linearly with
-the value of the 
-\fIprobes\fP
-parameter. In general higher 
-\fIprobes\fP
-value results better utilized hash while smaller value
-produces larger, sparser hash.
-.PP
-Example:
-.IP
-ipset \-N test iphash \-\-probes 2
-.SS nethash
-The nethash set type uses a hash to store different size of
-network addresses. The
-.I
-entry
-used in the ipset commands must be in the form
-"\fIaddress\fP\fB/\fP\fIprefixlen\fP"
-where prefixlen must be in the inclusive range of 1-31.
-In order to avoid clashes in the hash 
-double-hashing, and as a last resort, dynamic growing of the hash performed.
-.P
-Options to use when creating an nethash set:
-.TP
-\fB\-\-hashsize\fP \fIhashsize\fP
-The initial hash size (default 1024)
-.TP
-\fB\-\-probes\fP \fIprobes\fP
-How many times try to resolve clashing at adding an IP to the hash 
-by double-hashing (default 4).
-.TP
-\fB\-\-resize\fP \fIpercent\fP
-Increase the hash size by this many percent (default 50) when adding
-an IP to the hash could not be performed after
-.P
-The nethash type of sets can store up to 65536 entries. If a set is full,
-no new entries can be added to it.
-.P
-An IP address will be in a nethash type of set if it belongs to any of the
-netblocks added to the set. The matching always start from the smallest
-size of netblock (most specific netmask) to the largest ones (least
-specific netmasks). When adding/deleting IP addresses
-to a nethash set by the
-"SET"
-netfilter kernel module, it will be added/deleted by the smallest
-netblock size which can be found in the set, or by /31 if the set is empty.
-.P
-The lookup time in a nethash type of set grows approximately linearly 
-with the times of the
-\fIprobes\fP
-parameter and the number of different mask parameters in the hash.
-Otherwise the same speed and memory efficiency comments applies here 
-as at the iphash type.
-.SS ipporthash
-The ipporthash set type uses a hash to store IP address and port pairs.
-In order to avoid clashes in the hash double-hashing, and as a last
-resort, dynamic growing of the hash performed. An ipporthash set can 
-store up to 65536 (B-class network) IP addresses with all possible port
-values. When adding, deleting and testing values in an ipporthash type of
-set, the entries must be specified as
-"\fIaddress\fP\fB,\fP\fIport\fP".
-.P
-The ipporthash types of sets evaluates two src/dst parameters of the 
-"set"
-match and 
-"SET"
-target. 
-.P
-Options to use when creating an ipporthash set:
-.TP
-\fB\-\-from\fP \fIfrom-addr\fP
-.TP
-\fB\-\-to\fP \fIto-addr\fP
-Create an ipporthash set from the specified address range.
-.TP
-\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP
-Create an ipporthash set from the specified network.
-.TP
-\fB\-\-hashsize\fP \fIhashsize\fP
-The initial hash size (default 1024)
-.TP
-\fB\-\-probes\fP \fIprobes\fP
-How many times try to resolve clashing at adding an IP to the hash 
-by double-hashing (default 8).
-.TP
-\fB\-\-resize\fP \fIpercent\fP
-Increase the hash size by this many percent (default 50) when adding
-an IP to the hash could not be performed after
-\fIprobes\fP
-number of double-hashing.
-.P
-The same resizing, speed and memory efficiency comments applies here 
-as at the iphash type.
-.SS ipportiphash
-The ipportiphash set type uses a hash to store IP address,port and IP
-address triples. The first IP address must come form a maximum /16
-sized network or range while the port number and the second IP address
-parameters are arbitrary. When adding, deleting and testing values in an 
-ipportiphash type of set, the entries must be specified as
-"\fIaddress\fP\fB,\fP\fIport\fP\fB,\fP\fIaddress\fP".
-.P
-The ipportiphash types of sets evaluates three src/dst parameters of the 
-"set"
-match and 
-"SET"
-target. 
-.P
-Options to use when creating an ipportiphash set:
-.TP
-\fB\-\-from\fP \fIfrom-addr\fP
-.TP
-\fB\-\-to\fP \fIto-addr\fP
-Create an ipportiphash set from the specified address range.
-.TP
-\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP
-Create an ipportiphash set from the specified network.
-.TP
-\fB\-\-hashsize\fP \fIhashsize\fP
-The initial hash size (default 1024)
-.TP
-\fB\-\-probes\fP \fIprobes\fP
-How many times try to resolve clashing at adding an IP to the hash 
-by double-hashing (default 8).
-.TP
-\fB\-\-resize\fP \fIpercent\fP
-Increase the hash size by this many percent (default 50) when adding
-an IP to the hash could not be performed after
-\fIprobes\fP
-number of double-hashing.
-.P
-The same resizing, speed and memory efficiency comments applies here 
-as at the iphash type.
-.SS ipportnethash
-The ipportnethash set type uses a hash to store IP address, port, and
-network address triples. The IP address must come form a maximum /16
-sized network or range while the port number and the network address
-parameters are arbitrary, but the size of the network address must be
-between /1-/31. When adding, deleting 
-and testing values in an ipportnethash type of set, the entries must be
-specified as
-"\fIaddress\fP\fB,\fP\fIport\fP\fB,\fP\fIaddress\fP\fB/\fP\fIprefixlen\fP".
-.P
-The ipportnethash types of sets evaluates three src/dst parameters of the 
-"set"
-match and 
-"SET"
-target. 
-.P
-Options to use when creating an ipportnethash set:
-.TP
-\fB\-\-from\fP \fIfrom-address\fP
-.TP
-\fB\-\-to\fP \fIto-address\fP
-Create an ipporthash set from the specified range.
-.TP
-\fB\-\-network\fP \fIaddress\fP\fB/\fP\fImask\fP
-Create an ipporthash set from the specified network.
-.TP
-\fB\-\-hashsize\fP \fIhashsize\fP
-The initial hash size (default 1024)
-.TP
-\fB\-\-probes\fP \fIprobes\fP
-How many times try to resolve clashing at adding an IP to the hash 
-by double-hashing (default 8).
-.TP
-\fB\-\-resize\fP \fIpercent\fP
-Increase the hash size by this many percent (default 50) when adding
-an IP to the hash could not be performed after
-\fIprobes\fP
-number of double-hashing.
-.P
-The same resizing, speed and memory efficiency comments applies here 
-as at the iphash type.
-.SS iptree
-The iptree set type uses a tree to store IP addresses, optionally 
-with timeout values.
-.P
-Options to use when creating an iptree set:
-.TP
-\fB\-\-timeout\fP \fIvalue\fP
-The timeout value for the entries in seconds (default 0)
-.P
-If a set was created with a nonzero valued 
-\fB\-\-timeout\fP
-parameter then one may add IP addresses to the set with a specific 
-timeout value using the syntax 
-"\fIaddress\fP\fB,\fP\fItimeout-value\fP".
-Similarly to the hash types, the iptree type of sets can store up to 65536
-entries.
-.SS iptreemap
-The iptreemap set type uses a tree to store IP addresses or networks, 
-where the last octet of an IP address are stored in a bitmap.
-As input entry, you can add IP addresses, CIDR blocks or network ranges
-to the set. Network ranges can be specified in the format
-"\fIaddress1\fP\fB-\fP\fIaddress2\fP".
-.P
-Options to use when creating an iptreemap set:
-.TP
-\fB\-\-gc\fP \fIvalue\fP
-How often the garbage collection should be called, in seconds (default 300)
-.SS setlist
-The setlist type uses a simple list in which you can store sets. By the
-ipset
-command you can add, delete and test sets in a setlist type of set.
-You can specify the sets as
-"\fIsetname\fP[\fB,\fP{\fBafter\fP|\fBbefore\fP},\fIsetname\fP]".
-By default new sets are added after (appended to) the existing
-elements. Setlist type of sets cannot be added to a setlist type of set.
-.P
-Options to use when creating a setlist type of set:
-.TP
-\fB\-\-size\fP \fIsize\fP
-Create a setlist type of set with the given size (default 8).
-.PP
-By the
-"set"
-match or
-"SET"
-target of
-\fBiptables\fP(8)
-you can test, add or delete entries in the sets. The match
-will try to find a matching IP address/port in the sets and 
-the target will try to add the IP address/port to the first set
-to which it can be added. The number of src,dst options of
-the match and target are important: sets which eats more src,dst
-parameters than specified are skipped, while sets with equal
-or less parameters are checked, elements added. For example
-if
-.I
-a
-and
-.I
-b
-are setlist type of sets then in the command
-.IP
-iptables \-m set \-\-match\-set a src,dst \-j SET \-\-add-set b src,dst
-.PP
-the match and target will skip any set in
-.I a
-and
-.I b
-which stores 
-data triples, but will check all sets with single or double
-data storage in
-.I a
+.SH "SET TYPES"
+A set type comprises of the storage method by which the data is stored and
+the data type(s) which are stored in the set. Therefore the
+\fITYPENAME\fR
+parameter of the
+\fBcreate\fR 
+command follows the syntax
+
+\fITYPENAME\fR := \fImethod\fR\fB:\fR\fItype\fR[\fB,\fR\fItype\fR[\fB,\fR\fItype\fR]]
+
+where the current list of the methods are
+\fBbitmap\fR, \fBhash\fR, \fBlist\fR and the possible data types are \fBip\fR,
+\fBmac\fR and \fBport\fR.
+
+When adding, deleting or testing entries in a set, the same comma separated
+data syntax must be used for the entry parameter of the commands, i.e
+
+ipset add foo ipaddr,portnum,ipaddr
+
+All set types support the optional
+
+\fBtimeout\fR \fIvalue\fR
+
+parameter when creating a set and adding entries. The value of the \fBtimeout\fR
+parameter for the \fBcreate\fR command means the default timeout value (in seconds)
+for new entries. If a set is created with timeout support, then the same 
+\fBtimeout\fR option can be used to specify non\-default timeout values
+when adding entries. Zero timeout value means the entry is added permanent to the set.
+.SS bitmap:ip
+The \fBbitmap:ip\fR set type uses a memory range to store either IPv4 host
+(default) or IPv4 network addresses. A \fBbitmap:ip\fR type of set can store up
+to 65536 entries.
+.PP 
+\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfrom\-ip\fP\-\fIto\-ip\fR|\fIip\fR/\fIcidr\fR [ \fBnetmask\fP \fIcidr\fP ] [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIADD\-ENTRY\fR := { \fIipaddr\fR | \fIfromaddr\fR\-\fItoaddr\fR | \fIipaddr\fR/\fIcidr\fR }
+.PP 
+\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIDEL\-ENTRY\fR := { \fIipaddr\fR | \fIfromaddr\fR\-\fItoaddr\fR | \fIipaddr\fR/\fIcidr\fR }
+.PP 
+\fITEST\-ENTRY\fR := { \fIipaddr\fR }
+.PP 
+Mandatory \fBcreate\fR options:
+.TP 
+\fBrange\fP \fIfrom\-ip\fP\-\fIto\-ip\fR|\fIip\fR/\fIcidr\fR
+Create the set from the specified inclusive address range expressed in an
+IPv4 address range or network. The size of the range (in entries) cannot exceed
+the limit of maximum 65536 elements.
+.PP 
+Optional \fBcreate\fR options:
+.TP 
+\fBnetmask\fP \fIcidr\fP
+When the optional \fBnetmask\fP parameter specified, network addresses will be 
+stored in the set instead of IP host addresses. The \fIcidr\fR value must be
+between 1\-32.
+An IP address will be in the set if the network address, which is resulted by
+masking the address with the specified netmask calculated from the cidr value,
+can be found in the set.
+.PP 
+Examples:
+.IP 
+ipset create foo bitmap:ip range 192.168.0.0/16
+.IP 
+ipset add foo 192.168.1/24
+.IP 
+ipset test foo 192.168.1.1
+.SS bitmap:ip,mac
+The \fBbitmap:ip,mac\fR set type uses a memory range to store IPv4 and a MAC address pairs. A \fBbitmap:ip,mac\fR type of set can store up to 65536 entries.
+.PP 
+\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfrom\-ip\fP\-\fIto\-ip\fR|\fIip\fR/\fIcidr\fR [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIADD\-ENTRY\fR := { \fIipaddr\fR[,\fImac\-addr\fR] }
+.PP 
+\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIDEL\-ENTRY\fR := { \fIipaddr\fR[,\fImac\-addr\fR] }
+.PP 
+\fITEST\-ENTRY\fR := { \fIipaddr\fR[,\fImac\-addr\fR] }
+.PP 
+Mandatory options to use when creating a \fBbitmap:ip,mac\fR type of set:
+.TP 
+\fBrange\fP \fIfrom\-ip\fP\-\fIto\-ip\fR|\fIip\fR/\fIcidr\fR
+Create the set from the specified inclusive address range expressed in an
+IPv4 address range or network. The size of the range cannot exceed the limit
+of maximum 65536 entries.
+.PP 
+The \fBbitmap:ip,mac\fR type is exceptional in the sense that the MAC part can
+be left out when adding/deleting/testing entries in the set. If
+we add an entry without the MAC address specified, when the first time the entry is
+matched by the kernel, it will automatically fill out the missing part with the
+source MAC address from the packet. If the entry was specified with a timeout value,
+the timer starts off when the IP and MAC address pair is complete.
+.PP 
+Please note, the \fBset\fR match and \fBSET\fR target netfilter kernel modules
+\fBalways\fR use the source MAC address from the packet to match, add or delete
+entries from a \fBbitmap:ip,mac\fR type of set.
+.PP 
+Examples:
+.IP 
+ipset create foo bitmap:ip,mac range 192.168.0.0/16
+.IP 
+ipset add foo 192.168.1,12:34:56:78:9A:BC
+.IP 
+ipset test foo 192.168.1.1
+.SS bitmap:port
+The \fBbitmap:port\fR set type uses a memory range to store port numbers
+and such a set can store up to 65536 ports.
+.PP 
+\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfrom\-port\fP\-\fIto\-port [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIADD\-ENTRY\fR := { \fIport\fR | \fIfrom\-port\fR\-\fIto\-port\fR }
+.PP 
+\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIDEL\-ENTRY\fR := {\fIport\fR | \fIfrom\-port\fR\-\fIto\-port\fR }
+.PP 
+\fITEST\-ENTRY\fR := { \fIport\fR }
+.PP 
+Mandatory options to use when creating a \fBbitmap:port\fR type of set:
+.TP 
+\fBrange\fP \fIfrom\-port\fP\-\fIto\-port\fR
+Create the set from the specified inclusive port range.
+.PP 
+Examples:
+.IP 
+ipset create foo bitmap:port range 0\-1024
+.IP 
+ipset add foo 80
+.IP 
+ipset test foo 80
+.SS hash:ip
+The \fBhash:ip\fR set type uses a hash to store IP addresses.
+In order to avoid clashes in the hash a limited number of chaining, and then
+if that is exhausted, the doubling of the hash is performed.
+.PP 
+\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBnetmask\fP \fIcidr\fP ] [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIADD\-ENTRY\fR := { \fIipaddr\fR }
+.PP 
+\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIDEL\-ENTRY\fR := { \fIipaddr\fR }
+.PP 
+\fITEST\-ENTRY\fR := { \fIipaddr\fR }
+.PP 
+For the \fBinet\fR family one can add or delete multiple entries by specifying
+a range or a network:
+.PP 
+\fIADD\-ENTRY\fR := { \fIipaddr\fR | \fIfromaddr\fR\-\fItoaddr\fR | \fIipaddr\fR/\fIcidr\fR }
+.PP 
+\fIDEL\-ENTRY\fR := { \fIipaddr\fR | \fIfromaddr\fR\-\fItoaddr\fR | \fIipaddr\fR/\fIcidr\fR }
+.PP 
+Optional \fBcreate\fR options:
+.TP 
+\fBfamily\fR { \fBinet\fR|\fBinet6\fR }
+The protocol family of the IP addresses to be stored in the set. The default is
+\fBinet\fR, i.e IPv4.
+.TP 
+\fBhashsize\fR \fIvalue\fR
+The initial hash size for the set, default is 1024. The hash size must be a power
+of two, the kernel automatically rounds up non power of two hash sizes to the first
+correct value.
+.TP 
+\fBmaxelem\fR \fIvalue\fR
+The maximal number of elements which can be stored in the set, default 65536.
+.TP 
+\fBnetmask\fP \fIcidr\fP
+When the optional \fBnetmask\fP parameter specified, network addresses will be 
+stored in the set instead of IP host addresses. The \fIcidr\fP value must be
+between 1\-32 for IPv4 and between 1\-128 for IPv6. An IP address will be in the set
+if the network address, which is resulted by masking the address with the netmask
+calculated from the cidr, can be found in the set.
+.PP 
+Examples:
+.IP 
+ipset create foo hash:ip netmask 24
+.IP 
+ipset add foo 192.168.1.1
+.IP 
+ipset test foo 192.168.1.2
+.SS hash:net
+The \fBhash:net\fR set type uses a hash to store different sized of IP networks.
+In order to avoid clashes in the hash a limited number of chaining, and then
+if that is exhausted, the doubling of the hash is performed.
+.PP 
+\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIADD\-ENTRY\fR := { \fIipaddr\fR[/\fIcidr\fR] }
+.PP 
+\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIDEL\-ENTRY\fR := { \fIipaddr\fR[/\fIcidr\fR] }
+.PP 
+\fITEST\-ENTRY\fR := { \fIipaddr\fR[/\fIcidr\fR] }
+.PP 
+Optional \fBcreate\fR options:
+.TP 
+\fBfamily\fR { \fBinet\fR|\fBinet6\fR }
+The protocol family of the IP addresses to be stored in the set. The default is
+\fBinet\fR, i.e IPv4.
+.TP 
+\fBhashsize\fR \fIvalue\fR
+The initial hash size for the set, default is 1024. The hash size must be a power
+of two, the kernel automatically rounds up non power of two hash sizes to the first
+correct value.
+.TP 
+\fBmaxelem\fR \fIvalue\fR
+The maximal number of elements which can be stored in the set, default 65536.
+.PP 
+When adding/deleting/testing entries, if the cidr parameter is not specified,
+then the host cidr value is assumed.
+.PP 
+From the \fBset\fR netfilter match point of view an IP address will be in a \fBhash:net\fR type of set if it belongs to any of the netblocks added to the set.
+The  matching  always  start  from  the smallest  size  of netblock (most specific
+cidr) to the largest ones (least specific cidr).  When  adding/deleting IP
+addresses  to the set by the \fBSET\fR netfilter target, it  will  be
+added/deleted by the most specific cidr which can be found in  the
+set, or by the host cidr value if the set is empty.
+.PP 
+The lookup time grows linearly with the number of the different \fIcidr\fR
+values added to the set. 
+.PP 
+Examples:
+.IP 
+ipset create foo hash:net
+.IP 
+ipset add foo 192.168.0/24
+.IP 
+ipset add foo 10.1.0.0/16
+.IP 
+ipset test foo 192.168.0/24
+.SS hash:ip,port
+The \fBhash:ip,port\fR set type uses a hash to store IP address and port pairs.
+In order to avoid clashes in the hash a limited number of chaining, and then
+if that is exhausted, the doubling of the hash is performed.
+.PP 
+\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIADD\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR }
+.PP 
+\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIDEL\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR }
+.PP 
+\fITEST\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR }
+.PP 
+Optional \fBcreate\fR options:
+.TP 
+\fBfamily\fR { \fBinet\fR|\fBinet6\fR }
+The protocol family of the IP addresses to be stored in the set. The default is
+\fBinet\fR, i.e IPv4.
+.TP 
+\fBhashsize\fR \fIvalue\fR
+The initial hash size for the set, default is 1024. The hash size must be a power
+of two, the kernel automatically rounds up non power of two hash sizes to the first
+correct value.
+.TP 
+\fBmaxelem\fR \fIvalue\fR
+The maximal number of elements which can be stored in the set, default 65536.
+.PP 
+The \fBhash:ip,port\fR type of sets require two \fBsrc\fR/\fBdst\fR parameters of
+the \fBset\fR match and \fBSET\fR target kernel modules.
+.PP 
+Examples:
+.IP 
+ipset create foo hash:ip,port
+.IP 
+ipset add foo 192.168.1.1,80
+.IP 
+ipset test foo 192.168.1.1,80
+.SS hash:ip,port,ip
+The \fBhash:ip,port,ip\fR set type uses a hash to store IP address, port and
+IP address triples. In order to avoid clashes in the hash a limited number of
+chaining, and then if that is exhausted, the doubling of the hash is performed.
+.PP 
+\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIADD\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR }
+.PP 
+\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIDEL\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR }
+.PP 
+\fITEST\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR }
+.PP 
+Optional \fBcreate\fR options:
+.TP 
+\fBfamily\fR { \fBinet\fR|\fBinet6\fR }
+The protocol family of the IP addresses to be stored in the set. The default is
+\fBinet\fR, i.e IPv4.
+.TP 
+\fBhashsize\fR \fIvalue\fR
+The initial hash size for the set, default is 1024. The hash size must be a power
+of two, the kernel automatically rounds up non power of two hash sizes to the first
+correct value.
+.TP 
+\fBmaxelem\fR \fIvalue\fR
+The maximal number of elements which can be stored in the set, default 65536.
+.PP 
+The \fBhash:ip,port,ip\fR type of sets require three \fBsrc\fR/\fBdst\fR parameters of
+the \fBset\fR match and \fBSET\fR target kernel modules.
+.PP 
+Examples:
+.IP 
+ipset create foo hash:ip,port,ip
+.IP 
+ipset add foo 192.168.1.1,80,10.0.0.1
+.IP 
+ipset test foo 192.168.1.1,80,10.0.0.1
+.SS hash:ip,port,net
+The \fBhash:ip,port,net\fR set type uses a hash to store IP address, port and
+IP network triples.
+In order to avoid clashes in the hash a limited number of chaining, and then
+if that is exhausted, the doubling of the hash is performed.
+.PP 
+\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIADD\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR[/\fIcidr\fR] }
+.PP 
+\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIDEL\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR[/\fIcidr\fR] }
+.PP 
+\fITEST\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR[/\fIcidr\fR] }
+.PP 
+Optional \fBcreate\fR options:
+.TP 
+\fBfamily\fR { \fBinet\fR|\fBinet6\fR }
+The protocol family of the IP addresses to be stored in the set. The default is
+\fBinet\fR, i.e IPv4.
+.TP 
+\fBhashsize\fR \fIvalue\fR
+The initial hash size for the set, default is 1024. The hash size must be a power
+of two, the kernel automatically rounds up non power of two hash sizes to the first
+correct value.
+.TP 
+\fBmaxelem\fR \fIvalue\fR
+The maximal number of elements which can be stored in the set, default 65536.
+.PP 
+When adding/deleting/testing entries, if the cidr parameter is not specified,
+then the host cidr value is assumed.
+.PP 
+From the \fBset\fR netfilter match point of view a triple will be in a \fBhash:ip,port,net\fR type of set (when the first IP and the port match)
+if the second IP belongs to any of the netblocks added to the set.
+The  matching  always  start  from  the smallest  size  of netblock (most specific
+cidr) to the largest ones (least specific cidr).  When  adding/deleting triples
+to the set by the \fBSET\fR netfilter target, it  will  be
+added/deleted by the most specific cidr which can be found in  the
+set, or by the host cidr value if the set is empty.
+.PP 
+The lookup time grows linearly with the number of the different \fIcidr\fR
+values added to the set. 
+.PP 
+The \fBhash:ip,port,net\fR type of sets require three \fBsrc\fR/\fBdst\fR parameters of
+the \fBset\fR match and \fBSET\fR target kernel modules.
+.PP 
+Examples:
+.IP 
+ipset create foo hash:ip,port,net
+.IP 
+ipset add foo 192.168.1,80,10.0.0/24
+.IP 
+ipset add foo 192.168.2,25,10.1.0.0/16
+.IP 
+ipset test foo 192.168.1,80.10.0.0/24
+.SS list:set
+The \fBlist:set\fR type uses a simple list in which you can store
+sets.
+.PP 
+\fICREATE\-OPTIONS\fR := [ \fBsize\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIADD\-ENTRY\fR := \fIsetname\fR [ \fBbefore\fR|\fBafter\fR \fIsetname\fR ]
+.PP 
+\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
+.PP 
+\fIDEL\-ENTRY\fR := \fIsetname\fR [ \fBbefore\fR|\fBafter\fR \fIsetname\fR ]
+.PP 
+\fITEST\-ENTRY\fR := \fIsetname\fR [ \fBbefore\fR|\fBafter\fR \fIsetname\fR ]
+.PP 
+Optional \fBcreate\fR options:
+.TP 
+\fBsize\fR \fIvalue\fR
+The size of the list, the default is 8.
+.PP 
+By the \fBipset\fR commad you  can add, delete and test sets in a
+\fBlist:set\fR type of set.
+.PP 
+By the \fBset\fR match or \fBSET\fR target of netfiler
+you can test, add or delete entries in the sets added to the \fBlist:set\fR
+type of set. The match will try to find a matching entry in the sets and 
+the target will try to add an entry to the first set to which it can be added.
+The number of src,dst options of the match and target are important: sets which
+eats more src,dst parameters than specified are skipped, while sets with equal
+or less parameters are checked, elements added. For example if \fIa\fR and
+\fIb\fR are \fBlist:set\fR type of sets then in the command
+.IP 
+iptables \-m set \-\-match\-set a src,dst \-j SET \-\-add\-set b src,dst
+.PP 
+the match and target will skip any set in \fIa\fR and \fIb\fR
+which stores data triples, but will check all sets with single or double
+data storage in \fIa\fR
 set and add src to the first single or src,dst to the first double 
-data storage set in
-\fIb\fP.
-.P
+data storage set in \fIb\fR.
+.PP 
 You can imagine a setlist type of set as an ordered union of
 the set elements. 
-.SH GENERAL RESTRICTIONS
-Setnames starting with colon (:) cannot be defined. Zero valued set 
-entries cannot be used with hash type of sets.
-.SH COMMENTS
+.SH "GENERAL RESTRICTIONS"
+Zero valued set entries cannot be used with hash methods.
+.SH "COMMENTS"
 If you want to store same size subnets from a given network
-(say /24 blocks from a /8 network), use the ipmap set type.
+(say /24 blocks from a /8 network), use the \fBbitmap:ip\fR set type.
 If you want to store random same size networks (say random /24 blocks), 
-use the iphash set type. If you have got random size of netblocks, 
-use nethash.
-.P
-Old separator tokens (':' and '%") are still accepted.
-.P
-Binding support is removed.
-.SH DIAGNOSTICS
+use the \fBhash:ip\fR set type. If you have got random size of netblocks, 
+use \fBhash:net\fR.
+.PP 
+Backward compatibility is maintained and old \fBipset\fR syntax is still supported.
+.PP 
+The \fBiptree\fR and \fBiptreemap\fR set types are removed: if you refer to them,
+they are automatically replaced by \fBhash:ip\fR type of sets.
+.SH "DIAGNOSTICS"
 Various error messages are printed to standard error.  The exit code
-is 0 for correct functioning.  Errors which appear to be caused by
-invalid or abused command line parameters cause an exit code of 2, and
-other errors cause an exit code of 1.
-.SH BUGS
-Bugs? No, just funny features. :-)
+is 0 for correct functioning.
+.SH "BUGS"
+Bugs? No, just funny features. :\-)
 OK, just kidding...
-.SH SEE ALSO
-.BR iptables (8),
-.SH AUTHORS
+.SH "SEE ALSO"
+\fBiptables\fR(8),
+\fBip6tables\fR(8)
+.SH "AUTHORS"
 Jozsef Kadlecsik wrote ipset, which is based on ippool by
 Joakim Axelsson, Patrick Schaaf and Martin Josefsson.
-.P
+.br 
 Sven Wegener wrote the iptreemap type.
-.SH LAST REMARK
-.BR "I stand on the shoulders of giants."
+.SH "LAST REMARK"
+\fBI stand on the shoulders of giants.\fR
index d29042df6c62c269a74fb67ff7e42f4b898e5151..69fcd09602d3de0f542db3b60b3f9bb86ef5e7cf 100644 (file)
 
 #include <config.h>
 
+#include <libipset/debug.h>            /* D() */
 #include <libipset/parse.h>            /* ipset_parse_* */
 #include <libipset/session.h>          /* ipset_session_* */
 #include <libipset/types.h>            /* struct ipset_type */
 #include <libipset/ui.h>               /* core options, commands */
-#include <libipset/utils.h>            /* ipset_name_match */
+#include <libipset/utils.h>            /* STREQ */
 
 static char program_name[] = PACKAGE;
 static char program_version[] = PACKAGE_VERSION;
@@ -31,6 +32,18 @@ static char cmdline[1024];
 static char *newargv[255];
 static int newargc = 0;
 
+/* The known set types: (typename, revision, family) is unique */
+extern struct ipset_type ipset_bitmap_ip0;
+extern struct ipset_type ipset_bitmap_ipmac0;
+extern struct ipset_type ipset_bitmap_port0;
+extern struct ipset_type ipset_hash_ip0;
+extern struct ipset_type ipset_hash_net0;
+extern struct ipset_type ipset_hash_ipport0;
+extern struct ipset_type ipset_hash_ipportip0;
+extern struct ipset_type ipset_hash_ipportnet0;
+extern struct ipset_type ipset_tree_ip0;
+extern struct ipset_type ipset_list_set0;
+
 enum exittype {
        NO_PROBLEM = 0,
        OTHER_PROBLEM,
@@ -38,7 +51,7 @@ enum exittype {
        VERSION_PROBLEM,
 };
 
-static void __attribute__((format(printf,2,3)))
+static int __attribute__((format(printf,2,3)))
 exit_error(int status, const char *msg, ...)
 {
        bool quiet = !interactive
@@ -52,7 +65,8 @@ exit_error(int status, const char *msg, ...)
                va_start(args, msg);
                vfprintf(stderr, msg, args);
                va_end(args);
-               fprintf(stderr, "\n");
+               if (msg[strlen(msg) - 1] != '\n')
+                       fprintf(stderr, "\n");
 
                if (status == PARAMETER_PROBLEM)
                        fprintf(stderr,
@@ -63,7 +77,7 @@ exit_error(int status, const char *msg, ...)
        if (status && interactive) {
                if (session)
                        ipset_session_report_reset(session);
-               return;
+               return -1;
        }
 
        if (session)
@@ -71,6 +85,8 @@ exit_error(int status, const char *msg, ...)
 
        D("status: %u", status);
        exit(status);
+       /* Unreached */
+       return -1;
 }
 
 static int
@@ -81,8 +97,8 @@ handle_error(void)
                fprintf(stderr, "Warning: %s\n",
                        ipset_session_warning(session));
        if (ipset_session_error(session))
-               exit_error(OTHER_PROBLEM, "%s",
-                          ipset_session_error(session));
+               return exit_error(OTHER_PROBLEM, "%s",
+                                 ipset_session_error(session));
 
        if (!interactive) {
                ipset_session_fini(session);
@@ -96,19 +112,15 @@ handle_error(void)
 static void
 help(void)
 {
-       enum ipset_cmd cmd;
+       const struct ipset_commands *c;
        const struct ipset_envopts *opt = ipset_envopts;
        
        printf("%s v%s\n\n"
               "Usage: %s [options] COMMAND\n\nCommands:\n",
               program_name, program_version, program_name);
 
-       for (cmd = IPSET_CMD_NONE + 1; cmd < IPSET_CMD_MAX; cmd++) {
-               if (!ipset_commands[cmd-1].name[0])
-                       continue;
-               printf("%s %s\n",
-                      ipset_commands[cmd-1].name[0],
-                      ipset_commands[cmd-1].help);
+       for (c = ipset_commands; c->cmd; c++) {
+               printf("%s %s\n", c->name[0], c->help);
        }
        printf("\nOptions:\n");
        
@@ -136,9 +148,11 @@ build_argv(char *buffer)
        while ((ptr = strtok(NULL, " \t\n")) != NULL) {
                if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *)))
                        newargv[newargc++] = ptr;
-               else
+               else {
                        exit_error(PARAMETER_PROBLEM,
                                   "Line is too long to parse.");
+                       return;
+               }
        }
 }
 
@@ -188,57 +202,61 @@ restore(char *argv0)
 }
 
 static int
-call_parser(int argc, char *argv[],  const struct ipset_arg *args)
+call_parser(int argc, char *argv[], const struct ipset_arg *args)
 {
        int i = 1, ret = 0;
        const struct ipset_arg *arg;
+       const char *optstr;
        
-       /* Currently CREATE and ADD may have got additional arguments */
+       /* Currently CREATE and ADT may have got additional arguments */
        if (!args)
                goto done;
        for (arg = args; arg->opt; arg++) {
                for (i = 1; i < argc; ) {
-                       D("argc: %u, i: %u", argc, i);
-                       if (!(ipset_name_match(argv[i], arg->name))) {
+                       D("argc: %u, i: %u: %s vs %s", argc, i, argv[i], arg->name[0]);
+                       if (!(ipset_match_option(argv[i], arg->name))) {
                                i++;
                                continue;
                        }
+                       optstr = argv[i];
                        /* Shift off matched option */
                        D("match %s", arg->name[0]);
                        ipset_shift_argv(&argc, argv, i);
                        D("argc: %u, i: %u", argc, i);
                        switch (arg->has_arg) {
                        case IPSET_MANDATORY_ARG:
-                               if (i + 1 > argc) {
-                                       exit_error(PARAMETER_PROBLEM,
-                                                  "Missing mandatory argument of option `%s'",
-                                                  arg->name[0]);
-                                       return 1;
-                               }
+                               if (i + 1 > argc)
+                                       return exit_error(PARAMETER_PROBLEM,
+                                               "Missing mandatory argument of option `%s'",
+                                               arg->name[0]);
                                /* Fall through */
                        case IPSET_OPTIONAL_ARG:
                                if (i + 1 <= argc) {
-                                       ret = arg->parse(session, arg->opt,
-                                                        argv[i]);
+                                       ret = ipset_call_parser(session,
+                                                       arg->parse,
+                                                       optstr, arg->opt,
+                                                       argv[i]);
                                        if (ret < 0)
                                                return ret;
                                        ipset_shift_argv(&argc, argv, i);
+                                       break;
                                }
-                               break;
+                               /* Fall through */
                        default:
-                               ret = ipset_data_set(ipset_session_data(session),
-                                                    arg->opt, arg->name[0]);
+                               ret = ipset_call_parser(session,
+                                                       arg->parse,
+                                                       optstr, arg->opt,
+                                                       optstr);
                                if (ret < 0)
                                        return ret;
                        }
                }
        }
 done:
-       if (i < argc) {
-               exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'",
-                          argv[i]);
-               return 1;
-       }
+       if (i < argc)
+               return exit_error(PARAMETER_PROBLEM,
+                                 "Unknown argument: `%s'",
+                                 argv[i]);
        return ret;
 }
 
@@ -256,12 +274,20 @@ check_mandatory(const struct ipset_type *type, int cmd)
        mandatory &= ~flags;
        if (!mandatory)
                return;
+       if (!arg) {
+               exit_error(OTHER_PROBLEM,
+                       "There are missing mandatory flags but can't check them. "
+                       "It's a bug, please report the problem.");
+               return;
+       }
 
        for (; arg->opt; arg++)
-               if (mandatory & IPSET_FLAG(arg->opt))
+               if (mandatory & IPSET_FLAG(arg->opt)) {
                        exit_error(PARAMETER_PROBLEM,
                                   "Mandatory option `%s' is missing",
                                   arg->name[0]);
+                       return;
+               }
 }
 
 static const struct ipset_type *
@@ -270,7 +296,7 @@ type_find(const char *name)
        const struct ipset_type *t = ipset_types();
        
        while (t) {
-               if (STREQ(t->name, name) || STREQ(t->alias, name))
+               if (ipset_match_typename(name, t))
                        return t;
                t = t->next;
        }
@@ -299,7 +325,7 @@ parse_commandline(int argc, char *argv[])
 {
        int ret = 0;
        enum ipset_cmd cmd = IPSET_CMD_NONE;
-       int i = 0, j;
+       int i;
        char *arg0 = NULL, *arg1 = NULL, *c;
        const struct ipset_envopts *opt;
        const struct ipset_commands *command;
@@ -309,16 +335,16 @@ parse_commandline(int argc, char *argv[])
        if (session == NULL) {
                session = ipset_session_init(printf);
                if (session == NULL)
-                       exit_error(OTHER_PROBLEM,
-                                  "Cannot initialize ipset session, aborting.");
+                       return exit_error(OTHER_PROBLEM,
+                               "Cannot initialize ipset session, aborting.");
        }
 
        /* Commandline parsing, somewhat similar to that of 'ip' */
 
        /* First: parse core options */
-       for (opt = ipset_envopts; opt->flag ; opt++) {
+       for (opt = ipset_envopts; opt->flag; opt++) {
                for (i = 1; i < argc; ) {
-                       if (!ipset_name_match(argv[i], opt->name)) {
+                       if (!ipset_match_envopt(argv[i], opt->name)) {
                                i++;
                                continue;
                        }
@@ -327,9 +353,9 @@ parse_commandline(int argc, char *argv[])
                        switch (opt->has_arg) {
                        case IPSET_MANDATORY_ARG:
                                if (i + 1 > argc)
-                                       exit_error(PARAMETER_PROBLEM,
-                                                  "Missing mandatory argument to option %s",
-                                                  opt->name[0]);
+                                       return exit_error(PARAMETER_PROBLEM,
+                                               "Missing mandatory argument to option %s",
+                                               opt->name[0]);
                                /* Fall through */
                        case IPSET_OPTIONAL_ARG:
                                if (i + 1 <= argc) {
@@ -340,53 +366,49 @@ parse_commandline(int argc, char *argv[])
                                        ipset_shift_argv(&argc, argv, i);
                                }
                                break;
-                       default:
-                               ret = opt->parse(session, opt->flag, argv[i]);
+                       case IPSET_NO_ARG:
+                               ret = opt->parse(session, opt->flag,
+                                                opt->name[0]);
                                if (ret < 0)
                                        return handle_error();
                                break;
+                       default:
+                               break;
                        }
                }
        }
 
        /* Second: parse command */
-       for (j = IPSET_CMD_NONE + 1; j < IPSET_CMD_MAX; j++) {
-               command = &ipset_commands[j - 1];
-               if (!command->name[0])
-                       continue;
+       for (command = ipset_commands;
+            command->cmd && cmd == IPSET_CMD_NONE;
+            command++) {
                for (i = 1; i < argc; ) {
-                       if (!ipset_name_match(argv[i], command->name)) {
+                       if (!ipset_match_cmd(argv[1], command->name)) {
                                i++;
                                continue;
                        }
-                       if (cmd != IPSET_CMD_NONE)
-                               exit_error(PARAMETER_PROBLEM,
-                                          "Commands `%s' and `%s'"
-                                          "cannot be specified together.",
-                                          ipset_commands[cmd - 1].name[0],
-                                          command->name[0]);
                        if (restore_line != 0
-                           && (j == IPSET_CMD_RESTORE
-                               || j == IPSET_CMD_VERSION
-                               || j == IPSET_CMD_HELP))
-                               exit_error(PARAMETER_PROBLEM,
-                                          "Command `%s' is invalid in restore mode.",
-                                          command->name[0]);
-                       if (interactive && j == IPSET_CMD_RESTORE) {
-                               printf("Restore command ignored in interactive mode\n");
+                           && (command->cmd == IPSET_CMD_RESTORE
+                               || command->cmd == IPSET_CMD_VERSION
+                               || command->cmd == IPSET_CMD_HELP))
+                               return exit_error(PARAMETER_PROBLEM,
+                                       "Command `%s' is invalid in restore mode.",
+                                       command->name[0]);
+                               if (interactive && command->cmd == IPSET_CMD_RESTORE) {
+                                       printf("Restore command ignored in interactive mode\n");
                                return 0;
                        }
 
                        /* Shift off matched command arg */
                        ipset_shift_argv(&argc, argv, i);
-                       cmd = j;
+                       cmd = command->cmd;
                        switch (command->has_arg) {
                        case IPSET_MANDATORY_ARG:
                        case IPSET_MANDATORY_ARG2:
                                if (i + 1 > argc)
-                                       exit_error(PARAMETER_PROBLEM,
-                                                  "Missing mandatory argument to command %s",
-                                                  command->name[0]);
+                                       return exit_error(PARAMETER_PROBLEM,
+                                               "Missing mandatory argument to command %s",
+                                               command->name[0]);
                                /* Fall through */
                        case IPSET_OPTIONAL_ARG:
                                arg0 = argv[i];
@@ -399,13 +421,14 @@ parse_commandline(int argc, char *argv[])
                        }
                        if (command->has_arg == IPSET_MANDATORY_ARG2) {
                                if (i + 1 > argc)
-                                       exit_error(PARAMETER_PROBLEM,
-                                                  "Missing second mandatory argument to command %s",
-                                                  command->name[0]);
+                                       return exit_error(PARAMETER_PROBLEM,
+                                               "Missing second mandatory argument to command %s",
+                                               command->name[0]);
                                arg1 = argv[i];
                                /* Shift off second arg */
                                ipset_shift_argv(&argc, argv, i);
                        }
+                       break;
                }
        }
 
@@ -433,14 +456,14 @@ parse_commandline(int argc, char *argv[])
                                parse_commandline(newargc, newargv);
                                printf("%s> ", program_name);
                        }
-                       exit_error(NO_PROBLEM, NULL);
+                       return exit_error(NO_PROBLEM, NULL);
                }
-               exit_error(PARAMETER_PROBLEM, "No command specified.");
+               return exit_error(PARAMETER_PROBLEM, "No command specified.");
        case IPSET_CMD_VERSION:
                printf("%s v%s.\n", program_name, program_version);
                if (interactive)
                        return 0;
-               exit_error(NO_PROBLEM, NULL);
+               return exit_error(NO_PROBLEM, NULL);
        case IPSET_CMD_HELP:
                help();
 
@@ -450,8 +473,8 @@ parse_commandline(int argc, char *argv[])
                                /* Type-specific help, without kernel checking */
                                type = type_find(arg0);
                                if (!type)
-                                       exit_error(PARAMETER_PROBLEM,
-                                                  "Unknown settype: `%s'", arg0);
+                                       return exit_error(PARAMETER_PROBLEM,
+                                               "Unknown settype: `%s'", arg0);
                                printf("\n%s type specific options:\n\n%s",
                                       type->name, type->usage);
                                if (type->family == AF_UNSPEC)
@@ -475,7 +498,9 @@ parse_commandline(int argc, char *argv[])
                }
                if (interactive)
                        return 0;
-               exit_error(NO_PROBLEM, NULL);
+               return exit_error(NO_PROBLEM, NULL);
+       case IPSET_CMD_QUIT:
+               return exit_error(NO_PROBLEM, NULL);
        default:
                break;
        }
@@ -525,7 +550,7 @@ parse_commandline(int argc, char *argv[])
                ret = ipset_parse_setname(session, IPSET_SETNAME, arg0);
                if (ret < 0)
                        return handle_error();
-               ret = ipset_parse_name(session, IPSET_OPT_SETNAME2, arg1);
+               ret = ipset_parse_setname(session, IPSET_OPT_SETNAME2, arg1);
                if (ret < 0)
                        return handle_error();
                break;
@@ -582,5 +607,16 @@ parse_commandline(int argc, char *argv[])
 int
 main(int argc, char *argv[])
 {
+       /* Register types */
+       ipset_type_add(&ipset_bitmap_ip0);
+       ipset_type_add(&ipset_bitmap_ipmac0);
+       ipset_type_add(&ipset_bitmap_port0);
+       ipset_type_add(&ipset_hash_ip0);
+       ipset_type_add(&ipset_hash_net0);
+       ipset_type_add(&ipset_hash_ipport0);
+       ipset_type_add(&ipset_hash_ipportip0);
+       ipset_type_add(&ipset_hash_ipportnet0);
+       ipset_type_add(&ipset_list_set0);
+
        return parse_commandline(argc, argv);
 }
index 471cc969cce91618aeee18953c35a266bd71a945..e28432b2f8a4fa162462ed69580c7fd4f8738e8c 100644 (file)
 
 /* Parse commandline arguments */
 static const struct ipset_arg bitmap_ip_create_args[] = {
-       { .name = { "range", "--range", NULL },
+       { .name = { "range", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
          .parse = ipset_parse_netrange,        .print = ipset_print_ip,
        },
-       { .name = { "netmask", "--netmask", NULL },
+       { .name = { "netmask", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NETMASK,
          .parse = ipset_parse_netmask,         .print = ipset_print_number,
        },
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
        /* Backward compatibility */
-       { .name = { "--from", NULL },
+       { .name = { "from", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
          .parse = ipset_parse_single_ip,
        },
-       { .name = { "--to", NULL },
+       { .name = { "to", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
          .parse = ipset_parse_single_ip,
        },
-       { .name = { "--network", NULL },
+       { .name = { "network", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
          .parse = ipset_parse_net,
        },
@@ -40,7 +40,7 @@ static const struct ipset_arg bitmap_ip_create_args[] = {
 }; 
 
 static const struct ipset_arg bitmap_ip_add_args[] = {
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
@@ -56,7 +56,7 @@ static const char bitmap_ip_usage[] =
 
 struct ipset_type ipset_bitmap_ip0 = {
        .name = "bitmap:ip",
-       .alias = "ipmap",
+       .alias = { "ipmap", NULL },
        .revision = 0,
        .family = AF_INET,
        .dimension = IPSET_DIM_ONE,
index 4985fc48ac23c2505d5f19cf40335baadcdd8d83..382ebb5036f2a56ba456577c86899e52b3dbd49d 100644 (file)
 
 /* Parse commandline arguments */
 static const struct ipset_arg bitmap_ipmac_create_args[] = {
-       { .name = { "range", "--range", NULL },
+       { .name = { "range", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
          .parse = ipset_parse_netrange,        .print = ipset_print_ip,
        },
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
        /* Backward compatibility */
-       { .name = { "--from", NULL },
+       { .name = { "from", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
          .parse = ipset_parse_single_ip,
        },
-       { .name = { "--to", NULL },
+       { .name = { "to", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
          .parse = ipset_parse_single_ip,
        },
-       { .name = { "--network", NULL },
+       { .name = { "network", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
          .parse = ipset_parse_net,
        },
@@ -36,7 +36,7 @@ static const struct ipset_arg bitmap_ipmac_create_args[] = {
 }; 
 
 static const struct ipset_arg bitmap_ipmac_add_args[] = {
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
@@ -52,7 +52,7 @@ static const char bitmap_ipmac_usage[] =
 
 struct ipset_type ipset_bitmap_ipmac0 = {
        .name = "bitmap:ip,mac",
-       .alias = "macipmap",
+       .alias = { "macipmap", NULL },
        .revision = 0,
        .family = AF_INET,
        .dimension = IPSET_DIM_TWO,
index 11566ce5e3e432f54a0d9926b170c54e60d56eb4..787189120a59f0a17898e45082c185bd73a7dce3 100644 (file)
 
 /* Parse commandline arguments */
 static const struct ipset_arg bitmap_port_create_args[] = {
-       { .name = { "range", "--range", NULL },
+       { .name = { "range", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT,
          .parse = ipset_parse_port,            .print = ipset_print_port,
        },
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
        /* Backward compatibility */
-       { .name = { "--from", NULL },
+       { .name = { "from", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT,
          .parse = ipset_parse_single_port,
        },
-       { .name = { "--to", NULL },
+       { .name = { "to", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT_TO,
          .parse = ipset_parse_single_port,
        },
@@ -32,7 +32,7 @@ static const struct ipset_arg bitmap_port_create_args[] = {
 }; 
 
 static const struct ipset_arg bitmap_port_add_args[] = {
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
@@ -48,7 +48,7 @@ static const char bitmap_port_usage[] =
 
 struct ipset_type ipset_bitmap_port0 = {
        .name = "bitmap:port",
-       .alias = "portmap",
+       .alias = { "portmap", NULL },
        .revision = 0,
        .family = AF_UNSPEC,
        .dimension = IPSET_DIM_ONE,
index 212cb2224f184694d8569165c74ada2ebee3de7d..6609eea00ad44b5c22f518af1c15c129c2b32afb 100644 (file)
 
 /* Parse commandline arguments */
 static const struct ipset_arg hash_ip_create_args[] = {
-       { .name = { "hashsize", "--hashsize", NULL },
+       { .name = { "family", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,          .print = ipset_print_family,
+       },
+       /* Alias: family inet */
+       { .name = { "-4", NULL },
+         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,
+       },
+       /* Alias: family inet6 */
+       { .name = { "-6", NULL },
+         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,
+       },
+       { .name = { "hashsize", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_HASHSIZE,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
-       { .name = { "maxelem", "--maxleme", NULL },
+       { .name = { "maxelem", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
-       { .name = { "probes", "--probes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PROBES,
-         .parse = ipset_parse_uint8,           .print = ipset_print_number,
-       },
-       { .name = { "resize", "--resize", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_RESIZE,
-         .parse = ipset_parse_uint8,           .print = ipset_print_number,
-       },
-       { .name = { "netmask", "--netmask", NULL },
+       { .name = { "netmask", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NETMASK,
          .parse = ipset_parse_netmask,         .print = ipset_print_number,
        },
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
+       /* Ignored options: backward compatibilty */
+       { .name = { "probes", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PROBES,
+         .parse = ipset_parse_ignored,         .print = ipset_print_number,
+       },
+       { .name = { "resize", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_RESIZE,
+         .parse = ipset_parse_ignored,         .print = ipset_print_number,
+       },
+       { .name = { "gc", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_GC,
+         .parse = ipset_parse_ignored,         .print = ipset_print_number,
+       },
        { },
 };
 
 static const struct ipset_arg hash_ip_add_args[] = {
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
@@ -48,8 +67,8 @@ static const struct ipset_arg hash_ip_add_args[] = {
 
 static const char hash_ip_usage[] =
 "create SETNAME hash:ip\n"
+"              [family inet|inet6]\n"
 "               [hashsize VALUE] [maxelem VALUE]\n"
-"               [probes VALUE] [resize VALUE]\n"
 "               [netmask CIDR] [timeout VALUE]\n"
 "add    SETNAME IP|IP/CIDR|FROM-TO [timeout VALUE]\n"
 "del    SETNAME IP|IP/CIDR|FROM-TO\n"
@@ -57,7 +76,7 @@ static const char hash_ip_usage[] =
 
 struct ipset_type ipset_hash_ip0 = {
        .name = "hash:ip",
-       .alias = "iphash",
+       .alias = { "iphash", "iptree", "iptreemap", NULL },
        .revision = 0,
        .family = AF_INET46,
        .dimension = IPSET_DIM_ONE,
@@ -68,6 +87,7 @@ struct ipset_type ipset_hash_ip0 = {
                        .opt = IPSET_OPT_IP
                },
        },
+       .compat_parse_elem = ipset_parse_iptimeout,
        .args = {
                [IPSET_CREATE] = hash_ip_create_args,
                [IPSET_ADD] = hash_ip_add_args,
@@ -81,8 +101,6 @@ struct ipset_type ipset_hash_ip0 = {
        .full = {
                [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
                        | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_PROBES)
-                       | IPSET_FLAG(IPSET_OPT_RESIZE)
                        | IPSET_FLAG(IPSET_OPT_NETMASK)
                        | IPSET_FLAG(IPSET_OPT_TIMEOUT),
                [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
index a8cc7ad92d121e296acd01f57d2a8a1ed4baa262..4a9b8cf19cf9f980a6bba60124426064b09b1f89 100644 (file)
 
 /* Parse commandline arguments */
 static const struct ipset_arg hash_ipport_create_args[] = {
-       { .name = { "range", "--range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_netrange,        .print = ipset_print_ip,
+       { .name = { "family", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,          .print = ipset_print_family,
+       },
+       /* Alias: family inet */
+       { .name = { "-4", NULL },
+         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,
+       },
+       /* Alias: family inet6 */
+       { .name = { "-6", NULL },
+         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,
        },
-       { .name = { "hashsize", "--hashsize", NULL },
+       { .name = { "hashsize", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_HASHSIZE,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
-       { .name = { "maxelem", "--maxleme", NULL },
+       { .name = { "maxelem", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
-       { .name = { "probes", "--probes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PROBES,
-         .parse = ipset_parse_uint8,           .print = ipset_print_number,
-       },
-       { .name = { "resize", "--resize", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_RESIZE,
-         .parse = ipset_parse_uint8,           .print = ipset_print_number,
-       },
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
        /* Backward compatibility */
-       { .name = { "--from", NULL },
+       { .name = { "probes", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PROBES,
+         .parse = ipset_parse_ignored,         .print = ipset_print_number,
+       },
+       { .name = { "resize", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_RESIZE,
+         .parse = ipset_parse_ignored,         .print = ipset_print_number,
+       },
+       { .name = { "from", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_single_ip,
+         .parse = ipset_parse_ignored,
        },
-       { .name = { "--to", NULL },
+       { .name = { "to", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_single_ip,
+         .parse = ipset_parse_ignored,
        },
-       { .name = { "--network", NULL },
+       { .name = { "network", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_net,
+         .parse = ipset_parse_ignored,
        },
        { },
 }; 
 
 static const struct ipset_arg hash_ipport_add_args[] = {
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
@@ -60,10 +70,9 @@ static const struct ipset_arg hash_ipport_add_args[] = {
 }; 
 
 static const char hash_ipport_usage[] =
-"create SETNAME hash:ip,port range IP/CIDR|FROM-TO\n"
+"create SETNAME hash:ip,port\n"
 "              [family inet|inet6]\n"
 "               [hashsize VALUE] [maxelem VALUE]\n"
-"               [probes VALUE] [resize VALUE]\n"
 "               [timeout VALUE]\n"
 "add    SETNAME IP,PORT [timeout VALUE]\n"
 "del    SETNAME IP,PORT\n"
@@ -71,7 +80,7 @@ static const char hash_ipport_usage[] =
 
 struct ipset_type ipset_hash_ipport0 = {
        .name = "hash:ip,port",
-       .alias = "ipporthash",
+       .alias = { "ipporthash", NULL },
        .revision = 0,
        .family = AF_INET46,
        .dimension = IPSET_DIM_TWO,
@@ -92,8 +101,7 @@ struct ipset_type ipset_hash_ipport0 = {
                [IPSET_ADD] = hash_ipport_add_args,
        },
        .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
+               [IPSET_CREATE] = 0,
                [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
                        | IPSET_FLAG(IPSET_OPT_PORT),
                [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
@@ -102,12 +110,8 @@ struct ipset_type ipset_hash_ipport0 = {
                        | IPSET_FLAG(IPSET_OPT_PORT),
        },
        .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_HASHSIZE)
+               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
                        | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_PROBES)
-                       | IPSET_FLAG(IPSET_OPT_RESIZE)
                        | IPSET_FLAG(IPSET_OPT_TIMEOUT),
                [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
                        | IPSET_FLAG(IPSET_OPT_PORT)
index 71ed3c523396ae5d37b39905514e5d42cb98f8a3..299e36229e33e383bccc5891dfc63444da9420d2 100644 (file)
 
 /* Parse commandline arguments */
 static const struct ipset_arg hash_ipportip_create_args[] = {
-       { .name = { "range", "--range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_netrange,        .print = ipset_print_ip,
+       { .name = { "family", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,          .print = ipset_print_family,
+       },
+       /* Alias: family inet */
+       { .name = { "-4", NULL },
+         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,
+       },
+       /* Alias: family inet6 */
+       { .name = { "-6", NULL },
+         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,
        },
-       { .name = { "hashsize", "--hashsize", NULL },
+       { .name = { "hashsize", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_HASHSIZE,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
-       { .name = { "maxelem", "--maxleme", NULL },
+       { .name = { "maxelem", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
-       { .name = { "probes", "--probes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PROBES,
-         .parse = ipset_parse_uint8,           .print = ipset_print_number,
-       },
-       { .name = { "resize", "--resize", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_RESIZE,
-         .parse = ipset_parse_uint8,           .print = ipset_print_number,
-       },
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
        /* Backward compatibility */
-       { .name = { "--from", NULL },
+       { .name = { "probes", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PROBES,
+         .parse = ipset_parse_ignored,         .print = ipset_print_number,
+       },
+       { .name = { "resize", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_RESIZE,
+         .parse = ipset_parse_ignored,         .print = ipset_print_number,
+       },
+       { .name = { "from", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_single_ip,
+         .parse = ipset_parse_ignored,
        },
-       { .name = { "--to", NULL },
+       { .name = { "to", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_single_ip,
+         .parse = ipset_parse_ignored,
        },
-       { .name = { "--network", NULL },
+       { .name = { "network", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_net,
+         .parse = ipset_parse_ignored,
        },
        { },
 }; 
 
 static const struct ipset_arg hash_ipportip_add_args[] = {
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
@@ -60,10 +70,9 @@ static const struct ipset_arg hash_ipportip_add_args[] = {
 }; 
 
 static const char hash_ipportip_usage[] =
-"create SETNAME hash:ip,port,ip range IP/CIDR|FROM-TO\n"
+"create SETNAME hash:ip,port,ip\n"
 "              [family inet|inet6]\n"
 "               [hashsize VALUE] [maxelem VALUE]\n"
-"               [probes VALUE] [resize VALUE]\n"
 "               [timeout VALUE]\n"
 "add    SETNAME IP,PORT,IP [timeout VALUE]\n"
 "del    SETNAME IP,PORT,IP\n"
@@ -71,7 +80,7 @@ static const char hash_ipportip_usage[] =
 
 struct ipset_type ipset_hash_ipportip0 = {
        .name = "hash:ip,port,ip",
-       .alias = "ipportiphash",
+       .alias = { "ipportiphash", NULL },
        .revision = 0,
        .family = AF_INET46,
        .dimension = IPSET_DIM_THREE,
@@ -97,8 +106,7 @@ struct ipset_type ipset_hash_ipportip0 = {
                [IPSET_ADD] = hash_ipportip_add_args,
        },
        .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
+               [IPSET_CREATE] = 0,
                [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
                        | IPSET_FLAG(IPSET_OPT_PORT)
                        | IPSET_FLAG(IPSET_OPT_IP2),
@@ -110,12 +118,8 @@ struct ipset_type ipset_hash_ipportip0 = {
                        | IPSET_FLAG(IPSET_OPT_IP2),
        },
        .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_HASHSIZE)
+               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
                        | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_PROBES)
-                       | IPSET_FLAG(IPSET_OPT_RESIZE)
                        | IPSET_FLAG(IPSET_OPT_TIMEOUT),
                [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
                        | IPSET_FLAG(IPSET_OPT_PORT)
index 769304dec62463c820ee1dafcfab34eeefd74409..13a048740851c31a2930070a82bf93f85dd5f604 100644 (file)
 
 /* Parse commandline arguments */
 static const struct ipset_arg hash_ipportnet_create_args[] = {
-       { .name = { "range", "--range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_netrange,        .print = ipset_print_ip,
+       { .name = { "family", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,          .print = ipset_print_family,
+       },
+       /* Alias: family inet */
+       { .name = { "-4", NULL },
+         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,
+       },
+       /* Alias: family inet6 */
+       { .name = { "-6", NULL },
+         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,
        },
-       { .name = { "hashsize", "--hashsize", NULL },
+       { .name = { "hashsize", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_HASHSIZE,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
-       { .name = { "maxelem", "--maxleme", NULL },
+       { .name = { "maxelem", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
-       { .name = { "probes", "--probes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PROBES,
-         .parse = ipset_parse_uint8,           .print = ipset_print_number,
-       },
-       { .name = { "resize", "--resize", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_RESIZE,
-         .parse = ipset_parse_uint8,           .print = ipset_print_number,
-       },
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
        /* Backward compatibility */
-       { .name = { "--from", NULL },
+       { .name = { "probes", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PROBES,
+         .parse = ipset_parse_ignored,         .print = ipset_print_number,
+       },
+       { .name = { "resize", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_RESIZE,
+         .parse = ipset_parse_ignored,         .print = ipset_print_number,
+       },
+       { .name = { "from", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_single_ip,
+         .parse = ipset_parse_ignored,
        },
-       { .name = { "--to", NULL },
+       { .name = { "to", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_single_ip,
+         .parse = ipset_parse_ignored,
        },
-       { .name = { "--network", NULL },
+       { .name = { "network", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_net,
+         .parse = ipset_parse_ignored,
        },
        { },
 }; 
 
 static const struct ipset_arg hash_ipportnet_add_args[] = {
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
@@ -60,18 +70,17 @@ static const struct ipset_arg hash_ipportnet_add_args[] = {
 }; 
 
 static const char hash_ipportnet_usage[] =
-"create SETNAME hash:ip,port,net range IP/CIDR|FROM-TO\n"
+"create SETNAME hash:ip,port,net\n"
 "              [family inet|inet6]\n"
 "               [hashsize VALUE] [maxelem VALUE]\n"
-"               [probes VALUE] [resize VALUE]\n"
 "               [timeout VALUE]\n"
-"add    SETNAME IP,PORT,IP/CIDR [timeout VALUE]\n"
-"del    SETNAME IP,PORT,IP/CIDR\n"
-"test   SETNAME IP,PORT,IP/CIDR\n";
+"add    SETNAME IP,PORT,IP[/CIDR] [timeout VALUE]\n"
+"del    SETNAME IP,PORT,IP[/CIDR]\n"
+"test   SETNAME IP,PORT,IP[/CIDR]\n";
 
 struct ipset_type ipset_hash_ipportnet0 = {
        .name = "hash:ip,port,net",
-       .alias = "ipportnethash",
+       .alias = { "ipportnethash", NULL },
        .revision = 0,
        .family = AF_INET46,
        .dimension = IPSET_DIM_THREE,
@@ -87,7 +96,7 @@ struct ipset_type ipset_hash_ipportnet0 = {
                        .opt = IPSET_OPT_PORT
                },
                [IPSET_DIM_THREE] = { 
-                       .parse = ipset_parse_net,
+                       .parse = ipset_parse_ipnet,
                        .print = ipset_print_ip,
                        .opt = IPSET_OPT_IP2
                },
@@ -97,28 +106,20 @@ struct ipset_type ipset_hash_ipportnet0 = {
                [IPSET_ADD] = hash_ipportnet_add_args,
        },
        .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
+               [IPSET_CREATE] = 0,
                [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
                        | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       | IPSET_FLAG(IPSET_OPT_IP2),
                [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
                        | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       | IPSET_FLAG(IPSET_OPT_IP2),
                [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
                        | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       | IPSET_FLAG(IPSET_OPT_IP2),
        },
        .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_HASHSIZE)
+               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
                        | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_PROBES)
-                       | IPSET_FLAG(IPSET_OPT_RESIZE)
                        | IPSET_FLAG(IPSET_OPT_TIMEOUT),
                [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
                        | IPSET_FLAG(IPSET_OPT_PORT)
index 1d70900c89195b1313ebf012136467d05a63e337..c14652d25c4885b3f496fd5668656f9d59116157 100644 (file)
 
 /* Parse commandline arguments */
 static const struct ipset_arg hash_net_create_args[] = {
-       { .name = { "hashsize", "--hashsize", NULL },
+       { .name = { "family", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,          .print = ipset_print_family,
+       },
+       /* Alias: family inet */
+       { .name = { "-4", NULL },
+         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,
+       },
+       /* Alias: family inet6 */
+       { .name = { "-6", NULL },
+         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FAMILY,
+         .parse = ipset_parse_family,
+       },
+       { .name = { "hashsize", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_HASHSIZE,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
-       { .name = { "maxelem", "--maxleme", NULL },
+       { .name = { "maxelem", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
-       { .name = { "probes", "--probes", NULL },
+       { .name = { "timeout", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
+         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+       },
+       /* Ignored options: backward compatibilty */
+       { .name = { "probes", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PROBES,
-         .parse = ipset_parse_uint8,           .print = ipset_print_number,
+         .parse = ipset_parse_ignored,         .print = ipset_print_number,
        },
-       { .name = { "resize", "--resize", NULL },
+       { .name = { "resize", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_RESIZE,
-         .parse = ipset_parse_uint8,           .print = ipset_print_number,
-       },
-       { .name = { "timeout", "--timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_ignored,         .print = ipset_print_number,
        },
        { },
 }; 
 
 static const struct ipset_arg hash_net_add_args[] = {
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
@@ -46,21 +61,20 @@ static const char hash_net_usage[] =
 "create SETNAME hash:net\n"
 "              [family inet|inet6]\n"
 "               [hashsize VALUE] [maxelem VALUE]\n"
-"               [probes VALUE] [resize VALUE]\n"
 "               [timeout VALUE]\n"
-"add    SETNAME IP/CIDR [timeout VALUE]\n"
-"del    SETNAME IP/CIDR\n"
-"test   SETNAME IP/CIDR\n";
+"add    SETNAME IP[/CIDR] [timeout VALUE]\n"
+"del    SETNAME IP[/CIDR]\n"
+"test   SETNAME IP[/CIDR]\n";
 
 struct ipset_type ipset_hash_net0 = {
        .name = "hash:net",
-       .alias = "nethash",
+       .alias = { "nethash", NULL },
        .revision = 0,
        .family = AF_INET46,
        .dimension = IPSET_DIM_ONE,
        .elem = { 
                [IPSET_DIM_ONE] = { 
-                       .parse = ipset_parse_net,
+                       .parse = ipset_parse_ipnet,
                        .print = ipset_print_ip,
                        .opt = IPSET_OPT_IP
                },
@@ -71,18 +85,13 @@ struct ipset_type ipset_hash_net0 = {
        },
        .mandatory = {
                [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR),
+               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP),
+               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP),
+               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
        },
        .full = {
                [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
                        | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_PROBES)
-                       | IPSET_FLAG(IPSET_OPT_RESIZE)
                        | IPSET_FLAG(IPSET_OPT_TIMEOUT),
                [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
                        | IPSET_FLAG(IPSET_OPT_CIDR)
diff --git a/src/ipset_iptreemap.c b/src/ipset_iptreemap.c
deleted file mode 100644 (file)
index 22bdcb3..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/* Copyright 2007 Sven Wegener <sven.wegener@stealer.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <limits.h>                    /* UINT_MAX */
-#include <stdio.h>                     /* *printf */
-#include <string.h>                    /* mem* */
-
-#include "ipset.h"
-
-#include <linux/netfilter_ipv4/ip_set_iptreemap.h>
-
-#define OPT_CREATE_GC 0x1
-
-static void
-iptreemap_create_init(void *data)
-{
-       struct ip_set_req_iptreemap_create *mydata = data;
-
-       mydata->gc_interval = 0;
-}
-
-static int
-iptreemap_create_parse(int c, char *argv[] UNUSED, void *data,
-                      unsigned int *flags)
-{
-       struct ip_set_req_iptreemap_create *mydata = data;
-
-       switch (c) {
-               case 'g':
-                       string_to_number(optarg, 0, UINT_MAX, &mydata->gc_interval);
-
-                       *flags |= OPT_CREATE_GC;
-               break;
-               default:
-                       return 0;
-               break;
-       }
-
-       return 1;
-}
-
-static void
-iptreemap_create_final(void *data UNUSED, unsigned int flags UNUSED)
-{
-}
-
-static const struct option create_opts[] = {
-       {.name = "gc",  .has_arg = required_argument,   .val = 'g'},
-       {NULL},
-};
-
-static ip_set_ip_t
-iptreemap_adt_parser(int cmd UNUSED, const char *arg, void *data)
-{
-       struct ip_set_req_iptreemap *mydata = data;
-       ip_set_ip_t mask;
-
-       char *saved = ipset_strdup(arg);
-       char *ptr, *tmp = saved;
-
-       if (strchr(tmp, '/')) {
-               parse_ipandmask(tmp, &mydata->ip, &mask);
-               mydata->end = mydata->ip | ~mask;
-       } else {
-               if ((ptr = strchr(tmp, ':')) != NULL && ++warn_once == 1)
-                       fprintf(stderr, "Warning: please use '-' separator token between IP range.\n"
-                               "Next release won't support old separator token.\n");
-               ptr = strsep(&tmp, "-:");
-               parse_ip(ptr, &mydata->ip);
-
-               if (tmp) {
-                       parse_ip(tmp, &mydata->end);
-               } else {
-                       mydata->end = mydata->ip;
-               }
-       }
-
-       ipset_free(saved);
-
-       return 1;
-}
-
-static void
-iptreemap_initheader(struct set *set, const void *data)
-{
-       const struct ip_set_req_iptreemap_create *header = data;
-       struct ip_set_iptreemap *map = set->settype->header;
-
-       map->gc_interval = header->gc_interval;
-}
-
-static void
-iptreemap_printheader(struct set *set, unsigned int options UNUSED)
-{
-       struct ip_set_iptreemap *mysetdata = set->settype->header;
-
-       if (mysetdata->gc_interval)
-               printf(" gc: %u", mysetdata->gc_interval);
-
-       printf("\n");
-}
-
-static void
-iptreemap_printips_sorted(struct set *set UNUSED, void *data,
-                         u_int32_t len, unsigned int options, char dont_align)
-{
-       struct ip_set_req_iptreemap *req;
-       size_t offset = 0;
-
-       while (len >= offset + sizeof(struct ip_set_req_iptreemap)) {
-               req = data + offset;
-
-               printf("%s", ip_tostring(req->ip, options));
-               if (req->ip != req->end)
-                       printf("-%s", ip_tostring(req->end, options));
-               printf("\n");
-
-               offset += IPSET_VALIGN(sizeof(struct ip_set_req_iptreemap), dont_align);
-       }
-}
-
-static void
-iptreemap_saveheader(struct set *set, unsigned int options UNUSED)
-{
-       struct ip_set_iptreemap *mysetdata = set->settype->header;
-
-       printf("-N %s %s", set->name, set->settype->typename);
-
-       if (mysetdata->gc_interval)
-               printf(" --gc %u", mysetdata->gc_interval);
-
-       printf("\n");
-}
-
-static void
-iptreemap_saveips(struct set *set UNUSED, void *data,
-                 u_int32_t len, unsigned int options, char dont_align)
-{
-       struct ip_set_req_iptreemap *req;
-       size_t offset = 0;
-
-       while (len >= offset + sizeof(struct ip_set_req_iptreemap)) {
-               req = data + offset;
-
-               printf("-A %s %s", set->name, ip_tostring(req->ip, options));
-
-               if (req->ip != req->end)
-                       printf("-%s", ip_tostring(req->end, options));
-
-               printf("\n");
-
-               offset += IPSET_VALIGN(sizeof(struct ip_set_req_iptreemap), dont_align);
-       }
-}
-
-static void
-iptreemap_usage(void)
-{
-       printf(
-               "-N set iptreemap --gc interval\n"
-               "-A set IP\n"
-               "-D set IP\n"
-               "-T set IP\n"
-       );
-}
-
-static struct settype settype_iptreemap = {
-       .typename = SETTYPE_NAME,
-       .protocol_version = IP_SET_PROTOCOL_VERSION,
-
-       .create_size = sizeof(struct ip_set_req_iptreemap_create),
-       .create_init = iptreemap_create_init,
-       .create_parse = iptreemap_create_parse,
-       .create_final = iptreemap_create_final,
-       .create_opts = create_opts,
-
-       .adt_size = sizeof(struct ip_set_req_iptreemap),
-       .adt_parser = iptreemap_adt_parser,
-
-       .header_size = sizeof(struct ip_set_iptreemap),
-       .initheader = iptreemap_initheader,
-       .printheader = iptreemap_printheader,
-       .printips = iptreemap_printips_sorted,
-       .printips_sorted = iptreemap_printips_sorted,
-       .saveheader = iptreemap_saveheader,
-       .saveips = iptreemap_saveips,
-
-       .usage = iptreemap_usage,
-};
-
-CONSTRUCTOR(iptreemap)
-{
-       settype_register(&settype_iptreemap);
-}
index 11b2523c3c87bbaeb3f47a631ecf2223ae397062..76cf9b246118f6fa6d92926d2e394fada11e62a0 100644 (file)
 
 /* Parse commandline arguments */
 static const struct ipset_arg list_set_create_args[] = {
-       { .name = { "size", "--size", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_ip,
+       { .name = { "size", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SIZE,
+         .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
-       { .name = { "timeout", "--timeout", NULL },
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
        { },
 }; 
 
-static const struct ipset_arg list_set_add_args[] = {
-       { .name = { "timeout", "--timeout", NULL },
+static const struct ipset_arg list_set_adt_args[] = {
+       { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
          .parse = ipset_parse_uint32,          .print = ipset_print_number,
        },
+       { .name = { "before", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NAMEREF,
+         .parse = ipset_parse_before,
+       },
+       { .name = { "after", NULL },
+         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NAMEREF,
+         .parse = ipset_parse_after,
+       },
        { },
 }; 
 
 static const char list_set_usage[] =
 "create SETNAME list:set\n"
 "               [size VALUE] [timeout VALUE]\n"
-"add    SETNAME NAME[,before|after,NAME] [timeout VALUE]\n"
+"add    SETNAME NAME [before|after NAME] [timeout VALUE]\n"
 "del    SETNAME NAME\n"
 "test   SETNAME NAME\n";
 
 struct ipset_type ipset_list_set0 = {
        .name = "list:set",
-       .alias = "setlist",
+       .alias = { "setlist", NULL },
        .revision = 0,
        .family = AF_UNSPEC,
        .dimension = IPSET_DIM_ONE,
        .elem = { 
                [IPSET_DIM_ONE] = { 
-                       .parse = ipset_parse_name,
+                       .parse = ipset_parse_setname,
                        .print = ipset_print_name,
                        .opt = IPSET_OPT_NAME
                },
        },
+       .compat_parse_elem = ipset_parse_name_compat,
        .args = {
                [IPSET_CREATE] = list_set_create_args,
-               [IPSET_ADD] = list_set_add_args,
+               [IPSET_ADD] = list_set_adt_args,
+               [IPSET_DEL] = list_set_adt_args,
+               [IPSET_TEST] = list_set_adt_args,
        },
        .mandatory = {
                [IPSET_CREATE] = 0,
diff --git a/src/ipset_tree_ip.c b/src/ipset_tree_ip.c
deleted file mode 100644 (file)
index 7f7d842..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* Copyright 2007-2010 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.
- */
-#include <libipset/data.h>                     /* IPSET_OPT_* */
-#include <libipset/parse.h>                    /* parser functions */
-#include <libipset/print.h>                    /* printing functions */
-#include <libipset/types.h>                    /* prototypes */
-
-/* Parse commandline arguments */
-static const struct ipset_arg tree_ip_create_args[] = {
-       { .name = { "gc", "--gc", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_GC,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", "--timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { },
-}; 
-
-static const struct ipset_arg tree_ip_add_args[] = {
-       { .name = { "timeout", "--timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { },
-}; 
-
-static const char tree_ip_usage[] =
-"create SETNAME tree:ip\n"
-"               [gc VALUE] [timeout VALUE]\n"
-"add    SETNAME IP|IP/CIDR|FROM-TO [timeout VALUE]\n"
-"del    SETNAME IP|IP/CIDR|FROM-TO\n"
-"test   SETNAME IP\n";
-
-struct ipset_type ipset_tree_ip0 = {
-       .name = "tree:ip",
-       .alias = "iptree",
-       .revision = 0,
-       .family = AF_INET,
-       .dimension = IPSET_DIM_ONE,
-       .elem = { 
-               [IPSET_DIM_ONE] = { 
-                       .parse = ipset_parse_ip,
-                       .print = ipset_print_ip,
-                       .opt = IPSET_OPT_IP
-               },
-       },
-       .args = {
-               [IPSET_CREATE] = tree_ip_create_args,
-               [IPSET_ADD] = tree_ip_add_args,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_GC)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
-       },
-
-       .usage = tree_ip_usage,
-};
index bc01e61df3e5f92b044061801a6b5abfc2c414cd..d8face595aedbacbfa43ef81fc5e255113565335 100644 (file)
--- a/src/ui.c
+++ b/src/ui.c
  * it under the terms of the GNU General Public License version 2 as 
  * published by the Free Software Foundation.
  */
+#include <assert.h>                            /* assert */
+#include <ctype.h>                             /* tolower */
+#include <string.h>                            /* memcmp, str* */
+
 #include <libipset/linux_ip_set.h>             /* IPSET_CMD_* */
 #include <libipset/types.h>                    /* IPSET_*_ARG */
 #include <libipset/session.h>                  /* ipset_envopt_parse */
 #include <libipset/parse.h>                    /* ipset_parse_family */
 #include <libipset/print.h>                    /* ipset_print_family */
+#include <libipset/utils.h>                    /* STREQ */
 #include <libipset/ui.h>                       /* prototypes */
 
 /* Commands and environment options */
 
 const struct ipset_commands ipset_commands[] = {
-       [IPSET_CMD_CREATE - 1] = {
-               .name = { "create", "c",  "-N", "--create", NULL },
+       /* Order is important */
+
+       {       /* c[reate], --create, n, -N */
+               .cmd = IPSET_CMD_CREATE,
+               .name = { "create", "n" },
                .has_arg = IPSET_MANDATORY_ARG2,
                .help = "SETNAME TYPENAME [type-specific-options]\n"
                        "        Create a new set",
        },
-       [IPSET_CMD_DESTROY - 1] = {
-               .name = { "destroy", "x", "-X", "--destroy", NULL },
-               .has_arg = IPSET_OPTIONAL_ARG,
-               .help = "[SETNAME]\n"
-                       "        Destroy a named set or all sets",
-       },
-       [IPSET_CMD_FLUSH - 1] = {
-               .name = { "flush", "f",   "-F", "--flush", NULL },
-               .has_arg = IPSET_OPTIONAL_ARG,
-               .help = "[SETNAME]\n"
-                       "        Flush a named set or all sets",
+       {       /* a[dd], --add, -A  */
+               .cmd = IPSET_CMD_ADD,
+               .name = { "add", NULL },
+               .has_arg = IPSET_MANDATORY_ARG2,
+               .help = "SETNAME ENTRY\n"
+                       "        Add entry to the named set",
        },
-       [IPSET_CMD_RENAME - 1] = {
-               .name = { "rename", "e",  "-E", "--rename", NULL },
+       {       /* d[el], --del, -D */
+               .cmd = IPSET_CMD_DEL,
+               .name = { "del", NULL },
                .has_arg = IPSET_MANDATORY_ARG2,
-               .help = "FROM-SETNAME TO-SETNAME\n"
-                       "        Rename two sets",
+               .help = "SETNAME ENTRY\n"
+                       "        Delete entry from the named set",
        },
-       [IPSET_CMD_SWAP - 1] = {
-               .name = { "swap", "w",    "-W", "--swap", NULL },
+       {       /* t[est], --test, -T */
+               .cmd = IPSET_CMD_TEST,
+               .name = { "test", NULL },
                .has_arg = IPSET_MANDATORY_ARG2,
-               .help = "FROM-SETNAME TO-SETNAME\n"
-                       "        Swap the contect of two existing sets",
+               .help = "SETNAME ENTRY\n"
+                       "        Test entry in the named set",
+       },
+       {       /* des[troy], --destroy, x, -X */
+               .cmd = IPSET_CMD_DESTROY,
+               .name = { "destroy", "x" },
+               .has_arg = IPSET_OPTIONAL_ARG,
+               .help = "[SETNAME]\n"
+                       "        Destroy a named set or all sets",
        },
-       [IPSET_CMD_LIST - 1] = {
-               .name = { "list", "l",    "-L", "--list", NULL },
+       {       /* l[ist], --list, -L */
+               .cmd = IPSET_CMD_LIST,
+               .name = { "list", NULL },
                .has_arg = IPSET_OPTIONAL_ARG,
                .help = "[SETNAME]\n"
                        "        List the entries of a named set or all sets",
        },
-       [IPSET_CMD_SAVE - 1] = {
-               .name = { "save", "s",    "-S", "--save", NULL },
+       {       /* s[save], --save, -S */
+               .cmd = IPSET_CMD_SAVE,
+               .name = { "save", NULL },
                .has_arg = IPSET_OPTIONAL_ARG,
                .help = "[SETNAME]\n"
                        "        Save the named set or all sets to stdout",
        },
-       [IPSET_CMD_ADD - 1] = {
-               .name = { "add", "a",     "-A", "--add", NULL },
-               .has_arg = IPSET_MANDATORY_ARG2,
-               .help = "SETNAME ENTRY\n"
-                       "        Add entry to a named set",
+       {       /* r[estore], --restore, -R */
+               .cmd = IPSET_CMD_RESTORE,
+               .name = { "restore", NULL },
+               .has_arg = IPSET_NO_ARG,
+               .help = "\n"
+                       "        Restore a saved state",
+       },
+       {       /* f[lush], --flush, -F */
+               .cmd = IPSET_CMD_FLUSH,
+               .name = { "flush", NULL },
+               .has_arg = IPSET_OPTIONAL_ARG,
+               .help = "[SETNAME]\n"
+                       "        Flush a named set or all sets",
        },
-       [IPSET_CMD_DEL - 1] = {
-               .name = { "del", "d",     "-D", "--del", NULL },
+       {       /* ren[ame], --rename, e, -E */
+               .cmd = IPSET_CMD_RENAME,
+               .name = { "rename", "e" },
                .has_arg = IPSET_MANDATORY_ARG2,
-               .help = "SETNAME ENTRY\n"
-                       "        Delete entry from a named set",
+               .help = "FROM-SETNAME TO-SETNAME\n"
+                       "        Rename two sets",
        },
-       [IPSET_CMD_TEST - 1] = {
-               .name = { "test", "t",    "-T", "--test", NULL },
+       {       /* sw[ap], --swap, w, -W */
+               .cmd = IPSET_CMD_SWAP,
+               .name = { "swap", "w" },
                .has_arg = IPSET_MANDATORY_ARG2,
-               .help = "SETNAME ENTRY\n"
-                       "        Test if entry exists in the named set",
+               .help = "FROM-SETNAME TO-SETNAME\n"
+                       "        Swap the contect of two existing sets",
        },
-       [IPSET_CMD_HELP - 1] = {
-               .name = { "help", "h",    "-H", "-h", "--help", NULL },
+       {       /* h[elp, --help, -H */
+               .cmd = IPSET_CMD_HELP,
+               .name = { "help", NULL },
                .has_arg = IPSET_OPTIONAL_ARG,
                .help = "[TYPENAME]\n"
                        "        Print help, and settype specific help",
        },
-       [IPSET_CMD_RESTORE - 1] = {
-               .name = { "restore", "r", "-R", "--restore", NULL },
+       {       /* v[ersion], --version, -V */
+               .cmd = IPSET_CMD_VERSION,
+               .name = { "version", NULL },
                .has_arg = IPSET_NO_ARG,
                .help = "\n"
-                       "        Restore a saved state",
+                       "        Print version information",
        },
-       [IPSET_CMD_VERSION - 1] = {
-               .name = { "version", "v", "-V", "-v", "--version", NULL },
+       {       /* q[uit] */
+               .cmd = IPSET_CMD_QUIT,
+               .name = { "quit", NULL },
                .has_arg = IPSET_NO_ARG,
                .help = "\n"
-                       "        Print version information",
+                       "        Quit interactive mode",
        },
-       [IPSET_CMD_MAX - 1] = { },
+       { },
 };
 
+/* Match a command: try to match as a prefix or letter-command */
+bool
+ipset_match_cmd(const char *arg, const char * const name[])
+{
+       size_t len;
+
+       assert(arg);
+       assert(name && name[0]);
+
+       /* Ignore (two) leading dashes */
+       if (arg[0] == '-')
+               arg++;
+       if (arg[0] == '-')
+               arg++;
+
+       len = strlen(arg);
+
+       if (len > strlen(name[0]) || !len)
+               return false;
+       else if (memcmp(arg, name[0], len) == 0)
+               return true;
+       else if (len != 1)
+               return false;
+       else if (name[1] == NULL)
+               return tolower(arg[0]) == name[0][0];
+       else
+               return tolower(arg[0]) == name[1][0];   
+}
+
 const struct ipset_envopts ipset_envopts[] = {
-       { .name = { "family", "--family", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .flag = IPSET_OPT_FAMILY,
-         .parse = ipset_parse_family,          .print = ipset_print_family,
-         .help = "inet|inet6\n"
-                 "       Specify family when creating a set\n"
-                 "       which supports multiple families.\n"
-                 "       The default family is INET.",
-       },
-       { .name = { "-o", "--output", NULL },
+       { .name = { "-o", "-output" },
          .has_arg = IPSET_MANDATORY_ARG,       .flag = IPSET_OPT_MAX,
          .parse = ipset_parse_output,
          .help = "plain|save|xml\n"
@@ -112,25 +160,25 @@ const struct ipset_envopts ipset_envopts[] = {
                  "       Default value for \"list\" command is mode \"plain\"\n"
                  "       and for \"save\" command is mode \"save\".",
        },
-       { .name = { "-s", "--sorted", NULL },
+       { .name = { "-s", "-sorted" },
          .parse = ipset_envopt_parse,
          .has_arg = IPSET_NO_ARG,      .flag = IPSET_ENV_SORTED,
          .help = "\n"
                  "        Print elements sorted (if supported by the set type).",
        },
-       { .name = { "-q", "--quiet", NULL },
+       { .name = { "-q", "-quiet" },
          .parse = ipset_envopt_parse,
          .has_arg = IPSET_NO_ARG,      .flag = IPSET_ENV_QUIET,
          .help = "\n"
                  "        Suppress any notice or warning message.",
        },
-       { .name = { "-r", "--resolve", NULL },
+       { .name = { "-r", "-resolve" },
          .parse = ipset_envopt_parse,
          .has_arg = IPSET_NO_ARG,      .flag = IPSET_ENV_RESOLVE,
          .help = "\n"
                  "        Try to resolve IP addresses in the output (slow!)",
        },
-       { .name = { "-x", "--exist", NULL },
+       { .name = { "-!", "-exist" },
          .parse = ipset_envopt_parse,
          .has_arg = IPSET_NO_ARG,      .flag = IPSET_ENV_EXIST,
          .help = "\n"
@@ -138,14 +186,59 @@ const struct ipset_envopts ipset_envopts[] = {
                  "        when adding already existing elements\n"
                  "        or when deleting non-existing elements.",
        },
-       /* Aliases */
-       { .name = { "-4", NULL },
-         .has_arg = IPSET_NO_ARG,              .flag = IPSET_OPT_FAMILY,
-         .parse = ipset_parse_family,
-       },
-       { .name = { "-6", NULL },
-         .has_arg = IPSET_NO_ARG,              .flag = IPSET_OPT_FAMILY,
-         .parse = ipset_parse_family,
-       },
        { },
 };
+
+/* Strict option matching */
+bool
+ipset_match_option(const char *arg, const char * const name[])
+{
+       assert(arg);
+       assert(name && name[0]);
+       
+       /* Skip two leading dashes */
+       if (arg[0] == '-' && arg[1] == '-')
+               arg++, arg++;
+
+       return STREQ(arg, name[0])
+              || (name[1] != NULL && STREQ(arg, name[1]));
+}
+
+/* Strict envopt matching */
+bool
+ipset_match_envopt(const char *arg, const char * const name[])
+{
+       assert(arg);
+       assert(name && name[0]);
+       
+       /* Skip one leading dash */
+       if (arg[0] == '-' && arg[1] == '-')
+               arg++;
+
+       return STREQ(arg, name[0])
+              || (name[1] != NULL && STREQ(arg, name[1]));
+}
+
+/**
+ * ipset_shift_argv - shift off an argument
+ * @arc: argument count
+ * @argv: array of argument strings
+ * @from: from where shift off an argument
+ *
+ * Shift off the argument at "from" from the array of
+ * arguments argv of size argc.
+ */
+void
+ipset_shift_argv(int *argc, char *argv[], int from)
+{
+       int i;
+       
+       assert(*argc >= from + 1);
+
+       for (i = from + 1; i <= *argc; i++) {
+               argv[i-1] = argv[i];
+       }
+       (*argc)--;
+       return;
+}
+
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644 (file)
index 0000000..c9fcefc
--- /dev/null
@@ -0,0 +1,450 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# tests/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+pkgdatadir = $(datadir)/ipset
+pkglibdir = $(libdir)/ipset
+pkgincludedir = $(includedir)/ipset
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-unknown-linux-gnu
+host_triplet = x86_64-unknown-linux-gnu
+target_triplet = x86_64-unknown-linux-gnu
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       $(top_srcdir)/Make_global.am
+subdir = tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /root/ipset/missing --run aclocal-1.10
+AMTAR = ${SHELL} /root/ipset/missing --run tar
+AR = ar
+AUTOCONF = ${SHELL} /root/ipset/missing --run autoconf
+AUTOHEADER = ${SHELL} /root/ipset/missing --run autoheader
+AUTOMAKE = ${SHELL} /root/ipset/missing --run automake-1.10
+AWK = mawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS = 
+CXX = g++
+CXXCPP = 
+CXXDEPMODE = depmode=none
+CXXFLAGS = 
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DSYMUTIL = 
+ECHO = echo
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+EXEEXT = 
+F77 = 
+FFLAGS = 
+GREP = /bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LDFLAGS = 
+LIBOBJS = 
+LIBS = -lmnl 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LN_S = ln -s
+LTLIBOBJS = 
+MAKEINFO = ${SHELL} /root/ipset/missing --run makeinfo
+MKDIR_P = /bin/mkdir -p
+NMEDIT = 
+OBJEXT = o
+PACKAGE = ipset
+PACKAGE_BUGREPORT = kadlec@blackhole.kfki.hu
+PACKAGE_NAME = ipset
+PACKAGE_STRING = ipset 5.0
+PACKAGE_TARNAME = ipset
+PACKAGE_VERSION = 5.0
+PATH_SEPARATOR = :
+RANLIB = ranlib
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+VERSION = 5.0
+abs_builddir = /root/ipset/tests
+abs_srcdir = /root/ipset/tests
+abs_top_builddir = /root/ipset
+abs_top_srcdir = /root/ipset
+ac_ct_CC = gcc
+ac_ct_CXX = 
+ac_ct_F77 = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = ${AMTAR} chof - "$$tardir"
+am__untar = ${AMTAR} xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-unknown-linux-gnu
+build_alias = 
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = unknown
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = x86_64-unknown-linux-gnu
+host_alias = 
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = unknown
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = $(SHELL) /root/ipset/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = /bin/mkdir -p
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target = x86_64-unknown-linux-gnu
+target_alias = 
+target_cpu = x86_64
+target_os = linux-gnu
+target_vendor = unknown
+top_builddir = ..
+top_srcdir = ..
+
+# This is _NOT_ the library release version, it's an API version.
+# Please read Chapter 6 "Library interface versions" of the libtool
+# documentation before making any modification
+# http://sources.redhat.com/autobook/autobook/autobook_91.html
+LIBVERSION = 1:0:0
+AM_CPPFLAGS = $(kinclude_CFLAGS) $(all_includes) -I$(top_srcdir)/include \
+       -I/usr/local/include
+
+#      -Wconversion \  -> false warnings
+#      -Wcast-qual \   -> false warnings
+#      -Wpointer-arith \ -> we need it
+#      -std=gnu99
+
+#      -std=gnu99      ULLONG_MAX requires
+AM_CFLAGS = -std=gnu99 \
+       -Wall \
+       -Wextra \
+       -Waggregate-return \
+       -Wbad-function-cast \
+       -Wcast-align \
+       -Wfloat-equal \
+       -Winit-self \
+       -Winline \
+       -Wmissing-declarations \
+       -Wmissing-format-attribute \
+       -Wmissing-prototypes \
+       -Wnested-externs \
+       -Wold-style-definition \
+       -Wpacked \
+       -Wredundant-decls \
+       -Wshadow \
+       -Wsign-compare \
+       -Wstrict-prototypes \
+       -Wswitch-default \
+       -Wundef \
+       -Wwrite-strings \
+       -Wno-missing-field-initializers \
+       -Werror \
+       -g -ggdb
+
+
+#      fails with ntoh*: 
+#      -Wunreachable-code
+AM_VERBOSE_CC = @echo "  CC      " $@;
+AM_VERBOSE_CCLD = @echo "  CCLD    " $@;
+TESTS = ./runtest.sh
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/Make_global.am $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+               && exit 0; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  tests/Makefile'; \
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  tests/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+check-TESTS: $(TESTS)
+       @failed=0; all=0; xfail=0; xpass=0; skip=0; ws='[        ]'; \
+       srcdir=$(srcdir); export srcdir; \
+       list=' $(TESTS) '; \
+       if test -n "$$list"; then \
+         for tst in $$list; do \
+           if test -f ./$$tst; then dir=./; \
+           elif test -f $$tst; then dir=; \
+           else dir="$(srcdir)/"; fi; \
+           if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *$$ws$$tst$$ws*) \
+               xpass=`expr $$xpass + 1`; \
+               failed=`expr $$failed + 1`; \
+               echo "XPASS: $$tst"; \
+             ;; \
+             *) \
+               echo "PASS: $$tst"; \
+             ;; \
+             esac; \
+           elif test $$? -ne 77; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *$$ws$$tst$$ws*) \
+               xfail=`expr $$xfail + 1`; \
+               echo "XFAIL: $$tst"; \
+             ;; \
+             *) \
+               failed=`expr $$failed + 1`; \
+               echo "FAIL: $$tst"; \
+             ;; \
+             esac; \
+           else \
+             skip=`expr $$skip + 1`; \
+             echo "SKIP: $$tst"; \
+           fi; \
+         done; \
+         if test "$$failed" -eq 0; then \
+           if test "$$xfail" -eq 0; then \
+             banner="All $$all tests passed"; \
+           else \
+             banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+           fi; \
+         else \
+           if test "$$xpass" -eq 0; then \
+             banner="$$failed of $$all tests failed"; \
+           else \
+             banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+           fi; \
+         fi; \
+         dashes="$$banner"; \
+         skipped=""; \
+         if test "$$skip" -ne 0; then \
+           skipped="($$skip tests were not run)"; \
+           test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$skipped"; \
+         fi; \
+         report=""; \
+         if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+           report="Please report to $(PACKAGE_BUGREPORT)"; \
+           test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$report"; \
+         fi; \
+         dashes=`echo "$$dashes" | sed s/./=/g`; \
+         echo "$$dashes"; \
+         echo "$$banner"; \
+         test -z "$$skipped" || echo "$$skipped"; \
+         test -z "$$report" || echo "$$report"; \
+         echo "$$dashes"; \
+         test "$$failed" -eq 0; \
+       else :; fi
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+       $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-TESTS check-am clean clean-generic \
+       clean-libtool distclean distclean-generic distclean-libtool \
+       distdir dvi dvi-am html html-am info info-am install \
+       install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644 (file)
index 0000000..9b62557
--- /dev/null
@@ -0,0 +1,5 @@
+## Process this file with automake to produce Makefile.in
+
+include $(top_srcdir)/Make_global.am
+
+TESTS = ./runtest.sh
diff --git a/tests/Makefile.in b/tests/Makefile.in
new file mode 100644 (file)
index 0000000..5c47bc5
--- /dev/null
@@ -0,0 +1,450 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       $(top_srcdir)/Make_global.am
+subdir = tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# This is _NOT_ the library release version, it's an API version.
+# Please read Chapter 6 "Library interface versions" of the libtool
+# documentation before making any modification
+# http://sources.redhat.com/autobook/autobook/autobook_91.html
+LIBVERSION = 1:0:0
+AM_CPPFLAGS = $(kinclude_CFLAGS) $(all_includes) -I$(top_srcdir)/include \
+       -I/usr/local/include
+
+#      -Wconversion \  -> false warnings
+#      -Wcast-qual \   -> false warnings
+#      -Wpointer-arith \ -> we need it
+#      -std=gnu99
+
+#      -std=gnu99      ULLONG_MAX requires
+AM_CFLAGS = -std=gnu99 \
+       -Wall \
+       -Wextra \
+       -Waggregate-return \
+       -Wbad-function-cast \
+       -Wcast-align \
+       -Wfloat-equal \
+       -Winit-self \
+       -Winline \
+       -Wmissing-declarations \
+       -Wmissing-format-attribute \
+       -Wmissing-prototypes \
+       -Wnested-externs \
+       -Wold-style-definition \
+       -Wpacked \
+       -Wredundant-decls \
+       -Wshadow \
+       -Wsign-compare \
+       -Wstrict-prototypes \
+       -Wswitch-default \
+       -Wundef \
+       -Wwrite-strings \
+       -Wno-missing-field-initializers \
+       -Werror \
+       -g -ggdb
+
+
+#      fails with ntoh*: 
+#      -Wunreachable-code
+@VERBOSE_FALSE@AM_VERBOSE_CC = @echo "  CC      " $@;
+@VERBOSE_FALSE@AM_VERBOSE_CCLD = @echo "  CCLD    " $@;
+TESTS = ./runtest.sh
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/Make_global.am $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+               && exit 0; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  tests/Makefile'; \
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  tests/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+check-TESTS: $(TESTS)
+       @failed=0; all=0; xfail=0; xpass=0; skip=0; ws='[        ]'; \
+       srcdir=$(srcdir); export srcdir; \
+       list=' $(TESTS) '; \
+       if test -n "$$list"; then \
+         for tst in $$list; do \
+           if test -f ./$$tst; then dir=./; \
+           elif test -f $$tst; then dir=; \
+           else dir="$(srcdir)/"; fi; \
+           if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *$$ws$$tst$$ws*) \
+               xpass=`expr $$xpass + 1`; \
+               failed=`expr $$failed + 1`; \
+               echo "XPASS: $$tst"; \
+             ;; \
+             *) \
+               echo "PASS: $$tst"; \
+             ;; \
+             esac; \
+           elif test $$? -ne 77; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *$$ws$$tst$$ws*) \
+               xfail=`expr $$xfail + 1`; \
+               echo "XFAIL: $$tst"; \
+             ;; \
+             *) \
+               failed=`expr $$failed + 1`; \
+               echo "FAIL: $$tst"; \
+             ;; \
+             esac; \
+           else \
+             skip=`expr $$skip + 1`; \
+             echo "SKIP: $$tst"; \
+           fi; \
+         done; \
+         if test "$$failed" -eq 0; then \
+           if test "$$xfail" -eq 0; then \
+             banner="All $$all tests passed"; \
+           else \
+             banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+           fi; \
+         else \
+           if test "$$xpass" -eq 0; then \
+             banner="$$failed of $$all tests failed"; \
+           else \
+             banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+           fi; \
+         fi; \
+         dashes="$$banner"; \
+         skipped=""; \
+         if test "$$skip" -ne 0; then \
+           skipped="($$skip tests were not run)"; \
+           test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$skipped"; \
+         fi; \
+         report=""; \
+         if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+           report="Please report to $(PACKAGE_BUGREPORT)"; \
+           test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$report"; \
+         fi; \
+         dashes=`echo "$$dashes" | sed s/./=/g`; \
+         echo "$$dashes"; \
+         echo "$$banner"; \
+         test -z "$$skipped" || echo "$$skipped"; \
+         test -z "$$report" || echo "$$report"; \
+         echo "$$dashes"; \
+         test "$$failed" -eq 0; \
+       else :; fi
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+       $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-TESTS check-am clean clean-generic \
+       clean-libtool distclean distclean-generic distclean-libtool \
+       distdir dvi dvi-am html html-am info info-am install \
+       install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
index b44f5c4a87dc7b55f1cf18425245837e0fd24131..03cbe0ddd981a5bc31a37a9ca813f216f886cebc 100644 (file)
 # Range: Delete element not added to the set
 1 ipset -D test 2.0.0.2
 # Range: Delete element not added to the set, with exist flag
-0 ipset -x -D test 2.0.0.2
+0 ipset -! -D test 2.0.0.2
 # Range: Add element in the middle
 0 ipset -A test 2.0.0.128
 # Range: Add element in the middle again
 1 ipset -A test 2.0.0.128
 # Range: Add element in the middle again, with exist flag
-0 ipset -x -A test 2.0.0.128
+0 ipset -! -A test 2.0.0.128
 # Range: Delete the same element
 0 ipset -D test 2.0.0.128
 # Range: Add a range of elements
 0 ipset -A test 2.0.0.128-2.0.0.131 timeout 6
 # Range: List set
-0 ipset list test > .foo
+0 ipset list test | sed 's/timeout ./timeout x/' > .foo
 # Range: Check listing
-0 grep '2.0.0.1 timeout' .foo >/dev/null
+0 diff .foo bitmap:ip.t.list4 && rm .foo
 # Sleep 10s so that entries can time out
 0 sleep 10s
 # Range: List set after timeout
@@ -77,9 +77,9 @@
 # Network: Delete the same element
 0 ipset -D test 2.0.0.128
 # Network: List set
-0 ipset list test > .foo
+0 ipset list test | sed 's/timeout ./timeout x/' > .foo
 # Network: Check listing
-0 grep '2.0.255.255 timeout' .foo >/dev/null
+0 diff .foo bitmap:ip.t.list5 && rm .foo
 # Sleep 10s so that entries can time out
 0 sleep 10s
 # Network: List set
 0 ipset -D test 10.2.0.0
 # Subnets: Add a subnet of subnets
 0 ipset -A test 10.8.0.0/16 timeout 8
+# Subnets: List set
+0 ipset list test | sed 's/timeout ./timeout x/' > .foo
 # Subnets: Check listing
-0 ipset list test | grep '10.0.0.0 timeout' >/dev/null
+0 diff .foo bitmap:ip.t.list6 && rm .foo
 # Sleep 10s so that entries can time out
 0 sleep 10s
 # Subnets: List set
index 0be60c0da90da306699e25d7c6ea725f3a0b36ab..5f6b35df602e48b1dc6fa2d1dbd7733029a72cc8 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip
 Header: range 2.0.0.1-2.1.0.0 timeout 5 
-Elements: 1
-Size in memory: 524288
+Size in memory: 524408
 References: 0
 Members:
 2.1.0.0 timeout 0
index 02ccdaafdc8a2f14913705430588e86a3cea177d..60647176a0d1add62c2ea773a97830031ae5f583 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip
 Header: range 2.0.0.0-2.0.255.255 timeout 5 
-Elements: 1
-Size in memory: 524288
+Size in memory: 524408
 References: 0
 Members:
 2.0.0.0 timeout 0
index 7b1799919d7b8a268fe481a1e73e82b33f5beaf7..e00abc9b48d0f242dd7fc5035717733a623adfea 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip
 Header: range 10.0.0.0-10.255.255.255 netmask 24 timeout 5 
-Elements: 1
-Size in memory: 524288
+Size in memory: 524408
 References: 0
 Members:
 10.255.255.0 timeout 0
index 677bb2af4c287030c346d6fdfcb68bd6142d483c..2d5e7a7b97850e1902f7d1763b6e45f386eb4092 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip
 Header: range 0.0.0.0-255.255.255.255 netmask 16 timeout 5 
-Elements: 2
-Size in memory: 524288
+Size in memory: 524408
 References: 0
 Members:
 0.0.0.0 timeout 0
diff --git a/tests/bitmap:ip.t.list4 b/tests/bitmap:ip.t.list4
new file mode 100644 (file)
index 0000000..53004cf
--- /dev/null
@@ -0,0 +1,13 @@
+Name: test
+Type: bitmap:ip
+Header: range 2.0.0.1-2.1.0.0 timeout x 
+Size in memory: 524408
+References: 0
+Members:
+2.0.0.1 timeout x
+2.0.0.128 timeout x
+2.0.0.129 timeout x
+2.0.0.130 timeout x
+2.0.0.131 timeout x
+2.1.0.0 timeout x
+
diff --git a/tests/bitmap:ip.t.list5 b/tests/bitmap:ip.t.list5
new file mode 100644 (file)
index 0000000..65d338d
--- /dev/null
@@ -0,0 +1,9 @@
+Name: test
+Type: bitmap:ip
+Header: range 2.0.0.0-2.0.255.255 timeout x 
+Size in memory: 524408
+References: 0
+Members:
+2.0.0.0 timeout x
+2.0.255.255 timeout x
+
diff --git a/tests/bitmap:ip.t.list6 b/tests/bitmap:ip.t.list6
new file mode 100644 (file)
index 0000000..13b75ad
--- /dev/null
@@ -0,0 +1,265 @@
+Name: test
+Type: bitmap:ip
+Header: range 10.0.0.0-10.255.255.255 netmask 24 timeout x 
+Size in memory: 524408
+References: 0
+Members:
+10.0.0.0 timeout x
+10.8.0.0 timeout x
+10.8.1.0 timeout x
+10.8.2.0 timeout x
+10.8.3.0 timeout x
+10.8.4.0 timeout x
+10.8.5.0 timeout x
+10.8.6.0 timeout x
+10.8.7.0 timeout x
+10.8.8.0 timeout x
+10.8.9.0 timeout x
+10.8.10.0 timeout x
+10.8.11.0 timeout x
+10.8.12.0 timeout x
+10.8.13.0 timeout x
+10.8.14.0 timeout x
+10.8.15.0 timeout x
+10.8.16.0 timeout x
+10.8.17.0 timeout x
+10.8.18.0 timeout x
+10.8.19.0 timeout x
+10.8.20.0 timeout x
+10.8.21.0 timeout x
+10.8.22.0 timeout x
+10.8.23.0 timeout x
+10.8.24.0 timeout x
+10.8.25.0 timeout x
+10.8.26.0 timeout x
+10.8.27.0 timeout x
+10.8.28.0 timeout x
+10.8.29.0 timeout x
+10.8.30.0 timeout x
+10.8.31.0 timeout x
+10.8.32.0 timeout x
+10.8.33.0 timeout x
+10.8.34.0 timeout x
+10.8.35.0 timeout x
+10.8.36.0 timeout x
+10.8.37.0 timeout x
+10.8.38.0 timeout x
+10.8.39.0 timeout x
+10.8.40.0 timeout x
+10.8.41.0 timeout x
+10.8.42.0 timeout x
+10.8.43.0 timeout x
+10.8.44.0 timeout x
+10.8.45.0 timeout x
+10.8.46.0 timeout x
+10.8.47.0 timeout x
+10.8.48.0 timeout x
+10.8.49.0 timeout x
+10.8.50.0 timeout x
+10.8.51.0 timeout x
+10.8.52.0 timeout x
+10.8.53.0 timeout x
+10.8.54.0 timeout x
+10.8.55.0 timeout x
+10.8.56.0 timeout x
+10.8.57.0 timeout x
+10.8.58.0 timeout x
+10.8.59.0 timeout x
+10.8.60.0 timeout x
+10.8.61.0 timeout x
+10.8.62.0 timeout x
+10.8.63.0 timeout x
+10.8.64.0 timeout x
+10.8.65.0 timeout x
+10.8.66.0 timeout x
+10.8.67.0 timeout x
+10.8.68.0 timeout x
+10.8.69.0 timeout x
+10.8.70.0 timeout x
+10.8.71.0 timeout x
+10.8.72.0 timeout x
+10.8.73.0 timeout x
+10.8.74.0 timeout x
+10.8.75.0 timeout x
+10.8.76.0 timeout x
+10.8.77.0 timeout x
+10.8.78.0 timeout x
+10.8.79.0 timeout x
+10.8.80.0 timeout x
+10.8.81.0 timeout x
+10.8.82.0 timeout x
+10.8.83.0 timeout x
+10.8.84.0 timeout x
+10.8.85.0 timeout x
+10.8.86.0 timeout x
+10.8.87.0 timeout x
+10.8.88.0 timeout x
+10.8.89.0 timeout x
+10.8.90.0 timeout x
+10.8.91.0 timeout x
+10.8.92.0 timeout x
+10.8.93.0 timeout x
+10.8.94.0 timeout x
+10.8.95.0 timeout x
+10.8.96.0 timeout x
+10.8.97.0 timeout x
+10.8.98.0 timeout x
+10.8.99.0 timeout x
+10.8.100.0 timeout x
+10.8.101.0 timeout x
+10.8.102.0 timeout x
+10.8.103.0 timeout x
+10.8.104.0 timeout x
+10.8.105.0 timeout x
+10.8.106.0 timeout x
+10.8.107.0 timeout x
+10.8.108.0 timeout x
+10.8.109.0 timeout x
+10.8.110.0 timeout x
+10.8.111.0 timeout x
+10.8.112.0 timeout x
+10.8.113.0 timeout x
+10.8.114.0 timeout x
+10.8.115.0 timeout x
+10.8.116.0 timeout x
+10.8.117.0 timeout x
+10.8.118.0 timeout x
+10.8.119.0 timeout x
+10.8.120.0 timeout x
+10.8.121.0 timeout x
+10.8.122.0 timeout x
+10.8.123.0 timeout x
+10.8.124.0 timeout x
+10.8.125.0 timeout x
+10.8.126.0 timeout x
+10.8.127.0 timeout x
+10.8.128.0 timeout x
+10.8.129.0 timeout x
+10.8.130.0 timeout x
+10.8.131.0 timeout x
+10.8.132.0 timeout x
+10.8.133.0 timeout x
+10.8.134.0 timeout x
+10.8.135.0 timeout x
+10.8.136.0 timeout x
+10.8.137.0 timeout x
+10.8.138.0 timeout x
+10.8.139.0 timeout x
+10.8.140.0 timeout x
+10.8.141.0 timeout x
+10.8.142.0 timeout x
+10.8.143.0 timeout x
+10.8.144.0 timeout x
+10.8.145.0 timeout x
+10.8.146.0 timeout x
+10.8.147.0 timeout x
+10.8.148.0 timeout x
+10.8.149.0 timeout x
+10.8.150.0 timeout x
+10.8.151.0 timeout x
+10.8.152.0 timeout x
+10.8.153.0 timeout x
+10.8.154.0 timeout x
+10.8.155.0 timeout x
+10.8.156.0 timeout x
+10.8.157.0 timeout x
+10.8.158.0 timeout x
+10.8.159.0 timeout x
+10.8.160.0 timeout x
+10.8.161.0 timeout x
+10.8.162.0 timeout x
+10.8.163.0 timeout x
+10.8.164.0 timeout x
+10.8.165.0 timeout x
+10.8.166.0 timeout x
+10.8.167.0 timeout x
+10.8.168.0 timeout x
+10.8.169.0 timeout x
+10.8.170.0 timeout x
+10.8.171.0 timeout x
+10.8.172.0 timeout x
+10.8.173.0 timeout x
+10.8.174.0 timeout x
+10.8.175.0 timeout x
+10.8.176.0 timeout x
+10.8.177.0 timeout x
+10.8.178.0 timeout x
+10.8.179.0 timeout x
+10.8.180.0 timeout x
+10.8.181.0 timeout x
+10.8.182.0 timeout x
+10.8.183.0 timeout x
+10.8.184.0 timeout x
+10.8.185.0 timeout x
+10.8.186.0 timeout x
+10.8.187.0 timeout x
+10.8.188.0 timeout x
+10.8.189.0 timeout x
+10.8.190.0 timeout x
+10.8.191.0 timeout x
+10.8.192.0 timeout x
+10.8.193.0 timeout x
+10.8.194.0 timeout x
+10.8.195.0 timeout x
+10.8.196.0 timeout x
+10.8.197.0 timeout x
+10.8.198.0 timeout x
+10.8.199.0 timeout x
+10.8.200.0 timeout x
+10.8.201.0 timeout x
+10.8.202.0 timeout x
+10.8.203.0 timeout x
+10.8.204.0 timeout x
+10.8.205.0 timeout x
+10.8.206.0 timeout x
+10.8.207.0 timeout x
+10.8.208.0 timeout x
+10.8.209.0 timeout x
+10.8.210.0 timeout x
+10.8.211.0 timeout x
+10.8.212.0 timeout x
+10.8.213.0 timeout x
+10.8.214.0 timeout x
+10.8.215.0 timeout x
+10.8.216.0 timeout x
+10.8.217.0 timeout x
+10.8.218.0 timeout x
+10.8.219.0 timeout x
+10.8.220.0 timeout x
+10.8.221.0 timeout x
+10.8.222.0 timeout x
+10.8.223.0 timeout x
+10.8.224.0 timeout x
+10.8.225.0 timeout x
+10.8.226.0 timeout x
+10.8.227.0 timeout x
+10.8.228.0 timeout x
+10.8.229.0 timeout x
+10.8.230.0 timeout x
+10.8.231.0 timeout x
+10.8.232.0 timeout x
+10.8.233.0 timeout x
+10.8.234.0 timeout x
+10.8.235.0 timeout x
+10.8.236.0 timeout x
+10.8.237.0 timeout x
+10.8.238.0 timeout x
+10.8.239.0 timeout x
+10.8.240.0 timeout x
+10.8.241.0 timeout x
+10.8.242.0 timeout x
+10.8.243.0 timeout x
+10.8.244.0 timeout x
+10.8.245.0 timeout x
+10.8.246.0 timeout x
+10.8.247.0 timeout x
+10.8.248.0 timeout x
+10.8.249.0 timeout x
+10.8.250.0 timeout x
+10.8.251.0 timeout x
+10.8.252.0 timeout x
+10.8.253.0 timeout x
+10.8.254.0 timeout x
+10.8.255.0 timeout x
+10.255.255.0 timeout x
+
diff --git a/tests/hash:ip,port,ip.t b/tests/hash:ip,port,ip.t
new file mode 100644 (file)
index 0000000..3c74cd9
--- /dev/null
@@ -0,0 +1,51 @@
+# Range: Create a set with timeout
+0 ipset create test hash:ip,port,ip timeout 5
+# Range: Add partly zero valued element
+0 ipset add test 2.0.0.1,0,0.0.0.0
+# Range: Test partly zero valued element
+0 ipset test test 2.0.0.1,0,0.0.0.0
+# Range: Delete party zero valued element
+0 ipset del test 2.0.0.1,0,0.0.0.0
+# Range: Add almost zero valued element
+0 ipset add test 2.0.0.1,0,0.0.0.1
+# Range: Test almost zero valued element
+0 ipset test test 2.0.0.1,0,0.0.0.1
+# Range: Delete almost zero valued element
+0 ipset del test 2.0.0.1,0,0.0.0.1
+# Range: Add lower boundary
+0 ipset add test 2.0.0.1,5,1.1.1.1
+# Range: Add upper boundary
+0 ipset add test 2.1.0.0,128,2.2.2.2
+# Range: Test lower boundary
+0 ipset test test 2.0.0.1,5,1.1.1.1
+# Range: Test upper boundary
+0 ipset test test 2.1.0.0,128,2.2.2.2
+# Range: Test value not added to the set
+1 ipset test test 2.0.0.1,5,1.1.1.2
+# Range: Test value not added to the set
+1 ipset test test 2.0.0.1,6,1.1.1.1
+# Range: Test value not added to the set
+1 ipset test test 2.0.0.2,6,1.1.1.1
+# Range: Test value before lower boundary
+1 ipset test test 2.0.0.0,5,1.1.1.1
+# Range: Test value after upper boundary
+1 ipset test test 2.1.0.1,128,2.2.2.2
+# Range: Try to add value before lower boundary
+0 ipset add test 2.0.0.0,5,1.1.1.1
+# Range: Try to add value after upper boundary
+0 ipset add test 2.1.0.1,128,2.2.2.2
+# Range: List set
+0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
+# Range: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip,port,ip.t.list0 && rm .foo
+# Range: Sleep 6s so that elements can time out
+0 sleep 6
+# Range: List set
+0 ipset list test > .foo0 && ./sort.sh .foo0
+# Range: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip,port,ip.t.list1 && rm .foo
+# Range: Flush test set
+0 ipset flush test
+# Range: Delete test set
+0 ipset destroy test
+# eof
diff --git a/tests/hash:ip,port,ip.t.list0 b/tests/hash:ip,port,ip.t.list0
new file mode 100644 (file)
index 0000000..b20c8d8
--- /dev/null
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:ip,port,ip
+Header: family inet hashsize 1024 maxelem 65536 timeout x 
+Size in memory: 8720
+References: 0
+Members:
+2.0.0.0,5,1.1.1.1 timeout x
+2.0.0.1,5,1.1.1.1 timeout x
+2.1.0.0,128,2.2.2.2 timeout x
+2.1.0.1,128,2.2.2.2 timeout x
+
diff --git a/tests/hash:ip,port,ip.t.list1 b/tests/hash:ip,port,ip.t.list1
new file mode 100644 (file)
index 0000000..fb0b4a4
--- /dev/null
@@ -0,0 +1,7 @@
+Name: test
+Type: hash:ip,port,ip
+Header: family inet hashsize 1024 maxelem 65536 timeout 5 
+Size in memory: 8304
+References: 0
+Members:
+
diff --git a/tests/hash:ip,port.t b/tests/hash:ip,port.t
new file mode 100644 (file)
index 0000000..cb88f96
--- /dev/null
@@ -0,0 +1,43 @@
+# Range: Create a set with timeout
+0 ipset create test hash:ip,port timeout 5
+# Range: Add partly zero valued element
+0 ipset add test 2.0.0.1,0
+# Range: Test partly zero valued element
+0 ipset test test 2.0.0.1,0
+# Range: Delete partly zero valued element
+0 ipset del test 2.0.0.1,0
+# Range: Add lower boundary
+0 ipset add test 2.0.0.1,5
+# Range: Add upper boundary
+0 ipset add test 2.1.0.0,128
+# Range: Test lower boundary
+0 ipset test test 2.0.0.1,5
+# Range: Test upper boundary
+0 ipset test test 2.1.0.0,128
+# Range: Test value not added to the set
+1 ipset test test 2.0.0.1,4
+# Range: Delete value not added to the set
+1 ipset del test 2.0.0.1,6
+# Range: Test value before lower boundary
+1 ipset test test 2.0.0.0,5
+# Range: Test value after upper boundary
+1 ipset test test 2.1.0.1,128
+# Range: Try to add value before lower boundary
+0 ipset add test 2.0.0.0,5
+# Range: Try to add value after upper boundary
+0 ipset add test 2.1.0.1,128
+# Range: List set
+0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
+# Range: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip,port.t.list0 && rm .foo
+# Range: Sleep 6s so that elements can time out
+0 sleep 6
+# Range: List set
+0 ipset list test > .foo0 && ./sort.sh .foo0
+# Range: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip,port.t.list1 && rm .foo
+# Range: Flush test set
+0 ipset flush test
+# Range: Delete test set
+0 ipset destroy test
+# eof
diff --git a/tests/hash:ip,port.t.list0 b/tests/hash:ip,port.t.list0
new file mode 100644 (file)
index 0000000..25d8632
--- /dev/null
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:ip,port
+Header: family inet hashsize 1024 maxelem 65536 timeout x 
+Size in memory: 8592
+References: 0
+Members:
+2.0.0.0,5 timeout x
+2.0.0.1,5 timeout x
+2.1.0.0,128 timeout x
+2.1.0.1,128 timeout x
+
diff --git a/tests/hash:ip,port.t.list1 b/tests/hash:ip,port.t.list1
new file mode 100644 (file)
index 0000000..d455117
--- /dev/null
@@ -0,0 +1,7 @@
+Name: test
+Type: hash:ip,port
+Header: family inet hashsize 1024 maxelem 65536 timeout 5 
+Size in memory: 8304
+References: 0
+Members:
+
index de6b0dfaa94b06113d55afda720fda16a6bb93de..c7bddb82ddc9c20e2f7969a118a29b2d7da630a5 100644 (file)
 0 ipset -A test 200.100.0.12
 # IP: Delete the same value
 0 ipset -D test 200.100.0.12
+# IP: List set
+0 ipset -L test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
+# IP: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip.t.list2 && rm .foo
 # Sleep 6s so that element can time out
 0 sleep 6
 # IP: List set
 0 ipset -L test 2>/dev/null > .foo0 && ./sort.sh .foo0
 # IP: Check listing
-0 diff .foo hash:ip.t.list0 && rm .foo
+0 diff -I 'Size in memory.*' .foo hash:ip.t.list0 && rm .foo
 # IP: Flush test set
 0 ipset -F test
 # IP: Delete test set
 0 ipset -T test 192.168.68.95
 # Network: Test value not added to the set
 1 ipset -T test 2.0.1.0
-# Network: List set
-0 ipset -L test > .foo && grep '2.0.0.0 timeout' .foo >/dev/null && grep '192.168.68.0 timeout' .foo >/dev/null && rm .foo
 # Network: Add third element
 0 ipset -A test 200.100.10.1 timeout 0
 # Network: Add third random network
 0 ipset -A test 200.100.0.12
 # Network: Delete the same network
 0 ipset -D test 200.100.0.12
+# Network: List set
+0 ipset -L test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
+# Network: Check listing
+0 diff -I 'Size in memory.*' -I 'Size in memory.*' .foo hash:ip.t.list3 && rm .foo
 # Sleep 6s so that elements can time out
 0 sleep 6
 # Network: List set
 0 ipset -L test > .foo
 # Network: Check listing
-0 diff .foo hash:ip.t.list1 && rm .foo
+0 diff -I 'Size in memory.*' .foo hash:ip.t.list1 && rm .foo
 # Network: Flush test set
 0 ipset -F test
 # Network: Delete test set
index cf2ecac9de9bfe9b6bafcb4ebd59b9f1c7c50daa..117faf21a47896cca3718ab8b8ca4ff45ece495e 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: hash:ip
-Header: hashsize 128 maxelem 65536 probes 4 resize 50 timeout 5 
-Elements: 1
-Size in memory: 2048
+Header: family inet hashsize 128 maxelem 65536 timeout 5 
+Size in memory: 1208
 References: 0
 Members:
 192.168.68.69 timeout 0
index c564ba084552450daca4dc1bd362859478521a60..3189dae0d18ec7b578140b404b2c7a5ab713d50d 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: hash:ip
-Header: hashsize 128 maxelem 65536 probes 4 resize 50 netmask 24 timeout 6 
-Elements: 1
-Size in memory: 2048
+Header: family inet hashsize 128 maxelem 65536 netmask 24 timeout 6 
+Size in memory: 1352
 References: 0
 Members:
 200.100.10.0 timeout 0
diff --git a/tests/hash:ip.t.list2 b/tests/hash:ip.t.list2
new file mode 100644 (file)
index 0000000..468ba67
--- /dev/null
@@ -0,0 +1,9 @@
+Name: test
+Type: hash:ip
+Header: family inet hashsize 128 maxelem 65536 timeout x 
+Size in memory: 1280
+References: 0
+Members:
+192.168.68.69 timeout x
+2.0.0.1 timeout x
+
diff --git a/tests/hash:ip.t.list3 b/tests/hash:ip.t.list3
new file mode 100644 (file)
index 0000000..463f0a4
--- /dev/null
@@ -0,0 +1,10 @@
+Name: test
+Type: hash:ip
+Header: family inet hashsize 128 maxelem 65536 netmask 24 timeout x 
+Size in memory: 1352
+References: 0
+Members:
+192.168.68.0 timeout x
+2.0.0.0 timeout x
+200.100.10.0 timeout x
+
diff --git a/tests/hash:ip6,port,ip6.t b/tests/hash:ip6,port,ip6.t
new file mode 100644 (file)
index 0000000..84afdf9
--- /dev/null
@@ -0,0 +1,51 @@
+# Range: Create a set with timeout
+0 ipset create test hash:ip,port,ip family inet6 timeout 5
+# Range: Add partly zero valued element
+0 ipset add test 2:0:0::1,0,0:0:0::0
+# Range: Test partly zero valued element
+0 ipset test test 2:0:0::1,0,0:0:0::0
+# Range: Delete party zero valued element
+0 ipset del test 2:0:0::1,0,0:0:0::0
+# Range: Add almost zero valued element
+0 ipset add test 2:0:0::1,0,0:0:0::1
+# Range: Test almost zero valued element
+0 ipset test test 2:0:0::1,0,0:0:0::1
+# Range: Delete almost zero valued element
+0 ipset del test 2:0:0::1,0,0:0:0::1
+# Range: Add lower boundary
+0 ipset add test 2:0:0::1,5,1:1:1::1
+# Range: Add upper boundary
+0 ipset add test 2:1:0::0,128,2:2:2::2
+# Range: Test lower boundary
+0 ipset test test 2:0:0::1,5,1:1:1::1
+# Range: Test upper boundary
+0 ipset test test 2:1:0::0,128,2:2:2::2
+# Range: Test value not added to the set
+1 ipset test test 2:0:0::1,5,1:1:1::2
+# Range: Test value not added to the set
+1 ipset test test 2:0:0::1,6,1:1:1::1
+# Range: Test value not added to the set
+1 ipset test test 2:0:0::2,6,1:1:1::1
+# Range: Test value before lower boundary
+1 ipset test test 2:0:0::0,5,1:1:1::1
+# Range: Test value after upper boundary
+1 ipset test test 2:1:0::1,128,2:2:2::2
+# Range: Try to add value before lower boundary
+0 ipset add test 2:0:0::0,5,1:1:1::1
+# Range: Try to add value after upper boundary
+0 ipset add test 2:1:0::1,128,2:2:2::2
+# Range: List set
+0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
+# Range: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip6,port,ip6.t.list0 && rm .foo
+# Range: Sleep 6s so that elements can time out
+0 sleep 6
+# Range: List set
+0 ipset list test > .foo0 && ./sort.sh .foo0
+# Range: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip6,port,ip6.t.list1 && rm .foo
+# Range: Flush test set
+0 ipset flush test
+# Range: Delete test set
+0 ipset destroy test
+# eof
diff --git a/tests/hash:ip6,port,ip6.t.list0 b/tests/hash:ip6,port,ip6.t.list0
new file mode 100644 (file)
index 0000000..84cdf5c
--- /dev/null
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:ip,port,ip
+Header: family inet6 hashsize 1024 maxelem 65536 timeout x 
+Size in memory: 9104
+References: 0
+Members:
+2:1::1,128,2:2:2::2 timeout x
+2:1::,128,2:2:2::2 timeout x
+2::1,5,1:1:1::1 timeout x
+2::,5,1:1:1::1 timeout x
+
diff --git a/tests/hash:ip6,port,ip6.t.list1 b/tests/hash:ip6,port,ip6.t.list1
new file mode 100644 (file)
index 0000000..16fdb92
--- /dev/null
@@ -0,0 +1,7 @@
+Name: test
+Type: hash:ip,port,ip
+Header: family inet6 hashsize 1024 maxelem 65536 timeout 5 
+Size in memory: 8304
+References: 0
+Members:
+
diff --git a/tests/hash:ip6,port,net6.t b/tests/hash:ip6,port,net6.t
new file mode 100644 (file)
index 0000000..0041b5d
--- /dev/null
@@ -0,0 +1,45 @@
+# Range: Create a set
+0 ipset -N test ipportnethash -6
+# Range: Add zero valued element
+1 ipset -A test 2:0:0::1,0,0:0:0::0/0
+# Range: Test zero valued element
+1 ipset -T test 2:0:0::1,0,0:0:0::0/0
+# Range: Delete zero valued element
+1 ipset -D test 2:0:0::1,0,0:0:0::0/0
+# Range: Add almost zero valued element
+0 ipset -A test 2:0:0::1,0,0:0:0::0/24
+# Range: Test almost zero valued element
+0 ipset -T test 2:0:0::1,0,0:0:0::0/24
+# Range: Delete almost zero valued element
+0 ipset -D test 2:0:0::1,0,0:0:0::0/24
+# Range: Add lower boundary
+0 ipset -A test 2:0:0::1,5,1:1:1::1/24
+# Range: Add upper boundary
+0 ipset -A test 2:1:0::0,128,2:2:2::2/12
+# Range: Test lower boundary
+0 ipset -T test 2:0:0::1,5,1:1:1::2
+# Range: Test upper boundary
+0 ipset -T test 2:1:0::0,128,2:2:2::0
+# Range: Test value not added to the set
+1 ipset -T test 2:0:0::1,5,2:1:1::255
+# Range: Test value not added to the set
+1 ipset -T test 2:0:0::1,6,1:1:1::1
+# Range: Test value not added to the set
+1 ipset -T test 2:0:0::2,6,1:1:1::1
+# Range: Test value before lower boundary
+1 ipset -T test 2:0:0::0,5,1:1:1::1
+# Range: Test value after upper boundary
+1 ipset -T test 2:1:0::1,128,2:2:2::2
+# Range: Try to add value before lower boundary
+0 ipset -A test 2:0:0::0,5,1:1:1::1/24
+# Range: Try to add value after upper boundary
+0 ipset -A test 2:1:0::1,128,2:2:2::2/12
+# Range: List set
+0 ipset -L test > .foo0 && ./sort.sh .foo0
+# Range: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip6,port,net6.t.list0 && rm .foo
+# Range: Flush test set
+0 ipset -F test
+# Range: Delete test set
+0 ipset -X test
+# eof
diff --git a/tests/hash:ip6,port,net6.t.list0 b/tests/hash:ip6,port,net6.t.list0
new file mode 100644 (file)
index 0000000..cd9bffe
--- /dev/null
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:ip,port,net
+Header: family inet6 family inet6 hashsize 1024 maxelem 65536 
+Size in memory: 9928
+References: 0
+Members:
+2:1::1,128,::/12
+2:1::,128,::/12
+2::1,5,1::/24
+2::,5,1::/24
+
diff --git a/tests/hash:ip6,port.t b/tests/hash:ip6,port.t
new file mode 100644 (file)
index 0000000..feb525c
--- /dev/null
@@ -0,0 +1,43 @@
+# Range: Create a set with timeout
+0 ipset create test hash:ip,port family inet6 timeout 5
+# Range: Add partly zero valued element
+0 ipset add test 2:0:0::1,0
+# Range: Test partly zero valued element
+0 ipset test test 2:0:0::1,0
+# Range: Delete partly zero valued element
+0 ipset del test 2:0:0::1,0
+# Range: Add lower boundary
+0 ipset add test 2:0:0::1,5
+# Range: Add upper boundary
+0 ipset add test 2:1:0::0,128
+# Range: Test lower boundary
+0 ipset test test 2:0:0::1,5
+# Range: Test upper boundary
+0 ipset test test 2:1:0::0,128
+# Range: Test value not added to the set
+1 ipset test test 2:0:0::1,4
+# Range: Delete value not added to the set
+1 ipset del test 2:0:0::1,6
+# Range: Test value before lower boundary
+1 ipset test test 2:0:0::0,5
+# Range: Test value after upper boundary
+1 ipset test test 2:1:0::1,128
+# Range: Try to add value before lower boundary
+0 ipset add test 2:0:0::0,5
+# Range: Try to add value after upper boundary
+0 ipset add test 2:1:0::1,128
+# Range: List set
+0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
+# Range: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip6,port.t.list0 && rm .foo
+# Range: Sleep 6s so that elements can time out
+0 sleep 6
+# Range: List set
+0 ipset list test > .foo0 && ./sort.sh .foo0
+# Range: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip6,port.t.list1 && rm .foo
+# Range: Flush test set
+0 ipset flush test
+# Range: Delete test set
+0 ipset destroy test
+# eof
diff --git a/tests/hash:ip6,port.t.list0 b/tests/hash:ip6,port.t.list0
new file mode 100644 (file)
index 0000000..defd377
--- /dev/null
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:ip,port
+Header: family inet6 hashsize 1024 maxelem 65536 timeout x 
+Size in memory: 8848
+References: 0
+Members:
+2:1::1,128 timeout x
+2:1::,128 timeout x
+2::1,5 timeout x
+2::,5 timeout x
+
diff --git a/tests/hash:ip6,port.t.list1 b/tests/hash:ip6,port.t.list1
new file mode 100644 (file)
index 0000000..8dec3e8
--- /dev/null
@@ -0,0 +1,7 @@
+Name: test
+Type: hash:ip,port
+Header: family inet6 hashsize 1024 maxelem 65536 timeout 5 
+Size in memory: 8304
+References: 0
+Members:
+
diff --git a/tests/hash:ip6.t b/tests/hash:ip6.t
new file mode 100644 (file)
index 0000000..dae9e1e
--- /dev/null
@@ -0,0 +1,77 @@
+# IP: Create a set with timeout
+0 ipset -N test iphash -6 --hashsize 128 timeout 5
+# IP: Add zero valued element
+1 ipset -A test ::
+# IP: Test zero valued element
+1 ipset -T test ::
+# IP: Delete zero valued element
+1 ipset -D test ::
+# IP: Add first random value
+0 ipset -A test 2:0:0::1 timeout 5
+# IP: Add second random value
+0 ipset -A test 192:168:68::69 timeout 0
+# IP: Test first random value
+0 ipset -T test 2:0:0::1
+# IP: Test second random value
+0 ipset -T test 192:168:68::69
+# IP: Test value not added to the set
+1 ipset -T test 2:0:0::2
+# IP: Add third random value
+0 ipset -A test 200:100:0::12
+# IP: Delete the same value
+0 ipset -D test 200:100:0::12
+# IP: List set
+0 ipset -L test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
+# IP: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip6.t.list2 && rm .foo
+# Sleep 6s so that element can time out
+0 sleep 6
+# IP: List set
+0 ipset -L test 2>/dev/null > .foo0 && ./sort.sh .foo0
+# IP: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip6.t.list0 && rm .foo
+# IP: Flush test set
+0 ipset -F test
+# IP: Delete test set
+0 ipset -X test
+# Network: Create a set with timeout
+0 ipset -N test iphash -6 --hashsize 128 --netmask 64 timeout 6
+# Network: Add zero valued element
+1 ipset -A test ::
+# Network: Test zero valued element
+1 ipset -T test ::
+# Network: Delete zero valued element
+1 ipset -D test ::
+# Network: Add first random network
+0 ipset -A test 2:0:0::1
+# Network: Add second random network
+0 ipset -A test 192:168:68::69
+# Network: Test first random value
+0 ipset -T test 2:0:0::255
+# Network: Test second random value
+0 ipset -T test 192:168:68::95
+# Network: Test value not added to the set
+1 ipset -T test 4:0:1::0
+# Network: Add third element
+0 ipset -A test 200:100:10::1 timeout 0
+# Network: Add third random network
+0 ipset -A test 200:101:0::12
+# Network: Delete the same network
+0 ipset -D test 200:101:0::12
+# Network: Test the deleted network
+1 ipset -T test 200:101:0::12
+# Network: List set
+0 ipset -L test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
+# Network: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip6.t.list3 && rm .foo
+# Sleep 6s so that elements can time out
+0 sleep 6
+# Network: List set
+0 ipset -L test > .foo
+# Network: Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip6.t.list1 && rm .foo
+# Network: Flush test set
+0 ipset -F test
+# Network: Delete test set
+0 ipset -X test
+# eof
diff --git a/tests/hash:ip6.t.list0 b/tests/hash:ip6.t.list0
new file mode 100644 (file)
index 0000000..ff1c0da
--- /dev/null
@@ -0,0 +1,8 @@
+Name: test
+Type: hash:ip
+Header: family inet6 hashsize 128 maxelem 65536 timeout 5 
+Size in memory: 1240
+References: 0
+Members:
+192:168:68::69 timeout 0
+
diff --git a/tests/hash:ip6.t.list1 b/tests/hash:ip6.t.list1
new file mode 100644 (file)
index 0000000..ce5c5fe
--- /dev/null
@@ -0,0 +1,8 @@
+Name: test
+Type: hash:ip
+Header: family inet6 hashsize 128 maxelem 65536 netmask 64 timeout 6 
+Size in memory: 1448
+References: 0
+Members:
+200:100:10:: timeout 0
+
diff --git a/tests/hash:ip6.t.list2 b/tests/hash:ip6.t.list2
new file mode 100644 (file)
index 0000000..5cd39fb
--- /dev/null
@@ -0,0 +1,9 @@
+Name: test
+Type: hash:ip
+Header: family inet6 hashsize 128 maxelem 65536 timeout x 
+Size in memory: 1344
+References: 0
+Members:
+192:168:68::69 timeout x
+2::1 timeout x
+
diff --git a/tests/hash:ip6.t.list3 b/tests/hash:ip6.t.list3
new file mode 100644 (file)
index 0000000..dce0660
--- /dev/null
@@ -0,0 +1,10 @@
+Name: test
+Type: hash:ip
+Header: family inet6 hashsize 128 maxelem 65536 netmask 64 timeout x 
+Size in memory: 1448
+References: 0
+Members:
+192:168:68:: timeout x
+200:100:10:: timeout x
+2:: timeout x
+
diff --git a/tests/hash:net.t b/tests/hash:net.t
new file mode 100644 (file)
index 0000000..b46ac86
--- /dev/null
@@ -0,0 +1,49 @@
+# Create a set with timeout
+0 ipset create test nethash hashsize 128 timeout 6
+# Range: Add zero valued element
+1 ipset add test 0.0.0.0/0
+# Range: Test zero valued element
+1 ipset test test 0.0.0.0/0
+# Range: Delete zero valued element
+1 ipset del test 0.0.0.0/0
+# Range: Try to add /0
+1 ipset add test 1.1.1.1/0
+# Range: Try to add /32
+0 ipset add test 1.1.1.1/32
+# Range: Add almost zero valued element
+0 ipset add test 0.0.0.0/1
+# Range: Test almost zero valued element
+0 ipset test test 0.0.0.0/1
+# Range: Delete almost zero valued element
+0 ipset del test 0.0.0.0/1
+# Range: Test deleted element
+1 ipset test test 0.0.0.0/1
+# Range: Delete element not added to the set
+1 ipset del test 0.0.0.0/1
+# Range: Add first random network
+0 ipset add test 2.0.0.1/24
+# Range: Add second random network
+0 ipset add test 192.168.68.69/27
+# Range: Test first random value
+0 ipset test test 2.0.0.255
+# Range: Test second random value
+0 ipset test test 192.168.68.95
+# Range: Test value not added to the set
+1 ipset test test 2.0.1.0
+# Range: Try to add IP address
+0 ipset add test 2.0.0.1
+# Range: List set
+0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
+# Range: Check listing
+0 diff -I 'Size in memory.*' .foo hash:net.t.list0 && rm .foo
+# Sleep 6s so that element can time out
+0 sleep 6
+# IP: List set
+0 ipset -L test 2>/dev/null > .foo0 && ./sort.sh .foo0
+# IP: Check listing
+0 diff -I 'Size in memory.*' .foo hash:net.t.list1 && rm .foo
+# Flush test set
+0 ipset flush test
+# Delete test set
+0 ipset destroy test
+# eof
diff --git a/tests/hash:net.t.list0 b/tests/hash:net.t.list0
new file mode 100644 (file)
index 0000000..b5cc00b
--- /dev/null
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:net
+Header: family inet hashsize 128 maxelem 65536 timeout x 
+Size in memory: 1672
+References: 0
+Members:
+1.1.1.1 timeout x
+192.168.68.64/27 timeout x
+2.0.0.0/24 timeout x
+2.0.0.1 timeout x
+
diff --git a/tests/hash:net.t.list1 b/tests/hash:net.t.list1
new file mode 100644 (file)
index 0000000..7dec348
--- /dev/null
@@ -0,0 +1,7 @@
+Name: test
+Type: hash:net
+Header: family inet hashsize 128 maxelem 65536 timeout 6 
+Size in memory: 1672
+References: 0
+Members:
+
diff --git a/tests/hash:net6.t b/tests/hash:net6.t
new file mode 100644 (file)
index 0000000..e4246d9
--- /dev/null
@@ -0,0 +1,49 @@
+# Create a set with timeout
+0 ipset create test nethash family inet6 hashsize 128 timeout 6
+# Range: Add zero valued element
+1 ipset add test ::/0
+# Range: Test zero valued element
+1 ipset test test ::/0
+# Range: Delete zero valued element
+1 ipset del test ::/0
+# Range: Try to add /0
+1 ipset add test 1:1:1::1/0
+# Range: Try to add /32
+0 ipset add test 1:1:1::1/128
+# Range: Add almost zero valued element
+0 ipset add test 0:0:0::0/1
+# Range: Test almost zero valued element
+0 ipset test test 0:0:0::0/1
+# Range: Delete almost zero valued element
+0 ipset del test 0:0:0::0/1
+# Range: Test deleted element
+1 ipset test test 0:0:0::0/1
+# Range: Delete element not added to the set
+1 ipset del test 0:0:0::0/1
+# Range: Add first random network
+0 ipset add test 2:0:0::1/24
+# Range: Add second random network
+0 ipset add test 192:168:68::69/27
+# Range: Test first random value
+0 ipset test test 2:0:0::255
+# Range: Test second random value
+0 ipset test test 192:168:68::95
+# Range: Test value not added to the set
+1 ipset test test 3:0:0::1
+# Range: Try to add IP address
+0 ipset add test 3:0:0::1
+# Range: List set
+0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
+# Range: Check listing
+0 diff -I 'Size in memory.*' .foo hash:net6.t.list0 && rm .foo
+# Sleep 6s so that element can time out
+0 sleep 6
+# IP: List set
+0 ipset -L test 2>/dev/null > .foo0 && ./sort.sh .foo0
+# IP: Check listing
+0 diff -I 'Size in memory.*' .foo hash:net6.t.list1 && rm .foo
+# Flush test set
+0 ipset flush test
+# Delete test set
+0 ipset destroy test
+# eof
diff --git a/tests/hash:net6.t.list0 b/tests/hash:net6.t.list0
new file mode 100644 (file)
index 0000000..47a4663
--- /dev/null
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:net
+Header: family inet6 hashsize 128 maxelem 65536 timeout x 
+Size in memory: 2696
+References: 0
+Members:
+1:1:1::1 timeout x
+192:160::/27 timeout x
+2::/24 timeout x
+3::1 timeout x
+
diff --git a/tests/hash:net6.t.list1 b/tests/hash:net6.t.list1
new file mode 100644 (file)
index 0000000..2a606bc
--- /dev/null
@@ -0,0 +1,7 @@
+Name: test
+Type: hash:net
+Header: family inet6 hashsize 128 maxelem 65536 timeout 6 
+Size in memory: 2696
+References: 0
+Members:
+
index 923931afe30c308538c51ffa17bd63d11d43488e..c912ad77ab222175234757042f076f55142ffdaf 100644 (file)
 0 ipset -A test 200.100.0.12
 # IP: Delete the same value
 0 ipset -D test 200.100.0.12
+# IP: Delete element not added to the set
+1 ipset -D test 200.100.0.12
+# IP: Delete element not added to the set, ignoring error
+0 ipset -! -D test 200.100.0.12
 # IP: List set
 0 ipset -L test 2>/dev/null > .foo0 && ./sort.sh .foo0
 # IP: Check listing
-0 diff .foo iphash.t.list0 && rm .foo
+0 diff -I 'Size in memory.*' .foo iphash.t.list0 && rm .foo
 # IP: Flush test set
 0 ipset -F test
 # IP: Delete test set
 0 ipset -A test 200.100.0.12
 # Network: Delete the same network
 0 ipset -D test 200.100.0.12
+# Network: Delete element not added to the set
+1 ipset -D test 200.100.0.12
 # Network: List set
 0 ipset -L test > .foo0 && ./sort.sh .foo0
 # Network: Check listing
-0 diff .foo iphash.t.list1 && rm .foo
+0 diff -I 'Size in memory.*' .foo iphash.t.list1 && rm .foo
 # Network: Flush test set
 0 ipset -F test
 # Network: Delete test set
index 3f0c2fabea2d2f7a6a63ee81cfe214bb7a4fa7cc..e2cc4ca6b4d4a21ad47d77891a065ab1ed8e9e4f 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: hash:ip
-Header: hashsize 128 maxelem 65536 probes 4 resize 50 
-Elements: 2
-Size in memory: 512
+Header: family inet hashsize 128 maxelem 65536 
+Size in memory: 1184
 References: 0
 Members:
 192.168.68.69
index f32655a7f637f6835d50c8782072d35d16e52357..ec9b49351b4771c19c7855eb00e49e887d070407 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: hash:ip
-Header: hashsize 128 maxelem 65536 probes 4 resize 50 netmask 24 
-Elements: 2
-Size in memory: 512
+Header: family inet hashsize 128 maxelem 65536 netmask 24 
+Size in memory: 1184
 References: 0
 Members:
 192.168.68.0
index c639e0b94b2b6373860525d63ab19b0c086a09a0..00c35e8371ba5fccd2cfb097dec75573af095725 100644 (file)
@@ -33,7 +33,7 @@
 # Range: Check listing
 0 diff .foo ipmap.t.list0 && rm .foo
 # Range: Delete a range of elements
-0 ipset -D test -x 2.0.0.128-2.0.0.132
+0 ipset -! -D test 2.0.0.128-2.0.0.132
 # Range: List set
 0 ipset -L test > .foo
 # Range: Check listing
index 560eed1c724a24f4c00d563a0bdb033c027d7c14..8bf54c2b543d95e0a894643270bef282e8ee9dac 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip
 Header: range 2.0.0.1-2.1.0.0 
-Elements: 6
-Size in memory: 8192
+Size in memory: 8232
 References: 0
 Members:
 2.0.0.1
index 55556a7abd27198e428189d55ff5a03530271e44..4541cf553850d242af5b4c6a3b80a90e62d3d289 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip
 Header: range 2.0.0.1-2.1.0.0 
-Elements: 2
-Size in memory: 8192
+Size in memory: 8232
 References: 0
 Members:
 2.0.0.1
index 9e1b65d8b08b74e8cb9f2492d1c57434aaa7b4fa..5f78ba603c049618a0476e5245979d146c89bcd4 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip
 Header: range 2.0.0.0-2.0.255.255 
-Elements: 2
-Size in memory: 8192
+Size in memory: 8232
 References: 0
 Members:
 2.0.0.0
index 4b2a45a992e5d0f0882e3b58ed2aad97c5ea55b3..0acb3ee81422edfc2c13ed2d0e2d5aa0d3f1c388 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip
 Header: range 10.0.0.0-10.255.255.255 netmask 24 
-Elements: 258
-Size in memory: 8192
+Size in memory: 8232
 References: 0
 Members:
 10.0.0.0
index f498ba9fc5372da6d0c739f7ebb6f991378ab61b..67a0c4ff1e7148bfbf03be98e91f12e154cc3127 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip
 Header: range 0.0.0.0-255.255.255.255 netmask 16 
-Elements: 2
-Size in memory: 8192
+Size in memory: 8232
 References: 0
 Members:
 0.0.0.0
index 7c622bb4603fdb7acf86950dcfd5f5283a0d0d3b..dc35bcd971e5914ce60efd59f50bbf46660b1678 100644 (file)
@@ -1,13 +1,15 @@
-# Range: Try to create from an invalid range
-2 ipset -N test ipporthash --from 2.0.0.1 --to 2.1.0.1
-# Range: Create a set from a valid range
+# Range: Create a set from a range (range ignored)
 0 ipset -N test ipporthash --from 2.0.0.1 --to 2.1.0.0
-# Range: Add zero valued element
-1 ipset -A test 2.0.0.1,0
-# Range: Test zero valued element
-1 ipset -T test 2.0.0.1,0
-# Range: Delete zero valued element
-1 ipset -D test 2.0.0.1,0
+# Range: Destroy set
+0 ipset -X test
+# Range: Create a set
+0 ipset -N test ipporthash
+# Range: Add partly zero valued element
+0 ipset -A test 2.0.0.1,0
+# Range: Test partly zero valued element
+0 ipset -T test 2.0.0.1,0
+# Range: Delete partly zero valued element
+0 ipset -D test 2.0.0.1,0
 # Range: Add lower boundary
 0 ipset -A test 2.0.0.1,5
 # Range: Add upper boundary
 0 ipset -T test 2.1.0.0,128
 # Range: Test value not added to the set
 1 ipset -T test 2.0.0.1,4
-# Range: Test value not added to the set
-1 ipset -T test 2.0.0.1,6
+# Range: Delete value not added to the set
+1 ipset -D test 2.0.0.1,6
 # Range: Test value before lower boundary
 1 ipset -T test 2.0.0.0,5
 # Range: Test value after upper boundary
 1 ipset -T test 2.1.0.1,128
 # Range: Try to add value before lower boundary
-1 ipset -A test 2.0.0.0,5
+0 ipset -A test 2.0.0.0,5
 # Range: Try to add value after upper boundary
-1 ipset -A test 2.1.0.1,128
+0 ipset -A test 2.1.0.1,128
 # Range: List set
 0 ipset -L test > .foo0 && ./sort.sh .foo0
 # Range: Check listing
-0 diff .foo ipporthash.t.list0 && rm .foo
+0 diff -I 'Size in memory.*' .foo ipporthash.t.list0 && rm .foo
 # Range: Flush test set
 0 ipset -F test
 # Range: Delete test set
 0 ipset -X test
-# Network: Try to create a set from an invalid network
-2 ipset -N test ipporthash --network 2.0.0.0/15
-# Network: Create a set from a valid network
+# Network: Create a set from a network (network ignored)
 0 ipset -N test ipporthash --network 2.0.0.0/16
 # Network: Add lower boundary
 0 ipset -A test 2.0.0.0,5
 0 ipset -T test 2.0.255.255,128
 # Network: Test value not added to the set
 1 ipset -T test 2.0.0.0,4
-# Network: Test value not added to the set
-1 ipset -T test 2.0.0.0,6
+# Network: Delete value not added to the set
+1 ipset -D test 2.0.0.0,6
 # Network: Test value before lower boundary
 1 ipset -T test 1.255.255.255,5
 # Network: Test value after upper boundary
 1 ipset -T test 2.1.0.0,128
 # Network: Try to add value before lower boundary
-1 ipset -A test 1.255.255.255,5
+0 ipset -A test 1.255.255.255,5
 # Network: Try to add value after upper boundary
-1 ipset -A test 2.1.0.0,128
+0 ipset -A test 2.1.0.0,128
 # Network: List set
 0 ipset -L test > .foo0 && ./sort.sh .foo0
 # Network: Check listing
-0 diff .foo ipporthash.t.list1 && rm .foo
+0 diff -I 'Size in memory.*' .foo ipporthash.t.list1 && rm .foo
 # Network: Flush test set
 0 ipset -F test
 # Network: Delete test set
index b840a94d2ce65a94db062ae0d2440126875e1b89..2e78ac420a86da1d049f3a61ad6ef3e1ba4a8163 100644 (file)
@@ -1,7 +1,11 @@
 Name: test
-Type: ipporthash
+Type: hash:ip,port
+Header: family inet hashsize 1024 maxelem 65536 
+Size in memory: 8464
 References: 0
-Header: from: 2.0.0.1 to: 2.1.0.0 hashsize: 1024 probes: 8 resize: 50
 Members:
+2.0.0.0,5
 2.0.0.1,5
 2.1.0.0,128
+2.1.0.1,128
+
index be86cdaebacca96f6501d932a83a20197df5006c..e0f0da5d3e8f30f9e3e57065f778346caa883626 100644 (file)
@@ -1,7 +1,11 @@
 Name: test
-Type: ipporthash
+Type: hash:ip,port
+Header: family inet hashsize 1024 maxelem 65536 
+Size in memory: 8464
 References: 0
-Header: from: 2.0.0.0 to: 2.0.255.255 hashsize: 1024 probes: 8 resize: 50
 Members:
+1.255.255.255,5
 2.0.0.0,5
 2.0.255.255,128
+2.1.0.0,128
+
index 860d5a69a1e29e3f00ea434149c2beb72c49d835..3f619476d199a39904ab1a11a5f395ab9dd16240 100644 (file)
@@ -1,13 +1,15 @@
-# Range: Try to create from an invalid range
-2 ipset -N test ipportiphash --from 2.0.0.1 --to 2.1.0.1
-# Range: Create a set from a valid range
+# Range: Create a set from a range (range ignored)
 0 ipset -N test ipportiphash --from 2.0.0.1 --to 2.1.0.0
-# Range: Add zero valued element
-1 ipset -A test 2.0.0.1,0,0.0.0.0
-# Range: Test zero valued element
-1 ipset -T test 2.0.0.1,0,0.0.0.0
-# Range: Delete zero valued element
-1 ipset -D test 2.0.0.1,0,0.0.0.0
+# Range: Destroy set
+0 ipset -X test
+# Range: Create a set
+0 ipset -N test ipportiphash
+# Range: Add partly zero valued element
+0 ipset -A test 2.0.0.1,0,0.0.0.0
+# Range: Test partly zero valued element
+0 ipset -T test 2.0.0.1,0,0.0.0.0
+# Range: Delete party zero valued element
+0 ipset -D test 2.0.0.1,0,0.0.0.0
 # Range: Add almost zero valued element
 0 ipset -A test 2.0.0.1,0,0.0.0.1
 # Range: Test almost zero valued element
 # Range: Test value after upper boundary
 1 ipset -T test 2.1.0.1,128,2.2.2.2
 # Range: Try to add value before lower boundary
-1 ipset -A test 2.0.0.0,5,1.1.1.1
+0 ipset -A test 2.0.0.0,5,1.1.1.1
 # Range: Try to add value after upper boundary
-1 ipset -A test 2.1.0.1,128,2.2.2.2
+0 ipset -A test 2.1.0.1,128,2.2.2.2
 # Range: List set
 0 ipset -L test > .foo0 && ./sort.sh .foo0
 # Range: Check listing
-0 diff .foo ipportiphash.t.list0 && rm .foo
+0 diff -I 'Size in memory.*' .foo ipportiphash.t.list0 && rm .foo
 # Range: Flush test set
 0 ipset -F test
 # Range: Delete test set
 0 ipset -X test
-# Network: Try to create a set from an invalid network
-2 ipset -N test ipportiphash --network 2.0.0.0/15
-# Network: Create a set from a valid network
+# Network: Create a set from a valid network (network ignored)
 0 ipset -N test ipportiphash --network 2.0.0.0/16
 # Network: Add lower boundary
 0 ipset -A test 2.0.0.0,5,1.1.1.1
 # Network: Test value after upper boundary
 1 ipset -T test 2.1.0.0,128,2.2.2.2
 # Network: Try to add value before lower boundary
-1 ipset -A test 1.255.255.255,5,1.1.1.1
-# Network: Try to add value after upper boundary
-1 ipset -A test 2.1.0.0,128,2.2.2.2
+0 ipset -A test 1.255.255.255,5,1.1.1.1
+# Network: Try to test value before lower boundary
+0 ipset -T test 1.255.255.255,5,1.1.1.1
+# Network: Try to del value before lower boundary
+0 ipset -D test 1.255.255.255,5,1.1.1.1
 # Network: List set
 0 ipset -L test > .foo0 && ./sort.sh .foo0
 # Network: Check listing
-0 diff .foo ipportiphash.t.list1 && rm .foo
+0 diff -I 'Size in memory.*' .foo ipportiphash.t.list1 && rm .foo
 # Network: Flush test set
 0 ipset -F test
 # Network: Delete test set
index acb1041b7806ee0f94d5cb938ab2670a7862b23f..ba20b1458e95dedb27db4b6d8de7ffb121f6cae6 100644 (file)
@@ -1,7 +1,11 @@
 Name: test
-Type: ipportiphash
+Type: hash:ip,port,ip
+Header: family inet hashsize 1024 maxelem 65536 
+Size in memory: 8528
 References: 0
-Header: from: 2.0.0.1 to: 2.1.0.0 hashsize: 1024 probes: 8 resize: 50
 Members:
+2.0.0.0,5,1.1.1.1
 2.0.0.1,5,1.1.1.1
 2.1.0.0,128,2.2.2.2
+2.1.0.1,128,2.2.2.2
+
index 55450780c7b74c2cb93c511ce415a2597b3f8f1a..aca272a96824e33b98448ddc6b0c711edb5eb851 100644 (file)
@@ -1,7 +1,9 @@
 Name: test
-Type: ipportiphash
+Type: hash:ip,port,ip
+Header: family inet hashsize 1024 maxelem 65536 
+Size in memory: 8416
 References: 0
-Header: from: 2.0.0.0 to: 2.0.255.255 hashsize: 1024 probes: 8 resize: 50
 Members:
 2.0.0.0,5,1.1.1.1
 2.0.255.255,128,2.2.2.2
+
index 93369efabcd619ff7ea64f725c0b29c00b1decd8..6aff58331939c1dde2631c0218a207f007c4c203 100644 (file)
@@ -1,13 +1,11 @@
-# Range: Try to create from an invalid range
-2 ipset -N test ipportnethash --from 2.0.0.1 --to 2.1.0.1
-# Range: Create a set from a valid range
+# Range: Create a set from a range (range ignored)
 0 ipset -N test ipportnethash --from 2.0.0.1 --to 2.1.0.0
 # Range: Add zero valued element
-2 ipset -A test 2.0.0.1,0,0.0.0.0/0
+1 ipset -A test 2.0.0.1,0,0.0.0.0/0
 # Range: Test zero valued element
-2 ipset -T test 2.0.0.1,0,0.0.0.0/0
+1 ipset -T test 2.0.0.1,0,0.0.0.0/0
 # Range: Delete zero valued element
-2 ipset -D test 2.0.0.1,0,0.0.0.0/0
+1 ipset -D test 2.0.0.1,0,0.0.0.0/0
 # Range: Add almost zero valued element
 0 ipset -A test 2.0.0.1,0,0.0.0.0/24
 # Range: Test almost zero valued element
 # Range: Test value after upper boundary
 1 ipset -T test 2.1.0.1,128,2.2.2.2
 # Range: Try to add value before lower boundary
-1 ipset -A test 2.0.0.0,5,1.1.1.1/24
+0 ipset -A test 2.0.0.0,5,1.1.1.1/24
 # Range: Try to add value after upper boundary
-1 ipset -A test 2.1.0.1,128,2.2.2.2/12
+0 ipset -A test 2.1.0.1,128,2.2.2.2/12
 # Range: List set
 0 ipset -L test > .foo0 && ./sort.sh .foo0
 # Range: Check listing
-0 diff .foo ipportnethash.t.list0 && rm .foo
+0 diff -I 'Size in memory.*' .foo ipportnethash.t.list0 && rm .foo
 # Range: Flush test set
 0 ipset -F test
 # Range: Delete test set
 0 ipset -X test
-# Network: Try to create a set from an invalid network
-2 ipset -N test ipportnethash --network 2.0.0.0/15
-# Network: Create a set from a valid network
+# Network: Create a set from a valid network (network ignored)
 0 ipset -N test ipportnethash --network 2.0.0.0/16
 # Network: Add lower boundary
 0 ipset -A test 2.0.0.0,5,1.1.1.1/24
 # Network: Test value after upper boundary
 1 ipset -T test 2.1.0.0,128,2.2.2.2
 # Network: Try to add value before lower boundary
-1 ipset -A test 1.255.255.255,5,1.1.1.1/24
+0 ipset -A test 1.255.255.255,5,1.1.1.1/24
 # Network: Try to add value after upper boundary
-1 ipset -A test 2.1.0.0,128,2.2.2.2/12
+0 ipset -A test 2.1.0.0,128,2.2.2.2/12
 # Network: List set
 0 ipset -L test > .foo0 && ./sort.sh .foo0
 # Network: Check listing
-0 diff .foo ipportnethash.t.list1 && rm .foo
+0 diff -I 'Size in memory.*' .foo ipportnethash.t.list1 && rm .foo
 # Network: Flush test set
 0 ipset -F test
 # Network: Delete test set
index 9727d201b624238c621dbe133f911ade17e67ca1..60a024216e3e4fb1e7e9e0d497e5ef4adca6d81f 100644 (file)
@@ -1,7 +1,11 @@
 Name: test
-Type: ipportnethash
+Type: hash:ip,port,net
+Header: family inet hashsize 1024 maxelem 65536 
+Size in memory: 8776
 References: 0
-Header: from: 2.0.0.1 to: 2.1.0.0 hashsize: 1024 probes: 8 resize: 50
 Members:
+2.0.0.0,5,1.1.1.0/24
 2.0.0.1,5,1.1.1.0/24
 2.1.0.0,128,2.0.0.0/12
+2.1.0.1,128,2.0.0.0/12
+
index ad861d424fa62d60a0bd26786cf295ae95704c8b..5d741057bf98f086a9e49291c922e57b136d851b 100644 (file)
@@ -1,7 +1,11 @@
 Name: test
-Type: ipportnethash
+Type: hash:ip,port,net
+Header: family inet hashsize 1024 maxelem 65536 
+Size in memory: 8776
 References: 0
-Header: from: 2.0.0.0 to: 2.0.255.255 hashsize: 1024 probes: 8 resize: 50
 Members:
+1.255.255.255,5,1.1.1.0/24
 2.0.0.0,5,1.1.1.0/24
 2.0.255.255,128,2.0.0.0/12
+2.1.0.0,128,2.0.0.0/12
+
index 3cb0e004730734a9e1428678ddee6fbfcd2162ef..b1e36786fb084bc1377d2961b1cbfbd28b70a2ef 100644 (file)
@@ -13,7 +13,7 @@
 # Static: Test value not added to the set
 1 ipset -T test 192.168.68.70
 # Static: List set
-0 ipset -L test > .foo
+0 ipset -L test > .foo0 && ./sort.sh .foo0
 # Static: Check listing
 0 diff .foo iptree.t.list0 && rm .foo
 # Static: Flush test set
index 07433b9ce727d719fa546bdc4f7a6c3634c66a8e..f93546dc7716b5a2f0818933f904f360948d6beb 100644 (file)
@@ -1,8 +1,9 @@
 Name: test
-Type: iptree
+Type: hash:ip
+Header: family inet hashsize 1024 maxelem 65536 
+Size in memory: 8352
 References: 0
-Header:
 Members:
-2.0.0.1
 192.168.68.69
+2.0.0.1
 
index 2e9fce7ff861f4912c472fa787a30d7a2686c885..0c36c3afb4c8cee4bbaf7ce6916f15506453850e 100644 (file)
@@ -28,6 +28,8 @@
 1 ipset -T test 3.0.0.1
 # Test the range: third
 0 ipset -T test 3.0.0.2
+# Delete second random IP entry
+0 ipset -D test 192.168.68.69
 # Add a network block
 0 ipset -A test 192.168.68.69/27
 # Test the lower bound of the network
@@ -47,7 +49,7 @@
 # Test element after upper bound of deleted network
 0 ipset -T test 192.168.68.72
 # List set
-0 ipset -L test > .foo
+0 ipset -L test > .foo0 && ./sort.sh .foo0
 # Check listing
 0 diff .foo iptreemap.t.list0 && rm .foo
 # Flush test set
index 6e783a0722abffd50c5694a36f1ae963fc8550f3..15db1fe6fe729072c680003eaf0aaf8ee46977da 100644 (file)
@@ -1,11 +1,38 @@
 Name: test
-Type: iptreemap
+Type: hash:ip
+Header: family inet hashsize 1024 maxelem 65536 
+Size in memory: 9048
 References: 0
-Header: gc: 300
 Members:
+192.168.68.64
+192.168.68.65
+192.168.68.66
+192.168.68.67
+192.168.68.72
+192.168.68.73
+192.168.68.74
+192.168.68.75
+192.168.68.76
+192.168.68.77
+192.168.68.78
+192.168.68.79
+192.168.68.80
+192.168.68.81
+192.168.68.82
+192.168.68.83
+192.168.68.84
+192.168.68.85
+192.168.68.86
+192.168.68.87
+192.168.68.88
+192.168.68.89
+192.168.68.90
+192.168.68.91
+192.168.68.92
+192.168.68.93
+192.168.68.94
+192.168.68.95
 2.0.0.1
 3.0.0.0
 3.0.0.2
-192.168.68.64-192.168.68.67
-192.168.68.72-192.168.68.95
 
index 277672d28e58333a516076f7fa3eaab330bf5b61..90f09bad2d306b3bf4feab2250b915c075898a9d 100644 (file)
@@ -20,6 +20,8 @@
 1 ipset -A test 2.0.0.0
 # Range: Try to add value after upper boundary
 1 ipset -A test 2.1.0.1
+# Range: Delete element not added to the set
+1 ipset -D test 2.0.0.2
 # Range: Try to add value with MAC
 0 ipset -A test 2.0.0.2,00:11:22:33:44:55
 # Range: Test value with invalid MAC
 0 ipset -T test 2.0.0.2,00:11:22:33:44:55
 # Range: Add MAC to already added element
 0 ipset -A test 2.0.0.1,00:11:22:33:44:56
+# Range: Test value without supplying MAC
+0 ipset -T test 2.0.0.1
+# Range: Test value with valid MAC
+0 ipset -T test 2.0.0.1,00:11:22:33:44:56
 # Range: Add an element in the middle
 0 ipset -A test 2.0.200.214,00:11:22:33:44:57
 # Range: Delete the same element
@@ -62,6 +68,8 @@
 1 ipset -A test 1.255.255.255
 # Network: Try to add value after upper boundary
 1 ipset -A test 2.1.0.0
+# Network: Delete element not added to the set
+1 ipset -D test 2.0.0.2
 # Network: Try to add value with MAC
 0 ipset -A test 2.0.0.2,00:11:22:33:44:55
 # Network: Test value with invalid MAC
 0 ipset -A test 2.0.200.214,00:11:22:33:44:57
 # Range: Delete the same element
 0 ipset -D test 2.0.200.214
+# Range: List set
+0 ipset -L test | sed 's/timeout ./timeout x/' > .foo
 # Range: Check listing
-0 ipset -L test | grep '2.0.0.2,00:11:22:33:44:55 timeout' >/dev/null
+0 diff .foo macipmap.t.list3 && rm .foo
 # Range: wait 10s so that elements can timeout
 0 sleep 10
 # Range: List set
index f34c882b26b3c4ac1cf9df349f3e9d4545f1232d..9403224c98d24de9451f5de70e7e82e7d42ea6de 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip,mac
 Header: range 2.0.0.1-2.1.0.0 
-Elements: 3
-Size in memory: 458752
+Size in memory: 458864
 References: 0
 Members:
 2.0.0.1,00:11:22:33:44:56
index cbdf1277fd5d75775fbc4831e8cc692212c95751..3420abee14f9aef5111aa1a1aafb0616dba5d183 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip,mac
 Header: range 2.0.0.0-2.0.255.255 
-Elements: 3
-Size in memory: 458752
+Size in memory: 458864
 References: 0
 Members:
 2.0.0.0
index 9d0413e46d1f6fc97e16741558e9f5d108b70e32..6a727d8d3473b5a88d7373e74df045141b6047a7 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:ip,mac
 Header: range 2.0.0.1-2.1.0.0 timeout 10 
-Elements: 1
-Size in memory: 1048576
+Size in memory: 1048688
 References: 0
 Members:
 2.1.0.0 timeout 5
diff --git a/tests/macipmap.t.list3 b/tests/macipmap.t.list3
new file mode 100644 (file)
index 0000000..9f52f06
--- /dev/null
@@ -0,0 +1,10 @@
+Name: test
+Type: bitmap:ip,mac
+Header: range 2.0.0.1-2.1.0.0 timeout x0 
+Size in memory: 1048688
+References: 0
+Members:
+2.0.0.1,00:11:22:33:44:56 timeout x
+2.0.0.2,00:11:22:33:44:55 timeout x
+2.1.0.0 timeout x
+
index cedcfdec5a0ac45f7c5e465e3f0c0301cf70dc94..400e110202a24e924ebad4e719b28738c83ffb7b 100644 (file)
@@ -1,37 +1,41 @@
 # Create a set 
 0 ipset -N test nethash --hashsize 128 
 # Range: Add zero valued element
-2 ipset -A test 0.0.0.0/0
+1 ipset -A test 0.0.0.0/0
 # Range: Test zero valued element
-2 ipset -T test 0.0.0.0/0
+1 ipset -T test 0.0.0.0/0
 # Range: Delete zero valued element
-2 ipset -D test 0.0.0.0/0
+1 ipset -D test 0.0.0.0/0
 # Range: Try to add /0
-2 ipset -A test 1.1.1.1/0
+1 ipset -A test 1.1.1.1/0
 # Range: Try to add /32
-2 ipset -A test 1.1.1.1/32
+0 ipset -A test 1.1.1.1/32
 # Range: Add almost zero valued element
 0 ipset -A test 0.0.0.0/1
 # Range: Test almost zero valued element
 0 ipset -T test 0.0.0.0/1
 # Range: Delete almost zero valued element
 0 ipset -D test 0.0.0.0/1
-# Range:  Add first random network
+# Range: Test deleted element
+1 ipset -T test 0.0.0.0/1
+# Range: Delete element not added to the set
+1 ipset -D test 0.0.0.0/1
+# Range: Add first random network
 0 ipset -A test 2.0.0.1/24
-# Range:  Add second random network
+# Range: Add second random network
 0 ipset -A test 192.168.68.69/27
-# Range:  Test first random value
+# Range: Test first random value
 0 ipset -T test 2.0.0.255
-# Range:  Test second random value
+# Range: Test second random value
 0 ipset -T test 192.168.68.95
-# Range:  Test value not added to the set
+# Range: Test value not added to the set
 1 ipset -T test 2.0.1.0
-# Range:  Try to add IP address
-2 ipset -A test 2.0.0.1
+# Range: Try to add IP address
+0 ipset -A test 2.0.0.1
 # Range: List set
 0 ipset -L test > .foo0 && ./sort.sh .foo0
 # Range: Check listing
-0 diff .foo nethash.t.list0 && rm .foo
+0 diff -I 'Size in memory.*' .foo nethash.t.list0 && rm .foo
 # Flush test set
 0 ipset -F test
 # Delete test set
index 0b008b8fa4d18714ac3202bcf83b95a46a44cacc..2809d79384832251db4bc5c70ae6daeca3519cf5 100644 (file)
@@ -1,7 +1,11 @@
 Name: test
-Type: nethash
+Type: hash:net
+Header: family inet hashsize 128 maxelem 65536 
+Size in memory: 1544
 References: 0
-Header: hashsize: 128 probes: 4 resize: 50
 Members:
+1.1.1.1
 192.168.68.64/27
 2.0.0.0/24
+2.0.0.1
+
index 5e058496ff4a75d4cb5385a45e72f26e383bc7cb..b2ebf553a1b5681b5cbdfe49d6a4442e75dc91b3 100644 (file)
@@ -18,6 +18,8 @@
 1 ipset -A test 0
 # Range: Try to add value after upper boundary
 1 ipset -A test 1025
+# Range: Delete element not added to the set
+1 ipset -D test 567
 # Range: Add element in the middle
 0 ipset -A test 567
 # Range: Delete the same element
 0 ipset -A test 567
 # Full: Delete the same element
 0 ipset -D test 567
+# Full: List set
+0 ipset -L test | sed 's/timeout ./timeout x/' > .foo
+# Full: Check listing
+0 diff .foo portmap.t.list3 && rm .foo
 # Full: sleep 10s so that elements can timeout
 0 sleep 10
 # Full: List set
index ed0b7d12e565a1ca9bf516cbd477e9a9317739db..9934a75eca2eec5499c323c679502fdbb2025135 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:port
 Header: range 1-1024 
-Elements: 2
-Size in memory: 128
+Size in memory: 152
 References: 0
 Members:
 1
index f67b128334b92000f077e95ac9c686258c600998..4f13e32dde0191318d985189db4f50839a710f5e 100644 (file)
@@ -1,8 +1,7 @@
 Name: test
 Type: bitmap:port
 Header: range 0-65535 
-Elements: 2
-Size in memory: 8192
+Size in memory: 8216
 References: 0
 Members:
 0
diff --git a/tests/portmap.t.list3 b/tests/portmap.t.list3
new file mode 100644 (file)
index 0000000..b79cd1e
--- /dev/null
@@ -0,0 +1,9 @@
+Name: test
+Type: bitmap:port
+Header: range 0-65535 timeout x 
+Size in memory: 524400
+References: 0
+Members:
+0 timeout x
+65535 timeout x
+
index a0459058eaaf26a23b07365952066aa3ca50fd3e..ccd057e8af23d2a7f545b7eafecaa269ae1bcabf 100755 (executable)
@@ -1,22 +1,19 @@
 #!/bin/bash
 
 tests="init"
-tests="$tests ipmap bitmap:ip macipmap portmap"
-tests="$tests iphash hash:ip"
-# nethash ipporthash"
-# tests="$tests ipportiphash ipportnethash"
-# tests="$tests iptree iptreemap"
-# tests="$tests setlist"
+tests="$tests ipmap bitmap:ip"
+tests="$tests macipmap portmap"
+tests="$tests iphash hash:ip hash:ip6"
+tests="$tests ipporthash hash:ip,port hash:ip6,port"
+tests="$tests ipportiphash hash:ip,port,ip hash:ip6,port,ip6"
+tests="$tests nethash hash:net hash:net6"
+tests="$tests setlist"
+tests="$tests iptree iptreemap"
 
 if [ "$1" ]; then
        tests="init $@"
 fi
 
-if [ ! -x ../src/ipset ]; then
-       echo "Please rune `make` first and create the ipset binary."
-       exit 1
-fi
-
 for types in $tests; do
     ../src/ipset -X test >/dev/null 2>&1
     if [ -f $types ]; then
index ed21396d4e4c1f9daa14bde18902ba12f40d988e..f80f5ae6642e1ef0e0d44f4f21c41c35bd62c2f9 100644 (file)
@@ -1,9 +1,15 @@
+# Setlist: Create dummy set
+0 ipset -N dummy list:set
 # Setlist: Create base set foo
 0 ipset -N foo ipmap --from 2.0.0.1 --to 2.1.0.0
 # Setlist: Create base set bar
 0 ipset -N bar iphash
 # Setlist: Create setlist kind of set
 0 ipset -N test setlist
+# Setlist: Swap test and dumy sets
+0 ipset -W test dummy
+# Setlist: Destroy dummy set
+0 ipset -X dummy
 # Setlist: Add foo set to setlist
 0 ipset -A test foo
 # Setlist: Test foo set in setlist
index 9b7044680e6396a256d8752833317599596cb8d8..99f88fb5b9ec46ea523ad9c05823ba30b6a71aa1 100644 (file)
@@ -1,7 +1,8 @@
 Name: test
-Type: setlist
+Type: list:set
+Header: size 8 
+Size in memory: 112
 References: 0
-Header: size: 8
 Members:
 foo
 bar
index 907148aca21d548658645fb86f6722cf0ac0fb04..ccdbc4eafde212ea6fd991c90c874b8296ffcf7c 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-head -n 7 $1 > .foo
-tail -n +8 $1 | grep  '[[:alnum:]]' | sort >> .foo
+head -n 6 $1 > .foo
+tail -n +7 $1 | grep  '[[:alnum:]]' | sort >> .foo
 echo >> .foo
 rm $1