]> granicus.if.org Git - ipset/commitdiff
Userspace revision handling is reworked
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Mon, 9 Oct 2017 16:43:04 +0000 (18:43 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Tue, 2 Jan 2018 20:47:27 +0000 (21:47 +0100)
In order to make it simpler and more straightforward to express
the revisions of the set type, all keywords and their parsing
are separated from the individual set types.

All backward compatibility arguments are recognized and ignored
arguments are supported.

Recognized but ignored arguments will be removed in a later release.

26 files changed:
Make_global.am
include/libipset/args.h [new file with mode: 0644]
include/libipset/types.h
lib/Makefile.am
lib/args.c [new file with mode: 0644]
lib/ipset_bitmap_ip.c
lib/ipset_bitmap_ipmac.c
lib/ipset_bitmap_port.c
lib/ipset_hash_ip.c
lib/ipset_hash_ipmac.c
lib/ipset_hash_ipmark.c
lib/ipset_hash_ipport.c
lib/ipset_hash_ipportip.c
lib/ipset_hash_ipportnet.c
lib/ipset_hash_mac.c
lib/ipset_hash_net.c
lib/ipset_hash_netiface.c
lib/ipset_hash_netnet.c
lib/ipset_hash_netport.c
lib/ipset_hash_netportnet.c
lib/ipset_list_set.c
lib/libipset.map
lib/parse.c
lib/session.c
lib/types.c
src/ipset.c

index f9d8dcaf67942a33edbf33025774d245ca341055..4b0ac11f0398b530e9448ff0efba296abbde871e 100644 (file)
@@ -69,7 +69,7 @@
 # interface. 
 
 #            curr:rev:age
-LIBVERSION = 10:0:7
+LIBVERSION = 11:0:0
 
 AM_CPPFLAGS = $(kinclude_CFLAGS) $(all_includes) -I$(top_srcdir)/include
 
diff --git a/include/libipset/args.h b/include/libipset/args.h
new file mode 100644 (file)
index 0000000..cdec180
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright 2017 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_ARGS_H
+#define LIBIPSET_ARGS_H
+
+/* Keywords */
+enum ipset_keywords {
+       IPSET_ARG_NONE = 0,
+       /* Family and aliases */
+       IPSET_ARG_FAMILY,                       /* family */
+       IPSET_ARG_INET,                         /* -4 */
+       IPSET_ARG_INET6,                        /* -6 */
+       /* Hash types */
+       IPSET_ARG_HASHSIZE,                     /* hashsize */
+       IPSET_ARG_MAXELEM,                      /* maxelem */
+       /* Ignored options: backward compatibilty */
+       IPSET_ARG_PROBES,                       /* probes */
+       IPSET_ARG_RESIZE,                       /* resize */
+       IPSET_ARG_GC,                           /* gc */
+       IPSET_ARG_IGNORED_FROM,                 /* from */
+       IPSET_ARG_IGNORED_TO,                   /* to */
+       IPSET_ARG_IGNORED_NETWORK,              /* network */
+       /* List type */
+       IPSET_ARG_SIZE,                         /* size */
+       /* IP-type elements */
+       IPSET_ARG_IPRANGE,                      /* range */
+       IPSET_ARG_NETMASK,                      /* netmask */
+       /* Port-type elements */
+       IPSET_ARG_PORTRANGE,                    /* range */
+       /* Setname type elements */
+       IPSET_ARG_BEFORE,                       /* before */
+       IPSET_ARG_AFTER,                        /* after */
+       /* Backward compatibility */
+       IPSET_ARG_FROM_IP,                      /* from */
+       IPSET_ARG_TO_IP,                        /* to */
+       IPSET_ARG_NETWORK,                      /* network */
+       IPSET_ARG_FROM_PORT,                    /* from */
+       IPSET_ARG_TO_PORT,                      /* to */
+       /* Extra flags, options */
+       IPSET_ARG_FORCEADD,                     /* forceadd */
+       IPSET_ARG_MARKMASK,                     /* markmask */
+       IPSET_ARG_NOMATCH,                      /* nomatch */
+       /* Extensions */
+       IPSET_ARG_TIMEOUT,                      /* timeout */
+       IPSET_ARG_COUNTERS,                     /* counters */
+       IPSET_ARG_PACKETS,                      /* packets */
+       IPSET_ARG_BYTES,                        /* bytes */
+       IPSET_ARG_COMMENT,                      /* comment */
+       IPSET_ARG_ADT_COMMENT,                  /* comment */
+       IPSET_ARG_SKBINFO,                      /* skbinfo */
+       IPSET_ARG_SKBMARK,                      /* skbmark */
+       IPSET_ARG_SKBPRIO,                      /* skbprio */
+       IPSET_ARG_SKBQUEUE,                     /* skbqueue */
+       IPSET_ARG_MAX,
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const struct ipset_arg * ipset_keyword(enum ipset_keywords i);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBIPSET_ARGS_H */
index 137d7ec1764a1f44a6df0c4460a9d241190a63cd..bb71d88dc383877dc8727e5a9d6ac60ca74c64b9 100644 (file)
@@ -10,6 +10,7 @@
 #include <stddef.h>                            /* NULL */
 #include <stdint.h>                            /* uintxx_t */
 
+#include <libipset/args.h>                     /* enum ipset_keywords */
 #include <libipset/data.h>                     /* enum ipset_opt */
 #include <libipset/parse.h>                    /* ipset_parsefn */
 #include <libipset/print.h>                    /* ipset_printfn */
@@ -47,6 +48,7 @@ struct ipset_arg {
        enum ipset_opt opt;             /* argumentum type */
        ipset_parsefn parse;            /* parser function */
        ipset_printfn print;            /* printing function */
+       const char *help;               /* help text */
 };
 
 /* Type check against the kernel */
@@ -63,6 +65,16 @@ struct ipset_elem {
        enum ipset_opt opt;                     /* elem option */
 };
 
+#define IPSET_OPTARG_MAX       24
+
+/* How other CADT args are parsed */
+struct ipset_optarg {
+       enum ipset_keywords args[IPSET_OPTARG_MAX];/* args */
+       uint64_t need;                          /* needed flags */
+       uint64_t full;                          /* all possible flags */
+       const char *help;                       /* help text */
+};
+
 /* The set types in userspace
  * we could collapse 'args' and 'mandatory' to two-element lists
  * but for the readability the full list is supported.
@@ -76,9 +88,7 @@ struct ipset_type {
        bool last_elem_optional;                /* last element optional */
        struct ipset_elem elem[IPSET_DIM_UMAX]; /* parse elem */
        ipset_parsefn compat_parse_elem;        /* compatibility parser */
-       const struct ipset_arg *args[IPSET_CADT_MAX]; /* create/ADT args besides elem */
-       uint64_t mandatory[IPSET_CADT_MAX];     /* create/ADT mandatory flags */
-       uint64_t full[IPSET_CADT_MAX];          /* full args flags */
+       struct ipset_optarg cmd[IPSET_CADT_MAX];/* optional arguments */
        const char *usage;                      /* terse usage */
        void (*usagefn)(void);                  /* additional usage */
        const char *description;                /* short revision description */
index 6990b0f43ef994c0ac39638ed6579845ecb350f4..d85d5bb239633c628eef69d54167def14b8b6a9d 100644 (file)
@@ -27,6 +27,7 @@ include $(top_srcdir)/lib/Make_extra.am
 libipset_la_LDFLAGS = -Wl,--version-script=$(top_srcdir)/lib/libipset.map -version-info $(LIBVERSION)
 libipset_la_LIBADD  = ${libmnl_LIBS} $(IPSET_SETTYPE_STATIC_OBJECTS) $(LIBADD_DLOPEN)
 libipset_la_SOURCES = \
+       args.c \
        data.c \
        errcode.c \
        icmp.c \
diff --git a/lib/args.c b/lib/args.c
new file mode 100644 (file)
index 0000000..5376ed0
--- /dev/null
@@ -0,0 +1,285 @@
+/* Copyright 2017 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/types.h>                    /* ipset_args[] */
+
+static const struct ipset_arg ipset_args[] = {
+       [IPSET_ARG_FAMILY] = {
+               .name = { "family", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_FAMILY,
+               .parse = ipset_parse_family,
+               .print = ipset_print_family,
+               .help = "[family inet|inet6]|[-4|-6]",
+       },
+       /* Alias: family inet */
+       [IPSET_ARG_INET] = {
+               .name = { "-4", NULL },
+               .has_arg = IPSET_NO_ARG,
+               .opt = IPSET_OPT_FAMILY,
+               .parse = ipset_parse_family,
+               .help = "",
+       },
+       /* Alias: family inet6 */
+       [IPSET_ARG_INET6] = {
+               .name = { "-6", NULL },
+               .has_arg = IPSET_NO_ARG,
+               .opt = IPSET_OPT_FAMILY,
+               .parse = ipset_parse_family,
+               .help = "",
+       },
+       /* Hash types */
+       [IPSET_ARG_HASHSIZE] = {
+               .name = { "hashsize", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_HASHSIZE,
+               .parse = ipset_parse_uint32,
+               .print = ipset_print_number,
+               .help = "[hashsize VALUE]",
+       },
+       [IPSET_ARG_MAXELEM] = {
+               .name = { "maxelem", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_MAXELEM,
+               .parse = ipset_parse_uint32,
+               .print = ipset_print_number,
+               .help = "[maxelem VALUE]",
+       },
+       /* Ignored options: backward compatibilty */
+       [IPSET_ARG_PROBES] = {
+               .name = { "probes", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_PROBES,
+               .parse = ipset_parse_ignored,
+               .print = ipset_print_number,
+       },
+       [IPSET_ARG_RESIZE] = {
+               .name = { "resize", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_RESIZE,
+               .parse = ipset_parse_ignored,
+               .print = ipset_print_number,
+       },
+       [IPSET_ARG_GC] = {
+               .name = { "gc", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_GC,
+               .parse = ipset_parse_ignored,
+               .print = ipset_print_number,
+       },
+       [IPSET_ARG_IGNORED_FROM] = {
+               .name = { "from", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_IP,
+               .parse = ipset_parse_ignored,
+               .print = ipset_print_number,
+       },
+       [IPSET_ARG_IGNORED_TO] = {
+               .name = { "to", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_IP_TO,
+               .parse = ipset_parse_ignored,
+               .print = ipset_print_number,
+       },
+       [IPSET_ARG_IGNORED_NETWORK] = {
+               .name = { "network", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_IP,
+               .parse = ipset_parse_ignored,
+               .print = ipset_print_number,
+       },
+       /* List type */
+       [IPSET_ARG_SIZE] = {
+               .name = { "size", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_SIZE,
+               .parse = ipset_parse_uint32,
+               .print = ipset_print_number,
+               .help = "[size VALUE]",
+       },
+       /* IP-type elements */
+       [IPSET_ARG_IPRANGE] = {
+               .name = { "range", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_IP,
+               .parse = ipset_parse_netrange,
+               .print = ipset_print_ip,
+       },
+       [IPSET_ARG_NETMASK] = {
+               .name = { "netmask", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_NETMASK,
+               .parse = ipset_parse_netmask,
+               .print = ipset_print_number,
+               .help = "[netmask CIDR]",
+       },
+       /* Port-type elements */
+       [IPSET_ARG_PORTRANGE] = {
+               .name = { "range", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_PORT,
+               .parse = ipset_parse_tcp_udp_port,
+               .print = ipset_print_port,
+       },
+       /* Setname type elements */
+       [IPSET_ARG_BEFORE] = {
+               .name = { "before", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_NAMEREF,
+               .parse = ipset_parse_before,
+               .help = "[before|after NAME]",
+       },
+       [IPSET_ARG_AFTER] = {
+               .name = { "after", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_NAMEREF,
+               .parse = ipset_parse_after,
+       },
+       /* Backward compatibility */
+       [IPSET_ARG_FROM_IP] = {
+               .name = { "from", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_IP,
+               .parse = ipset_parse_single_ip,
+       },
+       [IPSET_ARG_TO_IP] = {
+               .name = { "to", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_IP_TO,
+               .parse = ipset_parse_single_ip,
+       },
+       [IPSET_ARG_NETWORK] = {
+               .name = { "network", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_IP,
+               .parse = ipset_parse_net,
+       },
+       [IPSET_ARG_FROM_PORT] = {
+               .name = { "from", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_PORT,
+               .parse = ipset_parse_single_tcp_port,
+       },
+       [IPSET_ARG_TO_PORT] = {
+               .name = { "to", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_PORT_TO,
+               .parse = ipset_parse_single_tcp_port,
+       },
+       /* Extra flags, options */
+       [IPSET_ARG_FORCEADD] = {
+               .name = { "forceadd", NULL },
+               .has_arg = IPSET_NO_ARG,
+               .opt = IPSET_OPT_FORCEADD,
+               .parse = ipset_parse_flag,
+               .print = ipset_print_flag,
+               .help = "[forceadd]",
+       },
+       [IPSET_ARG_MARKMASK] = {
+               .name = { "markmask", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_MARKMASK,
+               .parse = ipset_parse_uint32,
+               .print = ipset_print_mark,
+               .help = "markmask VALUE",
+       },
+       [IPSET_ARG_NOMATCH] = {
+               .name = { "nomatch", NULL },
+               .has_arg = IPSET_NO_ARG,
+               .opt = IPSET_OPT_NOMATCH,
+               .parse = ipset_parse_flag,
+               .print = ipset_print_flag,
+               .help = "[nomatch]",
+       },
+       /* Extensions */
+       [IPSET_ARG_TIMEOUT] = {
+               .name = { "timeout", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_TIMEOUT,
+               .parse = ipset_parse_timeout,
+               .print = ipset_print_number,
+               .help = "[timeout VALUE]",
+       },
+       [IPSET_ARG_COUNTERS] = {
+               .name = { "counters", NULL },
+               .has_arg = IPSET_NO_ARG,
+               .opt = IPSET_OPT_COUNTERS,
+               .parse = ipset_parse_flag,
+               .print = ipset_print_flag,
+               .help = "[counters]",
+       },
+       [IPSET_ARG_PACKETS] = {
+               .name = { "packets", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_PACKETS,
+               .parse = ipset_parse_uint64,
+               .print = ipset_print_number,
+               .help = "[packets VALUE]",
+       },
+       [IPSET_ARG_BYTES] = {
+               .name = { "bytes", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_BYTES,
+               .parse = ipset_parse_uint64,
+               .print = ipset_print_number,
+               .help = "[bytes VALUE]",
+       },
+       [IPSET_ARG_COMMENT] = {
+               .name = { "comment", NULL },
+               .has_arg = IPSET_NO_ARG,
+               .opt = IPSET_OPT_CREATE_COMMENT,
+               .parse = ipset_parse_flag,
+               .print = ipset_print_flag,
+               .help = "[comment]",
+       },
+       [IPSET_ARG_ADT_COMMENT] = {
+               .name = { "comment", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_ADT_COMMENT,
+               .parse = ipset_parse_comment,
+               .print = ipset_print_comment,
+               .help = "[comment \"string\"]",
+       },
+       [IPSET_ARG_SKBINFO] = {
+               .name = { "skbinfo", NULL },
+               .has_arg = IPSET_NO_ARG,
+               .opt = IPSET_OPT_SKBINFO,
+               .parse = ipset_parse_flag,
+               .print = ipset_print_flag,
+               .help = "[skbinfo]",
+       },
+       [IPSET_ARG_SKBMARK] = {
+               .name = { "skbmark", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_SKBMARK,
+               .parse = ipset_parse_skbmark,
+               .print = ipset_print_skbmark,
+               .help = "[skbmark VALUE]",
+       },
+       [IPSET_ARG_SKBPRIO] = {
+               .name = { "skbprio", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_SKBPRIO,
+               .parse = ipset_parse_skbprio,
+               .print = ipset_print_skbprio,
+               .help = "[skbprio VALUE]",
+       },
+       [IPSET_ARG_SKBQUEUE] = {
+               .name = { "skbqueue", NULL },
+               .has_arg = IPSET_MANDATORY_ARG,
+               .opt = IPSET_OPT_SKBQUEUE,
+               .parse = ipset_parse_uint16,
+               .print = ipset_print_number,
+               .help = "[skbqueue VALUE]",
+       },
+};
+
+const struct ipset_arg * ipset_keyword(enum ipset_keywords i)
+{
+       return (i > IPSET_ARG_NONE && i < IPSET_ARG_MAX)
+                       ? &ipset_args[i] : NULL;
+}
index 7b4acab993e33c49d19fd6e40a88bb843035eff0..10dc3ae1399da9629366e92d0b442832cac10909 100644 (file)
@@ -9,53 +9,7 @@
 #include <libipset/print.h>                    /* printing functions */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_ip_create_args0[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_netrange,        .print = ipset_print_ip,
-       },
-       { .name = { "netmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NETMASK,
-         .parse = ipset_parse_netmask,         .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_net,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_ip_add_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char bitmap_ip_usage0[] =
-"create SETNAME bitmap:ip range IP/CIDR|FROM-TO\n"
-"               [netmask CIDR] [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\n"
-"where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 CIDR prefix.\n";
-
+/* Initial release */
 static struct ipset_type ipset_bitmap_ip0 = {
        .name = "bitmap:ip",
        .alias = { "ipmap", NULL },
@@ -69,94 +23,58 @@ static struct ipset_type ipset_bitmap_ip0 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_ip_create_args0,
-               [IPSET_ADD] = bitmap_ip_add_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [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_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_NETMASK)
-                       | 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),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_IPRANGE,
+                               IPSET_ARG_NETMASK,
+                               IPSET_ARG_TIMEOUT,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_IP,
+                               IPSET_ARG_TO_IP,
+                               IPSET_ARG_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "range IP/CIDR|FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP|IP/CIDR|FROM-TO",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP|IP/CIDR|FROM-TO",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP),
+                       .help = "IP",
+               },
        },
-
-       .usage = bitmap_ip_usage0,
+       .usage = "where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 CIDR prefix.",
        .description = "Initial revision",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_ip_create_args1[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_netrange,        .print = ipset_print_ip,
-       },
-       { .name = { "netmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NETMASK,
-         .parse = ipset_parse_netmask,         .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_net,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_ip_add_args1[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char bitmap_ip_usage1[] =
-"create SETNAME bitmap:ip range IP/CIDR|FROM-TO\n"
-"               [netmask CIDR] [timeout VALUE] [counters]\n"
-"add    SETNAME IP|IP/CIDR|FROM-TO [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME IP|IP/CIDR|FROM-TO\n"
-"test   SETNAME IP\n\n"
-"where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 CIDR prefix.\n";
-
+/* Counters support */
 static struct ipset_type ipset_bitmap_ip1 = {
        .name = "bitmap:ip",
        .alias = { "ipmap", NULL },
@@ -170,105 +88,61 @@ static struct ipset_type ipset_bitmap_ip1 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_ip_create_args1,
-               [IPSET_ADD] = bitmap_ip_add_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [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_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_NETMASK)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_IPRANGE,
+                               IPSET_ARG_NETMASK,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_IP,
+                               IPSET_ARG_TO_IP,
+                               IPSET_ARG_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "range IP/CIDR|FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP|IP/CIDR|FROM-TO",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP|IP/CIDR|FROM-TO",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP),
+                       .help = "IP",
+               },
        },
-
-       .usage = bitmap_ip_usage1,
+       .usage = "where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 CIDR prefix.",
        .description = "counters support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_ip_create_args2[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_netrange,        .print = ipset_print_ip,
-       },
-       { .name = { "netmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NETMASK,
-         .parse = ipset_parse_netmask,         .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_net,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_ip_add_args2[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const char bitmap_ip_usage2[] =
-"create SETNAME bitmap:ip range IP/CIDR|FROM-TO\n"
-"               [netmask CIDR] [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME IP|IP/CIDR|FROM-TO [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP|IP/CIDR|FROM-TO\n"
-"test   SETNAME IP\n\n"
-"where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 CIDR prefix.\n";
-
+/* Comment support */
 static struct ipset_type ipset_bitmap_ip2 = {
        .name = "bitmap:ip",
        .alias = { "ipmap", NULL },
@@ -282,125 +156,63 @@ static struct ipset_type ipset_bitmap_ip2 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_ip_create_args2,
-               [IPSET_ADD] = bitmap_ip_add_args2,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [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_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_NETMASK)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_IPRANGE,
+                               IPSET_ARG_NETMASK,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_IP,
+                               IPSET_ARG_TO_IP,
+                               IPSET_ARG_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "range IP/CIDR|FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP|IP/CIDR|FROM-TO",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP|IP/CIDR|FROM-TO",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP),
+                       .help = "IP",
+               },
        },
-
-       .usage = bitmap_ip_usage2,
+       .usage = "where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 CIDR prefix.",
        .description = "comment support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_ip_create_args3[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_netrange,        .print = ipset_print_ip,
-       },
-       { .name = { "netmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NETMASK,
-         .parse = ipset_parse_netmask,         .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_net,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_ip_add_args3[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char bitmap_ip_usage3[] =
-"create SETNAME bitmap:ip range IP/CIDR|FROM-TO\n"
-"               [netmask CIDR] [timeout VALUE] [counters] [comment]\n"
-"              [skbinfo]\n"
-"add    SETNAME IP|IP/CIDR|FROM-TO [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP|IP/CIDR|FROM-TO\n"
-"test   SETNAME IP\n\n"
-"where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 CIDR prefix.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_bitmap_ip3 = {
        .name = "bitmap:ip",
        .alias = { "ipmap", NULL },
@@ -414,42 +226,66 @@ static struct ipset_type ipset_bitmap_ip3 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_ip_create_args3,
-               [IPSET_ADD] = bitmap_ip_add_args3,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [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_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_NETMASK)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_IPRANGE,
+                               IPSET_ARG_NETMASK,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_SKBINFO,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_IP,
+                               IPSET_ARG_TO_IP,
+                               IPSET_ARG_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "range IP/CIDR|FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP|IP/CIDR|FROM-TO",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP|IP/CIDR|FROM-TO",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP),
+                       .help = "IP",
+               },
        },
-
-       .usage = bitmap_ip_usage3,
+       .usage = "where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 CIDR prefix.",
        .description = "skbinfo support",
 };
+
 void _init(void);
 void _init(void)
 {
index d193246f252accaae2ec8d9ed7cce7c76d7be493..e26cc69fca78fefa1abac69e1ba7f4f8dd32a6e6 100644 (file)
@@ -9,50 +9,7 @@
 #include <libipset/print.h>                    /* printing functions */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_ipmac_create_args0[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_netrange,        .print = ipset_print_ip,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_net,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_ipmac_add_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char bitmap_ipmac_usage0[] =
-"create SETNAME bitmap:ip,mac range IP/CIDR|FROM-TO\n"
-"               [matchunset] [timeout VALUE]\n"
-"add    SETNAME IP[,MAC] [timeout VALUE]\n"
-"del    SETNAME IP[,MAC]\n"
-"test   SETNAME IP[,MAC]\n\n"
-"where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 CIDR prefix,\n"
-"      MAC is a valid MAC address.\n";
-
+/* Initial release */
 static struct ipset_type ipset_bitmap_ipmac0 = {
        .name = "bitmap:ip,mac",
        .alias = { "macipmap", NULL },
@@ -72,91 +29,59 @@ static struct ipset_type ipset_bitmap_ipmac0 = {
                        .opt = IPSET_OPT_ETHER
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_ipmac_create_args0,
-               [IPSET_ADD] = bitmap_ipmac_add_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [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_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_IPRANGE,
+                               IPSET_ARG_TIMEOUT,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_IP,
+                               IPSET_ARG_TO_IP,
+                               IPSET_ARG_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "range IP/CIDR|FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
        },
-
-       .usage = bitmap_ipmac_usage0,
+       .usage = "where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 CIDR prefix.\n"
+                "      MAC is a valid MAC address.",
        .description = "Initial revision",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_ipmac_create_args1[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_netrange,        .print = ipset_print_ip,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_net,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_ipmac_add_args1[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char bitmap_ipmac_usage1[] =
-"create SETNAME bitmap:ip,mac range IP/CIDR|FROM-TO\n"
-"               [matchunset] [timeout VALUE] [counters]\n"
-"add    SETNAME IP[,MAC] [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME IP[,MAC]\n"
-"test   SETNAME IP[,MAC]\n\n"
-"where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 CIDR prefix,\n"
-"      MAC is a valid MAC address.\n";
-
+/* Counters support */
 static struct ipset_type ipset_bitmap_ipmac1 = {
        .name = "bitmap:ip,mac",
        .alias = { "macipmap", NULL },
@@ -176,102 +101,62 @@ static struct ipset_type ipset_bitmap_ipmac1 = {
                        .opt = IPSET_OPT_ETHER
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_ipmac_create_args1,
-               [IPSET_ADD] = bitmap_ipmac_add_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [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_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_IPRANGE,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_IP,
+                               IPSET_ARG_TO_IP,
+                               IPSET_ARG_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "range IP/CIDR|FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
        },
-
-       .usage = bitmap_ipmac_usage1,
+       .usage = "where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 CIDR prefix.\n"
+                "      MAC is a valid MAC address.",
        .description = "counters support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_ipmac_create_args2[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_netrange,        .print = ipset_print_ip,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_net,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_ipmac_add_args2[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const char bitmap_ipmac_usage2[] =
-"create SETNAME bitmap:ip,mac range IP/CIDR|FROM-TO\n"
-"               [matchunset] [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME IP[,MAC] [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP[,MAC]\n"
-"test   SETNAME IP[,MAC]\n\n"
-"where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 CIDR prefix,\n"
-"      MAC is a valid MAC address.\n";
-
+/* Comment support */
 static struct ipset_type ipset_bitmap_ipmac2 = {
        .name = "bitmap:ip,mac",
        .alias = { "macipmap", NULL },
@@ -291,122 +176,64 @@ static struct ipset_type ipset_bitmap_ipmac2 = {
                        .opt = IPSET_OPT_ETHER
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_ipmac_create_args2,
-               [IPSET_ADD] = bitmap_ipmac_add_args2,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [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_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_IPRANGE,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_IP,
+                               IPSET_ARG_TO_IP,
+                               IPSET_ARG_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "range IP/CIDR|FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
        },
-
-       .usage = bitmap_ipmac_usage2,
+       .usage = "where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 CIDR prefix.\n"
+                "      MAC is a valid MAC address.",
        .description = "comment support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_ipmac_create_args3[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_netrange,        .print = ipset_print_ip,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_single_ip,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_net,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_ipmac_add_args3[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char bitmap_ipmac_usage3[] =
-"create SETNAME bitmap:ip,mac range IP/CIDR|FROM-TO\n"
-"               [matchunset] [timeout VALUE] [counters] [comment]\n"
-"              [skbinfo]\n"
-"add    SETNAME IP[,MAC] [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP[,MAC]\n"
-"test   SETNAME IP[,MAC]\n\n"
-"where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 CIDR prefix,\n"
-"      MAC is a valid MAC address.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_bitmap_ipmac3 = {
        .name = "bitmap:ip,mac",
        .alias = { "macipmap", NULL },
@@ -426,40 +253,64 @@ static struct ipset_type ipset_bitmap_ipmac3 = {
                        .opt = IPSET_OPT_ETHER
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_ipmac_create_args3,
-               [IPSET_ADD] = bitmap_ipmac_add_args3,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [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_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_IPRANGE,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_SKBINFO,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_IP,
+                               IPSET_ARG_TO_IP,
+                               IPSET_ARG_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "range IP/CIDR|FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP[,MAC]",
+               },
        },
-
-       .usage = bitmap_ipmac_usage3,
+       .usage = "where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 CIDR prefix.\n"
+                "      MAC is a valid MAC address.",
        .description = "skbinfo support",
 };
 
index 1f1fe102f9d579bd05484464b8e8ff011364cb42..cbffdd1735d2dd81aeab4cfb03fb7b9d0439cc5c 100644 (file)
@@ -9,46 +9,7 @@
 #include <libipset/print.h>                    /* printing functions */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_port_create_args0[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT,
-         .parse = ipset_parse_tcp_udp_port,    .print = ipset_print_port,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT,
-         .parse = ipset_parse_single_tcp_port,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT_TO,
-         .parse = ipset_parse_single_tcp_port,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_port_add_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char bitmap_port_usage0[] =
-"create SETNAME bitmap:port range [PROTO:]FROM-TO\n"
-"               [timeout VALUE]\n"
-"add    SETNAME [PROTO:]PORT|FROM-TO [timeout VALUE]\n"
-"del    SETNAME [PROTO:]PORT|FROM-TO\n"
-"test   SETNAME [PROTO:]PORT\n\n"
-"where PORT, FROM and TO are port numbers or port names from /etc/services.\n"
-"PROTO is only needed if a service name is used and it does not exist as a TCP service;\n"
-"it isn't used otherwise with the bitmap.\n";
-
+/* Initial release */
 static struct ipset_type ipset_bitmap_port0 = {
        .name = "bitmap:port",
        .alias = { "portmap", NULL },
@@ -62,86 +23,57 @@ static struct ipset_type ipset_bitmap_port0 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_port_create_args0,
-               [IPSET_ADD] = bitmap_port_add_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_PORT),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_PORTRANGE,
+                               IPSET_ARG_TIMEOUT,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_PORT,
+                               IPSET_ARG_TO_PORT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "range [PROTO:]FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "[PROTO:]PORT|FROM-TO",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "[PROTO:]PORT|FROM-TO",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT),
+                       .help = "[PROTO:]PORT",
+               },
        },
-
-       .usage = bitmap_port_usage0,
+       .usage = "where PORT, FROM and TO are port numbers or port names from /etc/services.\n"
+                "      PROTO is only needed if a service name is used and it does not exist\n"
+                "      as a TCP service; it isn't used otherwise with the bitmap.",
        .description = "Initial revision",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_port_create_args1[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT,
-         .parse = ipset_parse_tcp_udp_port,    .print = ipset_print_port,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT,
-         .parse = ipset_parse_single_tcp_port,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT_TO,
-         .parse = ipset_parse_single_tcp_port,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_port_add_args1[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char bitmap_port_usage1[] =
-"create SETNAME bitmap:port range [PROTO:]FROM-TO\n"
-"               [timeout VALUE] [counters]\n"
-"add    SETNAME [PROTO:]PORT|FROM-TO [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME [PROTO:]PORT|FROM-TO\n"
-"test   SETNAME [PROTO:]PORT\n\n"
-"where PORT, FROM and TO are port numbers or port names from /etc/services.\n"
-"PROTO is only needed if a service name is used and it does not exist as a TCP service;\n"
-"it isn't used otherwise with the bitmap.\n";
-
+/* Counters support */
 static struct ipset_type ipset_bitmap_port1 = {
        .name = "bitmap:port",
        .alias = { "portmap", NULL },
@@ -155,97 +87,60 @@ static struct ipset_type ipset_bitmap_port1 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_port_create_args1,
-               [IPSET_ADD] = bitmap_port_add_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_PORT),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_PORTRANGE,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_PORT,
+                               IPSET_ARG_TO_PORT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "range [PROTO:]FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "[PROTO:]PORT|FROM-TO",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "[PROTO:]PORT|FROM-TO",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT),
+                       .help = "[PROTO:]PORT",
+               },
        },
-
-       .usage = bitmap_port_usage1,
+       .usage = "where PORT, FROM and TO are port numbers or port names from /etc/services.\n"
+                "      PROTO is only needed if a service name is used and it does not exist\n"
+                "      as a TCP service; it isn't used otherwise with the bitmap.",
        .description = "counters support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_port_create_args2[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT,
-         .parse = ipset_parse_tcp_udp_port,    .print = ipset_print_port,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT,
-         .parse = ipset_parse_single_tcp_port,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT_TO,
-         .parse = ipset_parse_single_tcp_port,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_port_add_args2[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const char bitmap_port_usage2[] =
-"create SETNAME bitmap:port range [PROTO:]FROM-TO\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME [PROTO:]PORT|FROM-TO [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME [PROTO:]PORT|FROM-TO\n"
-"test   SETNAME [PROTO:]PORT\n\n"
-"where PORT, FROM and TO are port numbers or port names from /etc/services.\n"
-"PROTO is only needed if a service name is used and it does not exist as a TCP service;\n"
-"it isn't used otherwise with the bitmap.\n";
-
+/* Comment support */
 static struct ipset_type ipset_bitmap_port2 = {
        .name = "bitmap:port",
        .alias = { "portmap", NULL },
@@ -259,116 +154,62 @@ static struct ipset_type ipset_bitmap_port2 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_port_create_args2,
-               [IPSET_ADD] = bitmap_port_add_args2,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_PORT),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_PORTRANGE,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_PORT,
+                               IPSET_ARG_TO_PORT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "range [PROTO:]FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "[PROTO:]PORT|FROM-TO",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "[PROTO:]PORT|FROM-TO",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT),
+                       .help = "[PROTO:]PORT",
+               },
        },
-
-       .usage = bitmap_port_usage2,
+       .usage = "where PORT, FROM and TO are port numbers or port names from /etc/services.\n"
+                "      PROTO is only needed if a service name is used and it does not exist\n"
+                "      as a TCP service; it isn't used otherwise with the bitmap.",
        .description = "comment support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg bitmap_port_create_args3[] = {
-       { .name = { "range", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT,
-         .parse = ipset_parse_tcp_udp_port,    .print = ipset_print_port,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .name = { "from", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT,
-         .parse = ipset_parse_single_tcp_port,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PORT_TO,
-         .parse = ipset_parse_single_tcp_port,
-       },
-       { },
-};
-
-static const struct ipset_arg bitmap_port_add_args3[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char bitmap_port_usage3[] =
-"create SETNAME bitmap:port range [PROTO:]FROM-TO\n"
-"               [timeout VALUE] [counters] [comment] [skbinfo]\n"
-"add    SETNAME [PROTO:]PORT|FROM-TO [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME [PROTO:]PORT|FROM-TO\n"
-"test   SETNAME [PROTO:]PORT\n\n"
-"where PORT, FROM and TO are port numbers or port names from /etc/services.\n"
-"PROTO is only needed if a service name is used and it does not exist as a TCP service;\n"
-"it isn't used otherwise with the bitmap.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_bitmap_port3 = {
        .name = "bitmap:port",
        .alias = { "portmap", NULL },
@@ -382,39 +223,62 @@ static struct ipset_type ipset_bitmap_port3 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = bitmap_port_create_args3,
-               [IPSET_ADD] = bitmap_port_add_args3,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_PORT),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_PORTRANGE,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_SKBINFO,
+                               /* Backward compatibility */
+                               IPSET_ARG_FROM_PORT,
+                               IPSET_ARG_TO_PORT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "range [PROTO:]FROM-TO",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "[PROTO:]PORT|FROM-TO",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "[PROTO:]PORT|FROM-TO",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_PORT),
+                       .help = "[PROTO:]PORT",
+               },
        },
-
-       .usage = bitmap_port_usage3,
+       .usage = "where PORT, FROM and TO are port numbers or port names from /etc/services.\n"
+                "      PROTO is only needed if a service name is used and it does not exist\n"
+                "      as a TCP service; it isn't used otherwise with the bitmap.",
        .description = "skbinfo support",
 };
 
index 2bff34fc6a0d112980f6c38f3840c8178f3faba4..a125eff41ad8eff172c12d91ac5c6691e6f7a9a7 100644 (file)
@@ -9,76 +9,7 @@
 #include <libipset/print.h>                    /* printing functions */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ip_create_args0[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "netmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NETMASK,
-         .parse = ipset_parse_netmask,         .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .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_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_ip_usage0[] =
-"create SETNAME hash:ip\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [netmask CIDR] [timeout VALUE]\n"
-"add    SETNAME IP [timeout VALUE]\n"
-"del    SETNAME IP\n"
-"test   SETNAME IP\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n";
-
+/* Initial release */
 static struct ipset_type ipset_hash_ip0 = {
        .name = "hash:ip",
        .alias = { "iphash", NULL },
@@ -92,117 +23,65 @@ static struct ipset_type ipset_hash_ip0 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ip_create_args0,
-               [IPSET_ADD] = hash_ip_add_args0,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_NETMASK)
-                       | 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),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_NETMASK,
+                               IPSET_ARG_TIMEOUT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_GC,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
        },
-
-       .usage = hash_ip_usage0,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.",
        .description = "Initial revision",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ip_create_args1[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "netmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NETMASK,
-         .parse = ipset_parse_netmask,         .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* 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_args1[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_ip_usage1[] =
-"create SETNAME hash:ip\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [netmask CIDR] [timeout VALUE]\n"
-"               [counters]\n"
-"add    SETNAME IP [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME IP\n"
-"test   SETNAME IP\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n";
-
+/* Counters support */
 static struct ipset_type ipset_hash_ip1 = {
        .name = "hash:ip",
        .alias = { "iphash", NULL },
@@ -216,128 +95,68 @@ static struct ipset_type ipset_hash_ip1 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ip_create_args1,
-               [IPSET_ADD] = hash_ip_add_args1,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_NETMASK)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_NETMASK,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_GC,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
        },
-
-       .usage = hash_ip_usage1,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.",
        .description = "counters support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ip_create_args2[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "netmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NETMASK,
-         .parse = ipset_parse_netmask,         .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* 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_args2[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const char hash_ip_usage2[] =
-"create SETNAME hash:ip\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [netmask CIDR] [timeout VALUE]\n"
-"               [counters] [comment]\n"
-"add    SETNAME IP [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP\n"
-"test   SETNAME IP\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n";
-
+/* Comment support */
 static struct ipset_type ipset_hash_ip2 = {
        .name = "hash:ip",
        .alias = { "iphash", NULL },
@@ -351,114 +170,70 @@ static struct ipset_type ipset_hash_ip2 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ip_create_args2,
-               [IPSET_ADD] = hash_ip_add_args2,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_NETMASK)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_NETMASK,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_GC,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
        },
-
-       .usage = hash_ip_usage2,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.",
        .description = "comment support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ip_create_args3[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "netmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NETMASK,
-         .parse = ipset_parse_netmask,         .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* 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 char hash_ip_usage3[] =
-"create SETNAME hash:ip\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [netmask CIDR] [timeout VALUE]\n"
-"               [counters] [comment] [forceadd]\n"
-"add    SETNAME IP [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP\n"
-"test   SETNAME IP\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n";
-
+/* Forceadd support */
 static struct ipset_type ipset_hash_ip3 = {
        .name = "hash:ip",
        .alias = { "iphash", NULL },
@@ -472,153 +247,71 @@ static struct ipset_type ipset_hash_ip3 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ip_create_args3,
-               [IPSET_ADD] = hash_ip_add_args2,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_NETMASK)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_NETMASK,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_GC,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
        },
-
-       .usage = hash_ip_usage3,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.",
        .description = "forceadd support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ip_create_args4[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "netmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NETMASK,
-         .parse = ipset_parse_netmask,         .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* 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_args4[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-
-static const char hash_ip_usage4[] =
-"create SETNAME hash:ip\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [netmask CIDR] [timeout VALUE]\n"
-"               [counters] [comment] [forceadd] [skbinfo]\n"
-"add    SETNAME IP [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP\n"
-"test   SETNAME IP\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_hash_ip4 = {
        .name = "hash:ip",
        .alias = { "iphash", NULL },
@@ -632,40 +325,71 @@ static struct ipset_type ipset_hash_ip4 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ip_create_args4,
-               [IPSET_ADD] = hash_ip_add_args4,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_NETMASK)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_NETMASK,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_GC,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP",
+               },
        },
-
-       .usage = hash_ip_usage4,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.",
        .description = "skbinfo support",
 };
 
index 8b34a10b2112de8dfa51b55c66a24cd6e70ddf5a..c64e1bea36447bb24d525f6982b7e8d62ac2976c 100644 (file)
@@ -9,98 +9,7 @@
 #include <libipset/print.h>                    /* printing functions */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipmac_create_args0[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipmac_add_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-
-static const char hash_ipmac_usage0[] =
-"create SETNAME hash:ip,mac\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"               [counters] [comment] [forceadd] [skbinfo]\n"
-"add    SETNAME IP,MAC [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP,MAC\n"
-"test   SETNAME IP,MAC\n";
-
+/* Initial revision */
 static struct ipset_type ipset_hash_ipmac0 = {
        .name = "hash:ip,mac",
        .alias = { "ipmachash", NULL },
@@ -119,43 +28,66 @@ static struct ipset_type ipset_hash_ipmac0 = {
                        .opt = IPSET_OPT_ETHER
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipmac_create_args0,
-               [IPSET_ADD] = hash_ipmac_add_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_ETHER),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP,MAC",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP,MAC",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "IP,MAC",
+               },
        },
-
-       .usage = hash_ipmac_usage0,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      MAC is a MAC address.",
        .description = "Initial revision",
 };
 
index 8e1a596e7c2d7b4b1c73b4fc4bb19fcf263c5fca..33009f5b69548368f0f977c94186ce311315e555 100644 (file)
 #include <libipset/print.h>                    /* printing functions */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipmark_create_args0[] = {
-       { .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 = { "markmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MARKMASK,
-         .parse = ipset_parse_uint32,          .print = ipset_print_mark,
-       },
-       { .name = { "hashsize", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_HASHSIZE,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "maxelem", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipmark_add_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const char hash_ipmark_usage0[] =
-"create SETNAME hash:ip,mark\n"
-"              [family inet|inet6] [markmask VALUE]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME IP,MARK [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP,MARK\n"
-"test   SETNAME IP,MARK\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n"
-"      Adding/deleting single mark element\n"
-"      is supported both for IPv4 and IPv6.\n";
-
+/* Initial release */
 static struct ipset_type ipset_hash_ipmark0 = {
        .name = "hash:ip,mark",
        .alias = { "ipmarkhash", NULL },
@@ -128,128 +29,79 @@ static struct ipset_type ipset_hash_ipmark0 = {
                        .opt = IPSET_OPT_MARK
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipmark_create_args0,
-               [IPSET_ADD] = hash_ipmark_add_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_MARKMASK)
-                       | IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_MARK)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_MARKMASK,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .help = "IP,MARK",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .help = "IP,MARK",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .help = "IP,MARK",
+               },
        },
-
-       .usage = hash_ipmark_usage0,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.\n"
+                "      Adding/deleting single mark element\n"
+                "      is supported both for IPv4 and IPv6.",
        .description = "initial revision",
 };
 
-static const struct ipset_arg hash_ipmark_create_args1[] = {
-       { .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 = { "markmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MARKMASK,
-         .parse = ipset_parse_uint32,          .print = ipset_print_mark,
-       },
-       { .name = { "hashsize", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_HASHSIZE,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "maxelem", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const char hash_ipmark_usage1[] =
-"create SETNAME hash:ip,mark\n"
-"              [family inet|inet6] [markmask VALUE]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd]\n"
-"add    SETNAME IP,MARK [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP,MARK\n"
-"test   SETNAME IP,MARK\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n"
-"      Adding/deleting single mark element\n"
-"      is supported both for IPv4 and IPv6.\n";
-
+/* Forceadd support */
 static struct ipset_type ipset_hash_ipmark1 = {
        .name = "hash:ip,mark",
        .alias = { "ipmarkhash", NULL },
@@ -268,167 +120,80 @@ static struct ipset_type ipset_hash_ipmark1 = {
                        .opt = IPSET_OPT_MARK
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipmark_create_args1,
-               [IPSET_ADD] = hash_ipmark_add_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_MARKMASK)
-                       | IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_MARK)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-       },
-
-       .usage = hash_ipmark_usage1,
-       .description = "forceadd support"
-};
-
-static const struct ipset_arg hash_ipmark_create_args2[] = {
-       { .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 = { "markmask", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MARKMASK,
-         .parse = ipset_parse_uint32,          .print = ipset_print_mark,
-       },
-       { .name = { "hashsize", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_HASHSIZE,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "maxelem", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipmark_add_args2[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_MARKMASK,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .help = "IP,MARK",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .help = "IP,MARK",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .help = "IP,MARK",
+               },
        },
-       { },
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.\n"
+                "      Adding/deleting single mark element\n"
+                "      is supported both for IPv4 and IPv6.",
+       .description = "forceadd support",
 };
 
-
-static const char hash_ipmark_usage2[] =
-"create SETNAME hash:ip,mark\n"
-"              [family inet|inet6] [markmask VALUE]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd] [skbinfo]\n"
-"add    SETNAME IP,MARK [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP,MARK\n"
-"test   SETNAME IP,MARK\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n"
-"      Adding/deleting single mark element\n"
-"      is supported both for IPv4 and IPv6.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_hash_ipmark2 = {
        .name = "hash:ip,mark",
        .alias = { "ipmarkhash", NULL },
@@ -447,47 +212,81 @@ static struct ipset_type ipset_hash_ipmark2 = {
                        .opt = IPSET_OPT_MARK
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipmark_create_args2,
-               [IPSET_ADD] = hash_ipmark_add_args2,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_MARKMASK)
-                       | IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_MARK)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_MARK),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_MARKMASK,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .help = "IP,MARK",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .help = "IP,MARK",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_MARK),
+                       .help = "IP,MARK",
+               },
        },
-
-       .usage = hash_ipmark_usage2,
-       .description = "sbkinfo support"
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.\n"
+                "      Adding/deleting single mark element\n"
+                "      is supported both for IPv4 and IPv6.",
+       .description = "skbinfo support",
 };
 
 void _init(void);
index 21669220f377536d857e147a928024d4d82f75dd..870a02a76074cf31ebdda1134a27622340e57fca 100644 (file)
 #include <libipset/ui.h>                       /* ipset_port_usage */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipport_create_args1[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipport_add_args1[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_ipport_usage1[] =
-"create SETNAME hash:ip,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP,PROTO:PORT [timeout VALUE]\n"
-"del    SETNAME IP,PROTO:PORT\n"
-"test   SETNAME IP,PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* SCTP and UDPLITE support */
 static struct ipset_type ipset_hash_ipport1 = {
        .name = "hash:ip,port",
        .alias = { "ipporthash", NULL },
@@ -103,135 +29,81 @@ static struct ipset_type ipset_hash_ipport1 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipport_create_args1,
-               [IPSET_ADD] = hash_ipport_add_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "IP,[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "IP,[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .help = "IP,[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_ipport_usage1,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "SCTP and UDPLITE support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipport_create_args2[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipport_add_args2[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_ipport_usage2[] =
-"create SETNAME hash:ip,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters]\n"
-"add    SETNAME IP,PROTO:PORT [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME IP,PROTO:PORT\n"
-"test   SETNAME IP,PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* counters support */
 static struct ipset_type ipset_hash_ipport2 = {
        .name = "hash:ip,port",
        .alias = { "ipporthash", NULL },
@@ -250,146 +122,84 @@ static struct ipset_type ipset_hash_ipport2 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipport_create_args2,
-               [IPSET_ADD] = hash_ipport_add_args2,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "IP,[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "IP,[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .help = "IP,[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_ipport_usage2,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "counters support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipport_create_args3[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipport_add_args3[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const char hash_ipport_usage3[] =
-"create SETNAME hash:ip,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME IP,PROTO:PORT [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP,PROTO:PORT\n"
-"test   SETNAME IP,PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* comment support */
 static struct ipset_type ipset_hash_ipport3 = {
        .name = "hash:ip,port",
        .alias = { "ipporthash", NULL },
@@ -408,133 +218,86 @@ static struct ipset_type ipset_hash_ipport3 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipport_create_args3,
-               [IPSET_ADD] = hash_ipport_add_args3,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "IP,[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "IP,[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .help = "IP,[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_ipport_usage3,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "comment support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipport_create_args4[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const char hash_ipport_usage4[] =
-"create SETNAME hash:ip,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd]\n"
-"add    SETNAME IP,PROTO:PORT [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP,PROTO:PORT\n"
-"test   SETNAME IP,PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* forceadd support */
 static struct ipset_type ipset_hash_ipport4 = {
        .name = "hash:ip,port",
        .alias = { "ipporthash", NULL },
@@ -553,171 +316,87 @@ static struct ipset_type ipset_hash_ipport4 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipport_create_args4,
-               [IPSET_ADD] = hash_ipport_add_args3,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "IP,[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "IP,[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .help = "IP,[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_ipport_usage4,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "forceadd support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipport_create_args5[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipport_add_args5[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_ipport_usage5[] =
-"create SETNAME hash:ip,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd] [skbinfo]\n"
-"add    SETNAME IP,PROTO:PORT [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP,PROTO:PORT\n"
-"test   SETNAME IP,PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      is supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_hash_ipport5 = {
        .name = "hash:ip,port",
        .alias = { "ipporthash", NULL },
@@ -736,53 +415,86 @@ static struct ipset_type ipset_hash_ipport5 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipport_create_args5,
-               [IPSET_ADD] = hash_ipport_add_args5,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "IP,[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO),
+                       .help = "IP,[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .help = "IP,[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_ipport_usage5,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "skbinfo support",
 };
index 5eeb24515e228a52e4d5fde9ae51200753577914..c7fc1530c3d058486d44904681f229d963ac5e13 100644 (file)
 #include <libipset/ui.h>                       /* ipset_port_usage */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipportip_create_args1[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipportip_add_args1[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_ipportip_usage1[] =
-"create SETNAME hash:ip,port,ip\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP,PROTO:PORT,IP [timeout VALUE]\n"
-"del    SETNAME IP,PROTO:PORT,IP\n"
-"test   SETNAME IP,PROTO:PORT,IP\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in the first IP component is supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* SCTP and UDPLITE support */
 static struct ipset_type ipset_hash_ipportip1 = {
        .name = "hash:ip,port,ip",
        .alias = { "ipportiphash", NULL },
@@ -108,141 +34,87 @@ static struct ipset_type ipset_hash_ipportip1 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportip_create_args1,
-               [IPSET_ADD] = hash_ipportip_add_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
        },
-
-       .usage = hash_ipportip_usage1,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "SCTP and UDPLITE support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipportip_create_args2[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipportip_add_args2[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_ipportip_usage2[] =
-"create SETNAME hash:ip,port,ip\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters]\n"
-"add    SETNAME IP,PROTO:PORT,IP [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME IP,PROTO:PORT,IP\n"
-"test   SETNAME IP,PROTO:PORT,IP\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in the first IP component is supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* counters support */
 static struct ipset_type ipset_hash_ipportip2 = {
        .name = "hash:ip,port,ip",
        .alias = { "ipportiphash", NULL },
@@ -266,152 +138,90 @@ static struct ipset_type ipset_hash_ipportip2 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportip_create_args2,
-               [IPSET_ADD] = hash_ipportip_add_args2,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
        },
-
-       .usage = hash_ipportip_usage2,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "counters support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipportip_create_args3[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipportip_add_args3[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const char hash_ipportip_usage3[] =
-"create SETNAME hash:ip,port,ip\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME IP,PROTO:PORT,IP [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP,PROTO:PORT,IP\n"
-"test   SETNAME IP,PROTO:PORT,IP\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in the first IP component is supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* comment support */
 static struct ipset_type ipset_hash_ipportip3 = {
        .name = "hash:ip,port,ip",
        .alias = { "ipportiphash", NULL },
@@ -435,139 +245,92 @@ static struct ipset_type ipset_hash_ipportip3 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportip_create_args3,
-               [IPSET_ADD] = hash_ipportip_add_args3,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
        },
-
-       .usage = hash_ipportip_usage3,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "comment support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipportip_create_args4[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const char hash_ipportip_usage4[] =
-"create SETNAME hash:ip,port,ip\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd]\n"
-"add    SETNAME IP,PROTO:PORT,IP [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP,PROTO:PORT,IP\n"
-"test   SETNAME IP,PROTO:PORT,IP\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in the first IP component is supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* forceadd support */
 static struct ipset_type ipset_hash_ipportip4 = {
        .name = "hash:ip,port,ip",
        .alias = { "ipportiphash", NULL },
@@ -591,177 +354,93 @@ static struct ipset_type ipset_hash_ipportip4 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportip_create_args4,
-               [IPSET_ADD] = hash_ipportip_add_args3,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
        },
-
-       .usage = hash_ipportip_usage4,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "forceadd support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipportip_create_args5[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipportip_add_args5[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_ipportip_usage5[] =
-"create SETNAME hash:ip,port,ip\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd] [skbinfo]\n"
-"add    SETNAME IP,PROTO:PORT,IP [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP,PROTO:PORT,IP\n"
-"test   SETNAME IP,PROTO:PORT,IP\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in the first IP component is supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_hash_ipportip5 = {
        .name = "hash:ip,port,ip",
        .alias = { "ipportiphash", NULL },
@@ -785,59 +464,92 @@ static struct ipset_type ipset_hash_ipportip5 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportip_create_args5,
-               [IPSET_ADD] = hash_ipportip_add_args5,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .help = "IP,[PROTO:]PORT,IP",
+               },
        },
-
-       .usage = hash_ipportip_usage5,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname).\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "skbinfo support",
 };
index bd394de27598f1b8eae15edfbd689ce1b0dea71a..e0e9eb16110d0bedca67b668f71253c76b8e308c 100644 (file)
 #include <libipset/ui.h>                       /* ipset_port_usage */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipportnet_create_args1[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipportnet_add_args1[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_ipportnet_usage1[] =
-"create SETNAME hash:ip,port,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE]\n"
-"del    SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
-"test   SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in the first IP component is supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* SCTP and UDPLITE support */
 static struct ipset_type ipset_hash_ipportnet1 = {
        .name = "hash:ip,port,net",
        .alias = { "ipportnethash", NULL },
@@ -109,74 +34,91 @@ static struct ipset_type ipset_hash_ipportnet1 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportnet_create_args1,
-               [IPSET_ADD] = hash_ipportnet_add_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
        },
-
-       .usage = hash_ipportnet_usage1,
+       .usage = "where depending on the INET family\n"
+                "      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "SCTP and UDPLITE support",
 };
 
-static const char hash_ipportnet_usage2[] =
-"create SETNAME hash:ip,port,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE]\n"
-"del    SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
-"test   SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in both IP components are supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* Add/del range support */
 static struct ipset_type ipset_hash_ipportnet2 = {
        .name = "hash:ip,port,net",
        .alias = { "ipportnethash", NULL },
@@ -200,88 +142,93 @@ static struct ipset_type ipset_hash_ipportnet2 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportnet_create_args1,
-               [IPSET_ADD] = hash_ipportnet_add_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
        },
-
-       .usage = hash_ipportnet_usage2,
+       .usage = "where depending on the INET family\n"
+                "      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "Add/del range support",
 };
 
-static const struct ipset_arg hash_ipportnet_add_args3[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_ipportnet_usage3[] =
-"create SETNAME hash:ip,port,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE] [nomatch]\n"
-"del    SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
-"test   SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in both IP components are supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* nomatch flag support */
 static struct ipset_type ipset_hash_ipportnet3 = {
        .name = "hash:ip,port,net",
        .alias = { "ipportnethash", NULL },
@@ -305,162 +252,95 @@ static struct ipset_type ipset_hash_ipportnet3 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportnet_create_args1,
-               [IPSET_ADD] = hash_ipportnet_add_args3,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
        },
-
-       .usage = hash_ipportnet_usage3,
+       .usage = "where depending on the INET family\n"
+                "      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "nomatch flag support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipportnet_create_args4[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipportnet_add_args4[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipportnet_test_args4[] = {
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_ipportnet_usage4[] =
-"create SETNAME hash:ip,port,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters]\n"
-"add    SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
-"test   SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in both IP components are supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* counters support */
 static struct ipset_type ipset_hash_ipportnet4 = {
        .name = "hash:ip,port,net",
        .alias = { "ipportnethash", NULL },
@@ -484,175 +364,98 @@ static struct ipset_type ipset_hash_ipportnet4 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportnet_create_args4,
-               [IPSET_ADD] = hash_ipportnet_add_args4,
-               [IPSET_TEST] = hash_ipportnet_test_args4,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
        },
-
-       .usage = hash_ipportnet_usage4,
+       .usage = "where depending on the INET family\n"
+                "      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "counters support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipportnet_create_args5[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipportnet_add_args5[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipportnet_test_args5[] = {
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_ipportnet_usage5[] =
-"create SETNAME hash:ip,port,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
-"test   SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in both IP components are supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* comment support */
 static struct ipset_type ipset_hash_ipportnet5 = {
        .name = "hash:ip,port,net",
        .alias = { "ipportnethash", NULL },
@@ -676,150 +479,100 @@ static struct ipset_type ipset_hash_ipportnet5 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportnet_create_args5,
-               [IPSET_ADD] = hash_ipportnet_add_args5,
-               [IPSET_TEST] = hash_ipportnet_test_args5,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
        },
-
-       .usage = hash_ipportnet_usage5,
+       .usage = "where depending on the INET family\n"
+                "      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "comment support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipportnet_create_args6[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const char hash_ipportnet_usage6[] =
-"create SETNAME hash:ip,port,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd]\n"
-"add    SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
-"test   SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in both IP components are supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* forceadd support */
 static struct ipset_type ipset_hash_ipportnet6 = {
        .name = "hash:ip,port,net",
        .alias = { "ipportnethash", NULL },
@@ -843,192 +596,101 @@ static struct ipset_type ipset_hash_ipportnet6 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportnet_create_args6,
-               [IPSET_ADD] = hash_ipportnet_add_args5,
-               [IPSET_TEST] = hash_ipportnet_test_args5,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
        },
-
-       .usage = hash_ipportnet_usage6,
+       .usage = "where depending on the INET family\n"
+                "      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "forceadd support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_ipportnet_create_args7[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* Backward compatibility */
-       { .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_ignored,
-       },
-       { .name = { "to", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP_TO,
-         .parse = ipset_parse_ignored,
-       },
-       { .name = { "network", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_IP,
-         .parse = ipset_parse_ignored,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_ipportnet_add_args7[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_ipportnet_usage7[] =
-"create SETNAME hash:ip,port,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd] [skbinfo]\n"
-"add    SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
-"test   SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in both IP components are supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_hash_ipportnet7 = {
        .name = "hash:ip,port,net",
        .alias = { "ipportnethash", NULL },
@@ -1052,69 +714,100 @@ static struct ipset_type ipset_hash_ipportnet7 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_ipportnet_create_args6,
-               [IPSET_ADD] = hash_ipportnet_add_args5,
-               [IPSET_TEST] = hash_ipportnet_test_args5,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_IGNORED_FROM,
+                               IPSET_ARG_IGNORED_TO,
+                               IPSET_ARG_IGNORED_NETWORK,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP,[PROTO:]PORT,IP[/CIDR]",
+               },
        },
-
-       .usage = hash_ipportnet_usage7,
+       .usage = "where depending on the INET family\n"
+                "      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in the first IP component is supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "skbinfo support",
 };
index 30be160831cdda059bdc338571b739abbdeefe5d..b80ce881943ba96f38af6518656ba05563a12951 100644 (file)
@@ -9,83 +9,7 @@
 #include <libipset/print.h>                    /* printing functions */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_mac_create_args0[] = {
-       { .name = { "hashsize", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_HASHSIZE,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "maxelem", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_mac_add_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-
-static const char hash_mac_usage0[] =
-"create SETNAME hash:mac\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"               [counters] [comment] [forceadd] [skbinfo]\n"
-"add    SETNAME MAC [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME MAC\n"
-"test   SETNAME MAC\n";
-
+/* Initial revision */
 static struct ipset_type ipset_hash_mac0 = {
        .name = "hash:mac",
        .alias = { "machash", NULL },
@@ -99,37 +23,55 @@ static struct ipset_type ipset_hash_mac0 = {
                        .opt = IPSET_OPT_ETHER
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_mac_create_args0,
-               [IPSET_ADD] = hash_mac_add_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_ETHER),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_ETHER),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_ETHER),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_ETHER)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_ETHER),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_ETHER),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_ETHER),
+                       .full = IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "MAC",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_ETHER),
+                       .full = IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "MAC",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_ETHER),
+                       .full = IPSET_FLAG(IPSET_OPT_ETHER),
+                       .help = "MAC",
+               },
        },
-
-       .usage = hash_mac_usage0,
+       .usage = "",
        .description = "Initial revision",
 };
 
index 0dd5578159c945448c7bccd58e8b9d835df827c1..01371dbd64b2471167e9f40a627323dd41a72e11 100644 (file)
@@ -9,66 +9,7 @@
 #include <libipset/print.h>                    /* printing functions */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_net_create_args0[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .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,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_net_add_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_net_usage0[] =
-"create SETNAME hash:net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP[/CIDR] [timeout VALUE]\n"
-"del    SETNAME IP[/CIDR]\n"
-"test   SETNAME IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP is an IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n";
-
+/* Initial revision */
 static struct ipset_type ipset_hash_net0 = {
        .name = "hash:net",
        .alias = { "nethash", NULL },
@@ -82,46 +23,61 @@ static struct ipset_type ipset_hash_net0 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_net_create_args0,
-               [IPSET_ADD] = hash_net_add_args0,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR]",
+               },
        },
-
-       .usage = hash_net_usage0,
+       .usage = "where depending on the INET family\n"
+                "      IP is an IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.",
        .description = "Initial revision",
 };
 
-static const char hash_net_usage1[] =
-"create SETNAME hash:net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO [timeout VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO\n"
-"test   SETNAME IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP is an IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      IP range is not supported with IPv6.\n";
-
+/* Add/del range support */
 static struct ipset_type ipset_hash_net1 = {
        .name = "hash:net",
        .alias = { "nethash", NULL },
@@ -135,60 +91,63 @@ static struct ipset_type ipset_hash_net1 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_net_create_args0,
-               [IPSET_ADD] = hash_net_add_args0,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR]",
+               },
        },
-
-       .usage = hash_net_usage1,
+       .usage = "where depending on the INET family\n"
+                "      IP is an IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.",
        .description = "Add/del range support",
 };
 
-static const struct ipset_arg hash_net_add_args2[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_net_usage2[] =
-"create SETNAME hash:net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO [timeout VALUE] [nomatch]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO\n"
-"test   SETNAME IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP is an IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      IP range is not supported with IPv6.\n";
-
+/* nomatch flag support */
 static struct ipset_type ipset_hash_net2 = {
        .name = "hash:net",
        .alias = { "nethash", NULL },
@@ -202,122 +161,65 @@ static struct ipset_type ipset_hash_net2 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_net_create_args0,
-               [IPSET_ADD] = hash_net_add_args2,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR]",
+               },
        },
-
-       .usage = hash_net_usage2,
+       .usage = "where depending on the INET family\n"
+                "      IP is an IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.",
        .description = "nomatch flag support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_net_create_args3[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* 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,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_net_add_args3[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_net_test_args3[] = {
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_net_usage3[] =
-"create SETNAME hash:net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO\n"
-"test   SETNAME IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP is an IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      IP range is not supported with IPv6.\n";
-
+/* counters support */
 static struct ipset_type ipset_hash_net3 = {
        .name = "hash:net",
        .alias = { "nethash", NULL },
@@ -331,135 +233,68 @@ static struct ipset_type ipset_hash_net3 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_net_create_args3,
-               [IPSET_ADD] = hash_net_add_args3,
-               [IPSET_TEST] = hash_net_test_args3,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR]",
+               },
        },
-
-       .usage = hash_net_usage3,
+       .usage = "where depending on the INET family\n"
+                "      IP is an IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.",
        .description = "counters support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_net_create_args4[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* 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,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_net_add_args4[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_net_test_args4[] = {
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_net_usage4[] =
-"create SETNAME hash:net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO\n"
-"test   SETNAME IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP is an IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      IP range is not supported with IPv6.\n";
-
+/* comment support */
 static struct ipset_type ipset_hash_net4 = {
        .name = "hash:net",
        .alias = { "nethash", NULL },
@@ -473,110 +308,70 @@ static struct ipset_type ipset_hash_net4 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_net_create_args4,
-               [IPSET_ADD] = hash_net_add_args4,
-               [IPSET_TEST] = hash_net_test_args4,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR]",
+               },
        },
-
-       .usage = hash_net_usage4,
+       .usage = "where depending on the INET family\n"
+                "      IP is an IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.",
        .description = "comment support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_net_create_args5[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* 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,
-       },
-       { },
-};
-
-static const char hash_net_usage5[] =
-"create SETNAME hash:net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO\n"
-"test   SETNAME IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP is an IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      IP range is not supported with IPv6.\n";
-
+/* forceadd support */
 static struct ipset_type ipset_hash_net5 = {
        .name = "hash:net",
        .alias = { "nethash", NULL },
@@ -590,154 +385,71 @@ static struct ipset_type ipset_hash_net5 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_net_create_args5,
-               [IPSET_ADD] = hash_net_add_args4,
-               [IPSET_TEST] = hash_net_test_args4,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR]",
+               },
        },
-
-       .usage = hash_net_usage5,
+       .usage = "where depending on the INET family\n"
+                "      IP is an IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.",
        .description = "forceadd support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_net_create_args6[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       /* 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,
-       },
-       { },
-};
-
-
-static const struct ipset_arg hash_net_add_args6[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         . has_arg = IPSET_MANDATORY_ARG,      .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-
-static const char hash_net_usage6[] =
-"create SETNAME hash:net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [skbinfo] [forceadd]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE/VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO\n"
-"test   SETNAME IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP is an IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      IP range is not supported with IPv6.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_hash_net6 = {
        .name = "hash:net",
        .alias = { "nethash", NULL },
@@ -751,45 +463,71 @@ static struct ipset_type ipset_hash_net6 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_net_create_args6,
-               [IPSET_ADD] = hash_net_add_args6,
-               [IPSET_TEST] = hash_net_test_args4,
-       },
-       .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_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                               /* Ignored options: backward compatibilty */
+                               IPSET_ARG_PROBES,
+                               IPSET_ARG_RESIZE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR]",
+               },
        },
-
-       .usage = hash_net_usage6,
+       .usage = "where depending on the INET family\n"
+                "      IP is an IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.",
        .description = "skbinfo support",
 };
 
index abf286c647e5420bdad1e0c340e6b73f3624d5a1..9a4e7faa768cc9ee85091ffdd80df81c71149177 100644 (file)
 #include <libipset/ui.h>                       /* ipset_port_usage */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netiface_create_args0[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netiface_add_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_netiface_usage0[] =
-"create SETNAME hash:net,iface\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE [timeout VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE\n"
-"test   SETNAME IP[/CIDR],[physdev:]IFACE\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n";
-
+/* Initial revision */
 static struct ipset_type ipset_hash_netiface0 = {
        .name = "hash:net,iface",
        .alias = { "netifacehash", NULL },
@@ -80,70 +29,70 @@ static struct ipset_type ipset_hash_netiface0 = {
                        .opt = IPSET_OPT_IFACE
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netiface_create_args0,
-               [IPSET_ADD] = hash_netiface_add_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR],[physdev:]IFACE",
+               },
        },
-
-       .usage = hash_netiface_usage0,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with IPv4 is supported.",
        .description = "Initial revision",
 };
 
-static const struct ipset_arg hash_netiface_add_args1[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netiface_usage1[] =
-"create SETNAME hash:net,iface\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE [timeout VALUE] [nomatch]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE\n"
-"test   SETNAME IP[/CIDR],[physdev:]IFACE\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n";
-
+/* nomatch flag support */
 static struct ipset_type ipset_hash_netiface1 = {
        .name = "hash:net,iface",
        .alias = { "netifacehash", NULL },
@@ -162,46 +111,72 @@ static struct ipset_type ipset_hash_netiface1 = {
                        .opt = IPSET_OPT_IFACE
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netiface_create_args0,
-               [IPSET_ADD] = hash_netiface_add_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR],[physdev:]IFACE",
+               },
        },
-
-       .usage = hash_netiface_usage1,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with IPv4 is supported.",
        .description = "nomatch flag support",
 };
 
+/* /0 network support */
 static struct ipset_type ipset_hash_netiface2 = {
        .name = "hash:net,iface",
        .alias = { "netifacehash", NULL },
@@ -220,123 +195,72 @@ static struct ipset_type ipset_hash_netiface2 = {
                        .opt = IPSET_OPT_IFACE
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netiface_create_args0,
-               [IPSET_ADD] = hash_netiface_add_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR],[physdev:]IFACE",
+               },
        },
-
-       .usage = hash_netiface_usage1,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with IPv4 is supported.",
        .description = "/0 network support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netiface_create_args3[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netiface_add_args3[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netiface_test_args3[] = {
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netiface_usage3[] =
-"create SETNAME hash:net,iface\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE\n"
-"test   SETNAME IP[/CIDR],[physdev:]IFACE\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n";
-
+/* counters support */
 static struct ipset_type ipset_hash_netiface3 = {
        .name = "hash:net,iface",
        .alias = { "netifacehash", NULL },
@@ -355,136 +279,75 @@ static struct ipset_type ipset_hash_netiface3 = {
                        .opt = IPSET_OPT_IFACE
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netiface_create_args3,
-               [IPSET_ADD] = hash_netiface_add_args3,
-               [IPSET_TEST] = hash_netiface_test_args3,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR],[physdev:]IFACE",
+               },
        },
-
-       .usage = hash_netiface_usage3,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with IPv4 is supported.",
        .description = "counters support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netiface_create_args4[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netiface_add_args4[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netiface_test_args4[] = {
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netiface_usage4[] =
-"create SETNAME hash:net,iface\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE\n"
-"test   SETNAME IP[/CIDR],[physdev:]IFACE\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n";
-
+/* comment support */
 static struct ipset_type ipset_hash_netiface4 = {
        .name = "hash:net,iface",
        .alias = { "netifacehash", NULL },
@@ -503,111 +366,77 @@ static struct ipset_type ipset_hash_netiface4 = {
                        .opt = IPSET_OPT_IFACE
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netiface_create_args4,
-               [IPSET_ADD] = hash_netiface_add_args4,
-               [IPSET_TEST] = hash_netiface_test_args4,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR],[physdev:]IFACE",
+               },
        },
-
-       .usage = hash_netiface_usage4,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with IPv4 is supported.",
        .description = "comment support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netiface_create_args5[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netiface_usage5[] =
-"create SETNAME hash:net,iface\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE\n"
-"test   SETNAME IP[/CIDR],[physdev:]IFACE\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n";
-
+/* forceadd support */
 static struct ipset_type ipset_hash_netiface5 = {
        .name = "hash:net,iface",
        .alias = { "netifacehash", NULL },
@@ -626,153 +455,78 @@ static struct ipset_type ipset_hash_netiface5 = {
                        .opt = IPSET_OPT_IFACE
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netiface_create_args5,
-               [IPSET_ADD] = hash_netiface_add_args4,
-               [IPSET_TEST] = hash_netiface_test_args4,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR],[physdev:]IFACE",
+               },
        },
-
-       .usage = hash_netiface_usage5,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with IPv4 is supported.",
        .description = "forceadd support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netiface_create_args6[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netiface_add_args6[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_netiface_usage6[] =
-"create SETNAME hash:net,iface\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd] [skbinfo]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprip VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE\n"
-"test   SETNAME IP[/CIDR],[physdev:]IFACE\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_hash_netiface6 = {
        .name = "hash:net,iface",
        .alias = { "netifacehash", NULL },
@@ -791,55 +545,78 @@ static struct ipset_type ipset_hash_netiface6 = {
                        .opt = IPSET_OPT_IFACE
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netiface_create_args6,
-               [IPSET_ADD] = hash_netiface_add_args6,
-               [IPSET_TEST] = hash_netiface_test_args4,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IFACE),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IFACE)
-                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR]|FROM-TO,[physdev:]IFACE",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IFACE),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IFACE)
+                               | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+                       .help = "IP[/CIDR],[physdev:]IFACE",
+               },
        },
-
-       .usage = hash_netiface_usage6,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with IPv4 is supported.",
        .description = "skbinfo support",
 };
 
index b0d4954af899440777ce5df9129dac8bcc1d5e4f..64ff0dfeddd860f7059836f28995989f219ecedf 100644 (file)
 #include <libipset/print.h>                    /* printing functions */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netnet_create_args0[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netnet_add_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netnet_test_args0[] = {
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netnet_usage0[] =
-"create SETNAME hash:net,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO\n"
-"test   SETNAME IP[/CIDR],IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP is an IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      IP range is not supported with IPv6.\n";
-
+/* Initial revision */
 static struct ipset_type ipset_hash_netnet0 = {
        .name = "hash:net,net",
        .alias = { "netnethash", NULL },
@@ -113,111 +29,79 @@ static struct ipset_type ipset_hash_netnet0 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netnet_create_args0,
-               [IPSET_ADD] = hash_netnet_add_args0,
-               [IPSET_TEST] = hash_netnet_test_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP[/CIDR],IP[/CIDR]",
+               },
        },
-
-       .usage = hash_netnet_usage0,
+       .usage = "where depending on the INET family\n"
+                "      IP is an IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      IP range is not supported with IPv6.",
        .description = "initial revision",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netnet_create_args1[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netnet_usage1[] =
-"create SETNAME hash:net,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [forceadd]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO\n"
-"test   SETNAME IP[/CIDR],IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP is an IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      IP range is not supported with IPv6.\n";
-
+/* forceadd support */
 static struct ipset_type ipset_hash_netnet1 = {
        .name = "hash:net,net",
        .alias = { "netnethash", NULL },
@@ -236,153 +120,80 @@ static struct ipset_type ipset_hash_netnet1 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netnet_create_args1,
-               [IPSET_ADD] = hash_netnet_add_args0,
-               [IPSET_TEST] = hash_netnet_test_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP[/CIDR],IP[/CIDR]",
+               },
        },
-
-       .usage = hash_netnet_usage1,
+       .usage = "where depending on the INET family\n"
+                "      IP is an IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      IP range is not supported with IPv6.",
        .description = "forceadd support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netnet_create_args2[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netnet_add_args2[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_netnet_usage2[] =
-"create SETNAME hash:net,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [forceadd] [skbinfo]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO\n"
-"test   SETNAME IP[/CIDR],IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP is an IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      IP range is not supported with IPv6.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_hash_netnet2 = {
        .name = "hash:net,net",
        .alias = { "netnethash", NULL },
@@ -401,56 +212,80 @@ static struct ipset_type ipset_hash_netnet2 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netnet_create_args2,
-               [IPSET_ADD] = hash_netnet_add_args2,
-               [IPSET_TEST] = hash_netnet_test_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP[/CIDR],IP[/CIDR]",
+               },
        },
-
-       .usage = hash_netnet_usage2,
+       .usage = "where depending on the INET family\n"
+                "      IP is an IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      IP range is not supported with IPv6.",
        .description = "skbinfo support",
 };
 
index b99654187cfa6525e5d0657242e1e6ce9d2ead05..e6d9aa907901c88469621d1930b0e86ada286c17 100644 (file)
 #include <libipset/ui.h>                       /* ipset_port_usage */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netport_create_args1[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netport_add_args1[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_netport_usage1[] =
-"create SETNAME hash:net,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP[/CIDR],PROTO:PORT [timeout VALUE]\n"
-"del    SETNAME IP[/CIDR],PROTO:PORT\n"
-"test   SETNAME IP[/CIDR],PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* SCTP and UDPLITE support */
 static struct ipset_type ipset_hash_netport1 = {
        .name = "hash:net,port",
        .alias = { "netporthash", NULL },
@@ -81,63 +29,75 @@ static struct ipset_type ipset_hash_netport1 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netport_create_args1,
-               [IPSET_ADD] = hash_netport_add_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_CIDR),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_CIDR),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_CIDR),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR],[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR],[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR],[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_netport_usage1,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "SCTP and UDPLITE support",
 };
 
-static const char hash_netport_usage2[] =
-"create SETNAME hash:net,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT [timeout VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT\n"
-"test   SETNAME IP[/CIDR],PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* Add/del range support */
 static struct ipset_type ipset_hash_netport2 = {
        .name = "hash:net,port",
        .alias = { "netporthash", NULL },
@@ -156,77 +116,77 @@ static struct ipset_type ipset_hash_netport2 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netport_create_args1,
-               [IPSET_ADD] = hash_netport_add_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR],[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_netport_usage2,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "Add/del range support",
 };
 
-static const struct ipset_arg hash_netport_add_args3[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netport_usage3[] =
-"create SETNAME hash:net,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT [timeout VALUE] [nomatch]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT\n"
-"test   SETNAME IP[/CIDR],PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* nomatch flag support */
 static struct ipset_type ipset_hash_netport3 = {
        .name = "hash:net,port",
        .alias = { "netporthash", NULL },
@@ -245,130 +205,79 @@ static struct ipset_type ipset_hash_netport3 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netport_create_args1,
-               [IPSET_ADD] = hash_netport_add_args3,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR],[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_netport_usage3,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "nomatch flag support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netport_create_args4[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netport_add_args4[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netport_test_args4[] = {
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netport_usage4[] =
-"create SETNAME hash:net,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT\n"
-"test   SETNAME IP[/CIDR],PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* counters support */
 static struct ipset_type ipset_hash_netport4 = {
        .name = "hash:net,port",
        .alias = { "netporthash", NULL },
@@ -387,143 +296,82 @@ static struct ipset_type ipset_hash_netport4 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netport_create_args4,
-               [IPSET_ADD] = hash_netport_add_args4,
-               [IPSET_TEST] = hash_netport_test_args4,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR],[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_netport_usage4,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "counters support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netport_create_args5[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netport_add_args5[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netport_test_args5[] = {
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netport_usage5[] =
-"create SETNAME hash:net,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT\n"
-"test   SETNAME IP[/CIDR],PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* comment support */
 static struct ipset_type ipset_hash_netport5 = {
        .name = "hash:net,port",
        .alias = { "netporthash", NULL },
@@ -542,118 +390,84 @@ static struct ipset_type ipset_hash_netport5 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netport_create_args5,
-               [IPSET_ADD] = hash_netport_add_args5,
-               [IPSET_TEST] = hash_netport_test_args5,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR],[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_netport_usage5,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "comment support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netport_create_args6[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netport_usage6[] =
-"create SETNAME hash:net,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT\n"
-"test   SETNAME IP[/CIDR],PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* forceadd support */
 static struct ipset_type ipset_hash_netport6 = {
        .name = "hash:net,port",
        .alias = { "netporthash", NULL },
@@ -672,160 +486,85 @@ static struct ipset_type ipset_hash_netport6 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netport_create_args6,
-               [IPSET_ADD] = hash_netport_add_args5,
-               [IPSET_TEST] = hash_netport_test_args5,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR],[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_netport_usage6,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "forceadd support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netport_create_args7[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netport_add_args7[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_netport_usage7[] =
-"create SETNAME hash:net,port\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd] [skbinfo]\n"
-"add    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT\n"
-"test   SETNAME IP[/CIDR],PROTO:PORT\n\n"
-"where depending on the INET family\n"
-"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements with IPv4 is supported.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_hash_netport7 = {
        .name = "hash:net,port",
        .alias = { "netporthash", NULL },
@@ -844,59 +583,84 @@ static struct ipset_type ipset_hash_netport7 = {
                        .opt = IPSET_OPT_PORT
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netport_create_args7,
-               [IPSET_ADD] = hash_netport_add_args7,
-               [IPSET_TEST] = hash_netport_test_args5,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_PORT),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO),
+                       .help = "IP[/CIDR]|FROM-TO,[PROTO:]PORT",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_CIDR),
+                       .help = "IP[/CIDR],[PROTO:]PORT",
+               },
        },
-
-       .usage = hash_netport_usage7,
+       .usage = "where depending on the INET family\n"
+                "      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "skbinfo support",
 };
index c2146638b8835c2029f34334c98d70721923d9a5..3e1971843c16cd61b513fe7aa05e1967904bafad 100644 (file)
 #include <libipset/ui.h>                       /* ipset_port_usage */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netportnet_create_args0[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netportnet_add_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netportnet_test_args0[] = {
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netportnet_usage0[] =
-"create SETNAME hash:net,port,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME IP[/CIDR],PROTO:PORT,IP[/CIDR] [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP[/CIDR],PROTO:PORT,IP[/CIDR]\n"
-"test   SETNAME IP[/CIDR],PROTO:PORT,IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in both IP components are supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* initial revision */
 static struct ipset_type ipset_hash_netportnet0 = {
        .name = "hash:net,port,net",
        .alias = { "netportnethash", NULL },
@@ -121,130 +34,97 @@ static struct ipset_type ipset_hash_netportnet0 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netportnet_create_args0,
-               [IPSET_ADD] = hash_netportnet_add_args0,
-               [IPSET_TEST] = hash_netportnet_test_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR],[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR],[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP[/CIDR],[PROTO:]PORT,IP[/CIDR]",
+               },
        },
-
-       .usage = hash_netportnet_usage0,
+       .usage = "where depending on the INET family\n"
+                "      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in both IP components are supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "initial revision",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netportnet_create_args1[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const char hash_netportnet_usage1[] =
-"create SETNAME hash:net,port,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd]\n"
-"add    SETNAME IP[/CIDR],PROTO:PORT,IP[/CIDR] [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"del    SETNAME IP[/CIDR],PROTO:PORT,IP[/CIDR]\n"
-"test   SETNAME IP[/CIDR],PROTO:PORT,IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in both IP components are supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* forceadd support */
 static struct ipset_type ipset_hash_netportnet1 = {
        .name = "hash:net,port,net",
        .alias = { "netportnethash", NULL },
@@ -268,172 +148,98 @@ static struct ipset_type ipset_hash_netportnet1 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netportnet_create_args1,
-               [IPSET_ADD] = hash_netportnet_add_args0,
-               [IPSET_TEST] = hash_netportnet_test_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR],[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR],[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP[/CIDR],[PROTO:]PORT,IP[/CIDR]",
+               },
        },
-
-       .usage = hash_netportnet_usage1,
+       .usage = "where depending on the INET family\n"
+                "      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in both IP components are supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "forceadd support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg hash_netportnet_create_args2[] = {
-       { .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", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_MAXELEM,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "forceadd", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_FORCEADD,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg hash_netportnet_add_args2[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "nomatch", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char hash_netportnet_usage2[] =
-"create SETNAME hash:net,port,net\n"
-"              [family inet|inet6]\n"
-"               [hashsize VALUE] [maxelem VALUE]\n"
-"               [timeout VALUE] [counters] [comment]\n"
-"              [forceadd] [skbinfo]\n"
-"add    SETNAME IP[/CIDR],PROTO:PORT,IP[/CIDR] [timeout VALUE] [nomatch]\n"
-"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME IP[/CIDR],PROTO:PORT,IP[/CIDR]\n"
-"test   SETNAME IP[/CIDR],PROTO:PORT,IP[/CIDR]\n\n"
-"where depending on the INET family\n"
-"      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
-"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
-"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
-"      in both IP components are supported for IPv4.\n"
-"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
-"      port range is supported both for IPv4 and IPv6.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_hash_netportnet2 = {
        .name = "hash:net,port,net",
        .alias = { "netportnethash", NULL },
@@ -457,70 +263,97 @@ static struct ipset_type ipset_hash_netportnet2 = {
                        .opt = IPSET_OPT_IP2
                },
        },
-       .args = {
-               [IPSET_CREATE] = hash_netportnet_create_args2,
-               [IPSET_ADD] = hash_netportnet_add_args2,
-               [IPSET_TEST] = hash_netportnet_test_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
-                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_FORCEADD)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_IP_TO)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
-                       | IPSET_FLAG(IPSET_OPT_CIDR)
-                       | IPSET_FLAG(IPSET_OPT_PORT)
-                       | IPSET_FLAG(IPSET_OPT_PROTO)
-                       | IPSET_FLAG(IPSET_OPT_IP2)
-                       | IPSET_FLAG(IPSET_OPT_CIDR2)
-                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_FAMILY,
+                               /* Aliases */
+                               IPSET_ARG_INET,
+                               IPSET_ARG_INET6,
+                               IPSET_ARG_HASHSIZE,
+                               IPSET_ARG_MAXELEM,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_FORCEADD,
+                               IPSET_ARG_SKBINFO,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR],[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP_TO)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2)
+                               | IPSET_FLAG(IPSET_OPT_IP2_TO),
+                       .help = "IP[/CIDR],[PROTO:]PORT,IP[/CIDR]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_NOMATCH,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_IP2),
+                       .full = IPSET_FLAG(IPSET_OPT_IP)
+                               | IPSET_FLAG(IPSET_OPT_PROTO)
+                               | IPSET_FLAG(IPSET_OPT_PORT)
+                               | IPSET_FLAG(IPSET_OPT_CIDR)
+                               | IPSET_FLAG(IPSET_OPT_IP2)
+                               | IPSET_FLAG(IPSET_OPT_CIDR2),
+                       .help = "IP[/CIDR],[PROTO:]PORT,IP[/CIDR]",
+               },
        },
-
-       .usage = hash_netportnet_usage2,
+       .usage = "where depending on the INET family\n"
+                "      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
+                "      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+                "      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+                "      in both IP components are supported for IPv4.\n"
+                "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+                "      port range is supported both for IPv4 and IPv6.",
        .usagefn = ipset_port_usage,
        .description = "skbinfo support",
 };
index 45934e73323d307d78cf17cf4efced9ccc7dc214..973243fc46d54ff6f4b6be551e2d9787a950edc4 100644 (file)
@@ -9,43 +9,7 @@
 #include <libipset/print.h>                    /* printing functions */
 #include <libipset/types.h>                    /* prototypes */
 
-/* Parse commandline arguments */
-static const struct ipset_arg list_set_create_args0[] = {
-       { .name = { "size", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SIZE,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { },
-};
-
-static const struct ipset_arg list_set_adt_args0[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .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_usage0[] =
-"create SETNAME list:set\n"
-"               [size VALUE] [timeout VALUE]\n"
-"add    SETNAME NAME [before|after NAME] [timeout VALUE]\n"
-"del    SETNAME NAME [before|after NAME]\n"
-"test   SETNAME NAME [before|after NAME]\n\n"
-"where NAME are existing set names.\n";
-
+/* Initial revision */
 static struct ipset_type ipset_list_set0 = {
        .name = "list:set",
        .alias = { "setlist", NULL },
@@ -60,87 +24,57 @@ static struct ipset_type ipset_list_set0 = {
                },
        },
        .compat_parse_elem = ipset_parse_name_compat,
-       .args = {
-               [IPSET_CREATE] = list_set_create_args0,
-               [IPSET_ADD] = list_set_adt_args0,
-               [IPSET_DEL] = list_set_adt_args0,
-               [IPSET_TEST] = list_set_adt_args0,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_NAME),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_NAME),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_NAME),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_SIZE)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_SIZE,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
        },
-
-       .usage = list_set_usage0,
+       .usage = "where NAME are existing set names.",
        .description = "Initial revision",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg list_set_create_args1[] = {
-       { .name = { "size", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SIZE,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg list_set_adt_args1[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .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,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char list_set_usage1[] =
-"create SETNAME list:set\n"
-"               [size VALUE] [timeout VALUE] [counters\n"
-"add    SETNAME NAME [before|after NAME] [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE]\n"
-"del    SETNAME NAME [before|after NAME]\n"
-"test   SETNAME NAME [before|after NAME]\n\n"
-"where NAME are existing set names.\n";
-
+/* counters support */
 static struct ipset_type ipset_list_set1 = {
        .name = "list:set",
        .alias = { "setlist", NULL },
@@ -155,98 +89,60 @@ static struct ipset_type ipset_list_set1 = {
                },
        },
        .compat_parse_elem = ipset_parse_name_compat,
-       .args = {
-               [IPSET_CREATE] = list_set_create_args1,
-               [IPSET_ADD] = list_set_adt_args1,
-               [IPSET_DEL] = list_set_adt_args1,
-               [IPSET_TEST] = list_set_adt_args1,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_NAME),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_NAME),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_NAME),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_SIZE)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_SIZE,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
        },
-
-       .usage = list_set_usage1,
+       .usage = "where NAME are existing set names.",
        .description = "counters support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg list_set_create_args2[] = {
-       { .name = { "size", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SIZE,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg list_set_adt_args2[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .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,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { },
-};
-
-static const char list_set_usage2[] =
-"create SETNAME list:set\n"
-"               [size VALUE] [timeout VALUE] [counters] [comment]\n"
-"add    SETNAME NAME [before|after NAME] [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment STRING]\n"
-"del    SETNAME NAME [before|after NAME]\n"
-"test   SETNAME NAME [before|after NAME]\n\n"
-"where NAME are existing set names.\n";
-
+/* comment support */
 static struct ipset_type ipset_list_set2 = {
        .name = "list:set",
        .alias = { "setlist", NULL },
@@ -261,118 +157,62 @@ static struct ipset_type ipset_list_set2 = {
                },
        },
        .compat_parse_elem = ipset_parse_name_compat,
-       .args = {
-               [IPSET_CREATE] = list_set_create_args2,
-               [IPSET_ADD] = list_set_adt_args2,
-               [IPSET_DEL] = list_set_adt_args2,
-               [IPSET_TEST] = list_set_adt_args2,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_NAME),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_NAME),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_NAME),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_SIZE)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_SIZE,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
        },
-
-       .usage = list_set_usage2,
+       .usage = "where NAME are existing set names.",
        .description = "comment support",
 };
 
-/* Parse commandline arguments */
-static const struct ipset_arg list_set_create_args3[] = {
-       { .name = { "size", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SIZE,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
-       },
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .print = ipset_print_number,
-       },
-       { .name = { "counters", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_COUNTERS,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_CREATE_COMMENT,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { .name = { "skbinfo", NULL },
-         .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_SKBINFO,
-         .parse = ipset_parse_flag,            .print = ipset_print_flag,
-       },
-       { },
-};
-
-static const struct ipset_arg list_set_adt_args3[] = {
-       { .name = { "timeout", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_timeout,         .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,
-       },
-       { .name = { "packets", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_PACKETS,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "bytes", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_BYTES,
-         .parse = ipset_parse_uint64,          .print = ipset_print_number,
-       },
-       { .name = { "comment", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_ADT_COMMENT,
-         .parse = ipset_parse_comment,         .print = ipset_print_comment,
-       },
-       { .name = { "skbmark", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBMARK,
-         .parse = ipset_parse_skbmark,         .print = ipset_print_skbmark,
-       },
-       { .name = { "skbprio", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBPRIO,
-         .parse = ipset_parse_skbprio,         .print = ipset_print_skbprio,
-       },
-       { .name = { "skbqueue", NULL },
-         .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_SKBQUEUE,
-         .parse = ipset_parse_uint16,          .print = ipset_print_number,
-       },
-       { },
-};
-
-static const char list_set_usage3[] =
-"create SETNAME list:set\n"
-"               [size VALUE] [timeout VALUE] [counters] [comment]\n"
-"              [skbinfo]\n"
-"add    SETNAME NAME [before|after NAME] [timeout VALUE]\n"
-"               [packets VALUE] [bytes VALUE] [comment STRING]\n"
-"              [skbmark VALUE] [skbprio VALUE] [skbqueue VALUE]\n"
-"del    SETNAME NAME [before|after NAME]\n"
-"test   SETNAME NAME [before|after NAME]\n\n"
-"where NAME are existing set names.\n";
-
+/* skbinfo support */
 static struct ipset_type ipset_list_set3 = {
        .name = "list:set",
        .alias = { "setlist", NULL },
@@ -387,45 +227,65 @@ static struct ipset_type ipset_list_set3 = {
                },
        },
        .compat_parse_elem = ipset_parse_name_compat,
-       .args = {
-               [IPSET_CREATE] = list_set_create_args3,
-               [IPSET_ADD] = list_set_adt_args3,
-               [IPSET_DEL] = list_set_adt_args2,
-               [IPSET_TEST] = list_set_adt_args2,
-       },
-       .mandatory = {
-               [IPSET_CREATE] = 0,
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_NAME),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_NAME),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_NAME),
-       },
-       .full = {
-               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_SIZE)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_COUNTERS)
-                       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBINFO),
-               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF)
-                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
-                       | IPSET_FLAG(IPSET_OPT_PACKETS)
-                       | IPSET_FLAG(IPSET_OPT_BYTES)
-                       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT)
-                       | IPSET_FLAG(IPSET_OPT_SKBMARK)
-                       | IPSET_FLAG(IPSET_OPT_SKBPRIO)
-                       | IPSET_FLAG(IPSET_OPT_SKBQUEUE),
-               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF),
-               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_NAME)
-                       | IPSET_FLAG(IPSET_OPT_BEFORE)
-                       | IPSET_FLAG(IPSET_OPT_NAMEREF),
+       .cmd = {
+               [IPSET_CREATE] = {
+                       .args = {
+                               IPSET_ARG_SIZE,
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_COUNTERS,
+                               IPSET_ARG_COMMENT,
+                               IPSET_ARG_SKBINFO,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = 0,
+                       .full = 0,
+                       .help = "",
+               },
+               [IPSET_ADD] = {
+                       .args = {
+                               IPSET_ARG_TIMEOUT,
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_PACKETS,
+                               IPSET_ARG_BYTES,
+                               IPSET_ARG_ADT_COMMENT,
+                               IPSET_ARG_SKBMARK,
+                               IPSET_ARG_SKBPRIO,
+                               IPSET_ARG_SKBQUEUE,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
+               [IPSET_DEL] = {
+                       .args = {
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
+               [IPSET_TEST] = {
+                       .args = {
+                               IPSET_ARG_BEFORE,
+                               IPSET_ARG_AFTER,
+                               IPSET_ARG_NONE,
+                       },
+                       .need = IPSET_FLAG(IPSET_OPT_NAME),
+                       .full = IPSET_FLAG(IPSET_OPT_NAME)
+                               | IPSET_FLAG(IPSET_OPT_BEFORE),
+                       .help = "NAME [before|after NAME]",
+               },
        },
-
-       .usage = list_set_usage3,
+       .usage = "where NAME are existing set names.",
        .description = "skbinfo support",
 };
+
 void _init(void);
 void _init(void)
 {
index df632f204bdd974d2157d93d5e6444d2846ca2da..a2e9bd356113705dbb6fdb04a4080f30243b03b8 100644 (file)
@@ -163,3 +163,8 @@ LIBIPSET_4.5 {
 global:
   ipset_type_higher_rev;
 } LIBIPSET_4.4;
+
+LIBIPSET_4.6 {
+global:
+  ipset_keyword;
+} LIBIPSET_4.5;
index 88d288815147cccaa57f11505c835abf5db67159..bc8e7773f05d623afd4ce819a2bf8f78003bba95 100644 (file)
@@ -631,7 +631,7 @@ ipset_parse_proto_port(struct ipset_session *session,
                case IPPROTO_ICMP:
                        if (family != NFPROTO_IPV4) {
                                syntax_err("Protocol ICMP can be used "
-                                          "with family INET only");
+                                          "with family inet only");
                                goto error;
                        }
                        err = ipset_parse_icmp(session, opt, a);
@@ -639,7 +639,7 @@ ipset_parse_proto_port(struct ipset_session *session,
                case IPPROTO_ICMPV6:
                        if (family != NFPROTO_IPV6) {
                                syntax_err("Protocol ICMPv6 can be used "
-                                          "with family INET6 only");
+                                          "with family inet6 only");
                                goto error;
                        }
                        err = ipset_parse_icmpv6(session, opt, a);
@@ -742,7 +742,7 @@ ipset_parse_family(struct ipset_session *session,
        else if (STREQ(str, "any") || STREQ(str, "unspec"))
                family = NFPROTO_UNSPEC;
        else
-               return syntax_err("unknown INET family %s", str);
+               return syntax_err("unknown inet family %s", str);
 
        return ipset_data_set(data, opt, &family);
 }
index 4cd6d303010587bd80113fcf70ed296b55819e20..b1c5f5ebdce5c75155b603b27c1c15d8b7548668 100644 (file)
@@ -817,8 +817,9 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
        if (session->mode == IPSET_LIST_XML)
                safe_snprintf(session, "</elem>");
 
-       for (arg = type->args[IPSET_ADD]; arg != NULL && arg->opt; arg++) {
-               D("print arg opt %u %s", arg->opt,
+       for (i = 0; type->cmd[IPSET_ADD].args[i] != IPSET_ARG_NONE; i++) {
+               arg = ipset_keyword(type->cmd[IPSET_ADD].args[i]);
+               D("print arg opt %u (%s) %s", arg->opt, arg->name[0],
                   ipset_data_test(data, arg->opt) ? "(yes)" : "(missing)");
                if (!(arg->print && ipset_data_test(data, arg->opt)))
                        continue;
@@ -905,7 +906,12 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
                break;
        }
 
-       for (arg = type->args[IPSET_CREATE]; arg != NULL && arg->opt; arg++) {
+       D("type %s, rev %u", type->name, type->revision);
+       for (i = 0; type->cmd[IPSET_CREATE].args[i] != IPSET_ARG_NONE; i++) {
+               arg = ipset_keyword(type->cmd[IPSET_CREATE].args[i]);
+               D("create print arg opt %u (%s) %s", arg->opt,
+                  arg->name[0] ? arg->name[0] : "",
+                  ipset_data_test(data, arg->opt) ? "(yes)" : "(missing)");
                if (!arg->print ||
                    !ipset_data_test(data, arg->opt) ||
                    (arg->opt == IPSET_OPT_FAMILY &&
index 0fe8a7c4820ea042e82ec1bae281c24f7323388f..1adf64065b0c5816fefab4d07b45d67ec07f2dbf 100644 (file)
@@ -497,12 +497,21 @@ int
 ipset_type_add(struct ipset_type *type)
 {
        struct ipset_type *t, *prev;
+       const struct ipset_arg *arg;
+       enum ipset_adt cmd;
+       int i;
 
        assert(type);
 
        if (strlen(type->name) > IPSET_MAXNAMELEN - 1)
                return -EINVAL;
 
+       for (cmd = IPSET_ADD; cmd < IPSET_CADT_MAX; cmd++) {
+               for (i = 0; type->cmd[cmd].args[i] != IPSET_ARG_NONE; i++) {
+                       arg = ipset_keyword(type->cmd[cmd].args[i]);
+                       type->cmd[cmd].full |= IPSET_FLAG(arg->opt);
+               }
+       }
        /* Add to the list: higher revision numbers first */
        for (t = typelist, prev = NULL; t != NULL; t = t->next) {
                if (STREQ(t->name, type->name)) {
index df0778a92d8be0733b44bf7831365a934dbea1f2..ce1b73f51633cc0e093ae9fea8752946749d0131 100644 (file)
@@ -278,21 +278,21 @@ static int
 call_parser(int *argc, char *argv[], const struct ipset_type *type,
            enum ipset_adt cmd, bool family)
 {
-       const struct ipset_arg *args = type->args[cmd];
        const struct ipset_arg *arg;
        const char *optstr;
        const struct ipset_type *t = type;
        uint8_t revision = type->revision;
-       int ret = 0, i = 1;
+       int ret = 0, i = 1, j;
 
        /* Currently CREATE and ADT may have got additional arguments */
-       if (!args && *argc > 1)
+       if (type->cmd[cmd].args[0] == IPSET_ARG_NONE && *argc > 1)
                return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'",
                                  argv[i]);
 
        while (*argc > i) {
                ret = -1;
-               for (arg = args; arg->opt; arg++) {
+               for (j = 0; type->cmd[cmd].args[j] != IPSET_ARG_NONE; j++) {
+                       arg = ipset_keyword(type->cmd[cmd].args[j]);
                        D("argc: %u, %s vs %s", i, argv[i], arg->name[0]);
                        if (!(ipset_match_option(argv[i], arg->name)))
                                continue;
@@ -343,8 +343,8 @@ call_parser(int *argc, char *argv[], const struct ipset_type *type,
 
 err_unknown:
        while ((type = ipset_type_higher_rev(t)) != t) {
-               args = type->args[cmd];
-               for (arg = args; arg->opt; arg++) {
+               for (j = 0; type->cmd[cmd].args[j] != IPSET_ARG_NONE; j++) {
+                       arg = ipset_keyword(type->cmd[cmd].args[j]);
                        D("argc: %u, %s vs %s", i, argv[i], arg->name[0]);
                        if (ipset_match_option(argv[i], arg->name))
                                return exit_error(PARAMETER_PROBLEM,
@@ -382,8 +382,9 @@ check_mandatory(const struct ipset_type *type, enum ipset_cmd command)
 {
        enum ipset_adt cmd = cmd2cmd(command);
        uint64_t flags = ipset_data_flags(ipset_session_data(session));
-       uint64_t mandatory = type->mandatory[cmd];
-       const struct ipset_arg *arg = type->args[cmd];
+       uint64_t mandatory = type->cmd[cmd].need;
+       const struct ipset_arg *arg;
+       int i;
 
        /* Range can be expressed by ip/cidr */
        if (flags & IPSET_FLAG(IPSET_OPT_CIDR))
@@ -392,7 +393,7 @@ check_mandatory(const struct ipset_type *type, enum ipset_cmd command)
        mandatory &= ~flags;
        if (!mandatory)
                return;
-       if (!arg) {
+       if (type->cmd[cmd].args[0] == IPSET_ARG_NONE) {
                exit_error(OTHER_PROBLEM,
                        "There are missing mandatory flags "
                        "but can't check them. "
@@ -400,13 +401,15 @@ check_mandatory(const struct ipset_type *type, enum ipset_cmd command)
                return;
        }
 
-       for (; arg->opt; arg++)
+       for (i = 0; type->cmd[cmd].args[i] != IPSET_ARG_NONE; i++) {
+               arg = ipset_keyword(type->cmd[cmd].args[i]);
                if (mandatory & IPSET_FLAG(arg->opt)) {
                        exit_error(PARAMETER_PROBLEM,
                                   "Mandatory option `%s' is missing",
                                   arg->name[0]);
                        return;
                }
+       }
 }
 
 static const char *
@@ -438,11 +441,12 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
 {
        uint64_t flags = ipset_data_flags(ipset_session_data(session));
        enum ipset_adt cmd = cmd2cmd(command);
-       uint64_t allowed = type->full[cmd];
+       uint64_t allowed = type->cmd[cmd].full;
        uint64_t cmdflags = command == IPSET_CMD_CREATE
                                ? IPSET_CREATE_FLAGS : IPSET_ADT_FLAGS;
-       const struct ipset_arg *arg = type->args[cmd];
+       const struct ipset_arg *arg;
        enum ipset_opt i;
+       int j;
 
        /* Range can be expressed by ip/cidr or from-to */
        if (allowed & IPSET_FLAG(IPSET_OPT_IP_TO))
@@ -480,14 +484,15 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
                        break;
                }
                /* Other options */
-               if (!arg) {
+               if (type->cmd[cmd].args[0] == IPSET_ARG_NONE) {
                        exit_error(OTHER_PROBLEM,
                                "There are not allowed options (%u) "
-                               "but option list is NULL. "
+                               "but option list is empty. "
                                "It's a bug, please report the problem.", i);
                        return;
                }
-               for (; arg->opt; arg++) {
+               for (j = 0; type->cmd[cmd].args[j] != IPSET_ARG_NONE; j++) {
+                       arg = ipset_keyword(type->cmd[cmd].args[j]);
                        if (arg->opt != i)
                                continue;
                        exit_error(OTHER_PROBLEM,
@@ -519,6 +524,21 @@ type_find(const char *name)
        return NULL;
 }
 
+static enum ipset_adt cmd_help_order[] = {
+       IPSET_CREATE,
+       IPSET_ADD,
+       IPSET_DEL,
+       IPSET_TEST,
+       IPSET_CADT_MAX,
+};
+
+static const char *cmd_prefix[] = {
+       [IPSET_CREATE] = "create SETNAME",
+       [IPSET_ADD]    = "add    SETNAME",
+       [IPSET_DEL]    = "del    SETNAME",
+       [IPSET_TEST]   = "test   SETNAME",
+};
+
 /* Workhorse */
 int
 parse_commandline(int argc, char *argv[])
@@ -677,28 +697,42 @@ parse_commandline(int argc, char *argv[])
                if (interactive ||
                    !ipset_envopt_test(session, IPSET_ENV_QUIET)) {
                        if (arg0) {
+                               const struct ipset_arg *arg;
+                               int k;
+
                                /* Type-specific help, without kernel checking */
                                type = type_find(arg0);
                                if (!type)
                                        return exit_error(PARAMETER_PROBLEM,
                                                "Unknown settype: `%s'", arg0);
-                               printf("\n%s type specific options:\n\n%s",
-                                      type->name, type->usage);
+                               printf("\n%s type specific options:\n\n", type->name);
+                               for (i = 0; cmd_help_order[i] != IPSET_CADT_MAX; i++) {
+                                       cmd = cmd_help_order[i];
+                                       printf("%s %s %s\n",
+                                               cmd_prefix[cmd], type->name, type->cmd[cmd].help);
+                                       for (k = 0; type->cmd[cmd].args[k] != IPSET_ARG_NONE; k++) {
+                                               arg = ipset_keyword(type->cmd[cmd].args[k]);
+                                               if (!arg->help || arg->help[0] == '\0')
+                                                       continue;
+                                               printf("               %s\n", arg->help);
+                                       }
+                               }
+                               printf("\n%s\n", type->usage);
                                if (type->usagefn)
                                        type->usagefn();
                                if (type->family == NFPROTO_UNSPEC)
                                        printf("\nType %s is family neutral.\n",
                                               type->name);
                                else if (type->family == NFPROTO_IPSET_IPV46)
-                                       printf("\nType %s supports INET "
-                                              "and INET6.\n",
+                                       printf("\nType %s supports inet "
+                                              "and inet6.\n",
                                               type->name);
                                else
                                        printf("\nType %s supports family "
                                               "%s only.\n",
                                               type->name,
                                               type->family == NFPROTO_IPV4
-                                               ? "INET" : "INET6");
+                                               ? "inet" : "inet6");
                        } else {
                                printf("\nSupported set types:\n");
                                type = ipset_types();