]> git.ipfire.org Git - thirdparty/ipset.git/commitdiff
Introduction of new commands and protocol version 7
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Mon, 22 Oct 2018 20:25:09 +0000 (22:25 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Sat, 27 Oct 2018 12:58:55 +0000 (14:58 +0200)
Two new commands (IPSET_CMD_GET_BYNAME, IPSET_CMD_GET_BYINDEX) are
introduced. The new commands makes possible to eliminate the getsockopt
operation (in iptables set/SET match/target) and thus use only netlink
communication between userspace and kernel for ipset. With the new
protocol version, userspace can exactly know which functionality is
supported by the running kernel.

Both the kernel and userspace is fully backward compatible.

14 files changed:
include/libipset/args.h
include/libipset/data.h
include/libipset/linux_ip_set.h
include/libipset/linux_ip_set_bitmap.h
include/libipset/linux_ip_set_hash.h
include/libipset/linux_ip_set_list.h
kernel/include/linux/netfilter/ipset/ip_set.h
kernel/include/linux/netfilter/ipset/ip_set_compat.h.in
kernel/include/uapi/linux/netfilter/ipset/ip_set.h
kernel/net/netfilter/ipset/ip_set_core.c
lib/PROTOCOL
lib/args.c
lib/data.c
lib/session.c

index dce4190a55a2312af3ba5a0ac77cd5d7eb55226e..3a9929fe7c4f6b64f4eefecab418d9f1d229aaba 100644 (file)
@@ -63,7 +63,7 @@ extern "C" {
 #endif
 
 extern const struct ipset_arg * ipset_keyword(enum ipset_keywords i);
-extern const char * ipset_ignored_optname(int opt);
+extern const char * ipset_ignored_optname(unsigned int opt);
 #ifdef __cplusplus
 }
 #endif
index ca218901a09f580a3c42e0d7b005beb2dae61e1d..744b010dafd2fd07ccb3ccbcf7650d215e37be94 100644 (file)
@@ -74,6 +74,7 @@ enum ipset_opt {
        IPSET_OPT_LINENO,
        IPSET_OPT_REVISION,
        IPSET_OPT_REVISION_MIN,
+       IPSET_OPT_INDEX,
        IPSET_OPT_MAX,
 };
 
index 2096611ea45532b0f001a87e6e5a08ec1baeb398..68a2087f69b5326f8325b898ed9603d53c533d34 100644 (file)
@@ -12,9 +12,9 @@
 
 #include <linux/types.h>
 
-/* The supported protocol versions */
-#define IPSET_PROTOCOL_MIN     6
+/* The protocol versions */
 #define IPSET_PROTOCOL         7
+#define IPSET_PROTOCOL_MIN     6
 
 /* The max length of strings including NUL: set and type identifiers */
 #define IPSET_MAXNAMELEN       32
@@ -38,17 +38,19 @@ enum ipset_cmd {
        IPSET_CMD_TEST,         /* 11: Test an element in a set */
        IPSET_CMD_HEADER,       /* 12: Get set header data only */
        IPSET_CMD_TYPE,         /* 13: Get set type */
+       IPSET_CMD_GET_BYNAME,   /* 14: Get set index by name */
+       IPSET_CMD_GET_BYINDEX,  /* 15: Get set name by index */
        IPSET_MSG_MAX,          /* Netlink message commands */
 
        /* Commands in userspace: */
-       IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */
-       IPSET_CMD_HELP,         /* 15: Get help */
-       IPSET_CMD_VERSION,      /* 16: Get program version */
-       IPSET_CMD_QUIT,         /* 17: Quit from interactive mode */
+       IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 16: Enter restore mode */
+       IPSET_CMD_HELP,         /* 17: Get help */
+       IPSET_CMD_VERSION,      /* 18: Get program version */
+       IPSET_CMD_QUIT,         /* 19: Quit from interactive mode */
 
        IPSET_CMD_MAX,
 
-       IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */
+       IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 20: Commit buffered commands */
 };
 
 /* Attributes at command level */
@@ -66,6 +68,7 @@ enum {
        IPSET_ATTR_LINENO,      /* 9: Restore lineno */
        IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */
        IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
+       IPSET_ATTR_INDEX,       /* 11: Kernel index of set */
        __IPSET_ATTR_CMD_MAX,
 };
 #define IPSET_ATTR_CMD_MAX     (__IPSET_ATTR_CMD_MAX - 1)
@@ -223,6 +226,7 @@ enum ipset_adt {
 
 /* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
  * and IPSET_INVALID_ID if you want to increase the max number of sets.
+ * Also, IPSET_ATTR_INDEX must be changed.
  */
 typedef __u16 ip_set_id_t;
 
index c4b63d650b55c86774327c8ed1dc2989a2c4cde3..a3652c2d63825d51c0823b14b2ecb454f775ab38 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 #ifndef __IP_SET_BITMAP_H
 #define __IP_SET_BITMAP_H
 
index 73d40d715b78b5e9a8adf804b0d96e1a796b5994..3753952e3fa9b07de9eabe6b110049ea443b3307 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 #ifndef __IP_SET_HASH_H
 #define __IP_SET_HASH_H
 
index f8cb89ea2bcaa997806bc8a6df554c79a9575600..650e308bb19287ca9f391d19190e4126f0a192f1 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 #ifndef __IP_SET_LIST_H
 #define __IP_SET_LIST_H
 
index 94f126c98cb6d056988637dbd0205aa6a1d10794..f2b946f698d590843d003dc63615dc1cefd41ab8 100644 (file)
@@ -304,11 +304,11 @@ ip_set_put_flags(struct sk_buff *skb, struct ip_set *set)
 /* Netlink CB args */
 enum {
        IPSET_CB_NET = 0,       /* net namespace */
+       IPSET_CB_PROTO,         /* ipset protocol */
        IPSET_CB_DUMP,          /* dump single set/all sets */
        IPSET_CB_INDEX,         /* set index */
        IPSET_CB_PRIVATE,       /* set private data */
        IPSET_CB_ARG0,          /* type specific */
-       IPSET_CB_ARG1,
 };
 
 /* register and unregister set references */
index b93d662eea0a0f1fa2f1e594b8134e61187f7d1f..1d536a3e128fd44a7049fab789b916e197898ae7 100644 (file)
@@ -134,11 +134,13 @@ do {                              \
        __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head))
 #endif
 
+#if 0
 #ifdef CHECK_KCONFIG
 #ifndef CONFIG_SPARSE_RCU_POINTER
 #error "CONFIG_SPARSE_RCU_POINTER must be enabled"
 #endif
 #endif
+#endif
 
 #if defined(CONFIG_NETFILTER_NETLINK) || defined(CONFIG_NETFILTER_NETLINK_MODULE)
 #else
index 4a6776f7c09556449a54d559abcf4fe18dcec3c3..c83497f1b149f0e00331895dc753ae9f38e1466d 100644 (file)
@@ -12,8 +12,9 @@
 
 #include <linux/types.h>
 
-/* The protocol version */
-#define IPSET_PROTOCOL         6
+/* The protocol versions */
+#define IPSET_PROTOCOL         7
+#define IPSET_PROTOCOL_MIN     6
 
 /* The max length of strings including NUL: set and type identifiers */
 #define IPSET_MAXNAMELEN       32
@@ -37,17 +38,19 @@ enum ipset_cmd {
        IPSET_CMD_TEST,         /* 11: Test an element in a set */
        IPSET_CMD_HEADER,       /* 12: Get set header data only */
        IPSET_CMD_TYPE,         /* 13: Get set type */
+       IPSET_CMD_GET_BYNAME,   /* 14: Get set index by name */
+       IPSET_CMD_GET_BYINDEX,  /* 15: Get set name by index */
        IPSET_MSG_MAX,          /* Netlink message commands */
 
        /* Commands in userspace: */
-       IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */
-       IPSET_CMD_HELP,         /* 15: Get help */
-       IPSET_CMD_VERSION,      /* 16: Get program version */
-       IPSET_CMD_QUIT,         /* 17: Quit from interactive mode */
+       IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 16: Enter restore mode */
+       IPSET_CMD_HELP,         /* 17: Get help */
+       IPSET_CMD_VERSION,      /* 18: Get program version */
+       IPSET_CMD_QUIT,         /* 19: Quit from interactive mode */
 
        IPSET_CMD_MAX,
 
-       IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */
+       IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 20: Commit buffered commands */
 };
 
 /* Attributes at command level */
@@ -65,6 +68,7 @@ enum {
        IPSET_ATTR_LINENO,      /* 9: Restore lineno */
        IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */
        IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
+       IPSET_ATTR_INDEX,       /* 11: Kernel index of set */
        __IPSET_ATTR_CMD_MAX,
 };
 #define IPSET_ATTR_CMD_MAX     (__IPSET_ATTR_CMD_MAX - 1)
@@ -222,6 +226,7 @@ enum ipset_adt {
 
 /* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
  * and IPSET_INVALID_ID if you want to increase the max number of sets.
+ * Also, IPSET_ATTR_INDEX must be changed.
  */
 typedef __u16 ip_set_id_t;
 
index 65628ae8c4c678fa92df2b3b0b3fdb18738d6c0a..e99dda987ec41d3159ef995eeb98135d60e2d928 100644 (file)
@@ -782,11 +782,21 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
  * The commands are serialized by the nfnl mutex.
  */
 
+static inline u8 protocol(const struct nlattr * const tb[])
+{
+       return nla_get_u8(tb[IPSET_ATTR_PROTOCOL]);
+}
+
 static inline bool
 protocol_failed(const struct nlattr * const tb[])
 {
-       return !tb[IPSET_ATTR_PROTOCOL] ||
-              nla_get_u8(tb[IPSET_ATTR_PROTOCOL]) != IPSET_PROTOCOL;
+       return !tb[IPSET_ATTR_PROTOCOL] || protocol(tb) != IPSET_PROTOCOL;
+}
+
+static inline bool
+protocol_min_failed(const struct nlattr * const tb[])
+{
+       return !tb[IPSET_ATTR_PROTOCOL] || protocol(tb) < IPSET_PROTOCOL_MIN;
 }
 
 static inline u32
@@ -903,7 +913,7 @@ IPSET_CBFN(ip_set_create, struct net *n, struct sock *ctnl,
        u32 flags = flag_exist(nlh);
        int ret = 0;
 
-       if (unlikely(protocol_failed(attr) ||
+       if (unlikely(protocol_min_failed(attr) ||
                     !attr[IPSET_ATTR_SETNAME] ||
                     !attr[IPSET_ATTR_TYPENAME] ||
                     !attr[IPSET_ATTR_REVISION] ||
@@ -1042,7 +1052,7 @@ IPSET_CBFN(ip_set_destroy, struct net *net, struct sock *ctnl,
        ip_set_id_t i;
        int ret = 0;
 
-       if (unlikely(protocol_failed(attr)))
+       if (unlikely(protocol_min_failed(attr)))
                return -IPSET_ERR_PROTOCOL;
 
        /* Must wait for flush to be really finished in list:set */
@@ -1121,7 +1131,7 @@ IPSET_CBFN(ip_set_flush, struct net *net, struct sock *ctnl,
        struct ip_set *s;
        ip_set_id_t i;
 
-       if (unlikely(protocol_failed(attr)))
+       if (unlikely(protocol_min_failed(attr)))
                return -IPSET_ERR_PROTOCOL;
 
        if (!attr[IPSET_ATTR_SETNAME]) {
@@ -1164,7 +1174,7 @@ IPSET_CBFN(ip_set_rename, struct net *net, struct sock *ctnl,
        ip_set_id_t i;
        int ret = 0;
 
-       if (unlikely(protocol_failed(attr) ||
+       if (unlikely(protocol_min_failed(attr) ||
                     !attr[IPSET_ATTR_SETNAME] ||
                     !attr[IPSET_ATTR_SETNAME2]))
                return -IPSET_ERR_PROTOCOL;
@@ -1214,7 +1224,7 @@ IPSET_CBFN(ip_set_swap, struct net *net, struct sock *ctnl,
        ip_set_id_t from_id, to_id;
        char from_name[IPSET_MAXNAMELEN];
 
-       if (unlikely(protocol_failed(attr) ||
+       if (unlikely(protocol_min_failed(attr) ||
                     !attr[IPSET_ATTR_SETNAME] ||
                     !attr[IPSET_ATTR_SETNAME2]))
                return -IPSET_ERR_PROTOCOL;
@@ -1309,6 +1319,7 @@ dump_init(struct netlink_callback *cb, struct ip_set_net *inst)
        NLA_PARSE(cda, IPSET_ATTR_CMD_MAX, attr, nlh->nlmsg_len - min_len,
                  ip_set_setname_policy, NULL);
 
+       cb->args[IPSET_CB_PROTO] = nla_get_u8(cda[IPSET_ATTR_PROTOCOL]);
        if (cda[IPSET_ATTR_SETNAME]) {
                struct ip_set *set;
 
@@ -1410,7 +1421,8 @@ dump_last:
                        ret = -EMSGSIZE;
                        goto release_refcount;
                }
-               if (nla_put_u8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL) ||
+               if (nla_put_u8(skb, IPSET_ATTR_PROTOCOL,
+                              cb->args[IPSET_CB_PROTO]) ||
                    nla_put_string(skb, IPSET_ATTR_SETNAME, set->name))
                        goto nla_put_failure;
                if (dump_flags & IPSET_FLAG_LIST_SETNAME)
@@ -1425,6 +1437,9 @@ dump_last:
                            nla_put_u8(skb, IPSET_ATTR_REVISION,
                                       set->revision))
                                goto nla_put_failure;
+                       if (cb->args[IPSET_CB_PROTO] > IPSET_PROTOCOL_MIN &&
+                           nla_put_net16(skb, IPSET_ATTR_INDEX, htons(index)))
+                               goto nla_put_failure;
                        ret = set->variant->head(set, skb);
                        if (ret < 0)
                                goto release_refcount;
@@ -1485,7 +1500,7 @@ IPSET_CBFN(ip_set_dump, struct net *net, struct sock *ctnl,
           const struct nlattr * const attr[],
           struct netlink_ext_ack *extack)
 {
-       if (unlikely(protocol_failed(attr)))
+       if (unlikely(protocol_min_failed(attr)))
                return -IPSET_ERR_PROTOCOL;
 
 #if HAVE_NETLINK_DUMP_START_ARGS == 5
@@ -1590,7 +1605,7 @@ IPSET_CBFN(ip_set_uadd, struct net *net, struct sock *ctnl,
        bool use_lineno;
        int ret = 0;
 
-       if (unlikely(protocol_failed(attr) ||
+       if (unlikely(protocol_min_failed(attr) ||
                     !attr[IPSET_ATTR_SETNAME] ||
                     !((attr[IPSET_ATTR_DATA] != NULL) ^
                       (attr[IPSET_ATTR_ADT] != NULL)) ||
@@ -1646,7 +1661,7 @@ IPSET_CBFN(ip_set_udel, struct net *net, struct sock *ctnl,
        bool use_lineno;
        int ret = 0;
 
-       if (unlikely(protocol_failed(attr) ||
+       if (unlikely(protocol_min_failed(attr) ||
                     !attr[IPSET_ATTR_SETNAME] ||
                     !((attr[IPSET_ATTR_DATA] != NULL) ^
                       (attr[IPSET_ATTR_ADT] != NULL)) ||
@@ -1700,7 +1715,7 @@ IPSET_CBFN(ip_set_utest, struct net *net, struct sock *ctnl,
        struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
        int ret = 0;
 
-       if (unlikely(protocol_failed(attr) ||
+       if (unlikely(protocol_min_failed(attr) ||
                     !attr[IPSET_ATTR_SETNAME] ||
                     !attr[IPSET_ATTR_DATA] ||
                     !flag_nested(attr[IPSET_ATTR_DATA])))
@@ -1738,7 +1753,7 @@ IPSET_CBFN(ip_set_header, struct net *net, struct sock *ctnl,
        struct nlmsghdr *nlh2;
        int ret = 0;
 
-       if (unlikely(protocol_failed(attr) ||
+       if (unlikely(protocol_min_failed(attr) ||
                     !attr[IPSET_ATTR_SETNAME]))
                return -IPSET_ERR_PROTOCOL;
 
@@ -1754,7 +1769,7 @@ IPSET_CBFN(ip_set_header, struct net *net, struct sock *ctnl,
                         IPSET_CMD_HEADER);
        if (!nlh2)
                goto nlmsg_failure;
-       if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL) ||
+       if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, protocol(attr)) ||
            nla_put_string(skb2, IPSET_ATTR_SETNAME, set->name) ||
            nla_put_string(skb2, IPSET_ATTR_TYPENAME, set->type->name) ||
            nla_put_u8(skb2, IPSET_ATTR_FAMILY, set->family) ||
@@ -1796,7 +1811,7 @@ IPSET_CBFN(ip_set_type, struct net *net, struct sock *ctnl,
        const char *typename;
        int ret = 0;
 
-       if (unlikely(protocol_failed(attr) ||
+       if (unlikely(protocol_min_failed(attr) ||
                     !attr[IPSET_ATTR_TYPENAME] ||
                     !attr[IPSET_ATTR_FAMILY]))
                return -IPSET_ERR_PROTOCOL;
@@ -1815,7 +1830,7 @@ IPSET_CBFN(ip_set_type, struct net *net, struct sock *ctnl,
                         IPSET_CMD_TYPE);
        if (!nlh2)
                goto nlmsg_failure;
-       if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL) ||
+       if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, protocol(attr)) ||
            nla_put_string(skb2, IPSET_ATTR_TYPENAME, typename) ||
            nla_put_u8(skb2, IPSET_ATTR_FAMILY, family) ||
            nla_put_u8(skb2, IPSET_ATTR_REVISION, max) ||
@@ -1867,6 +1882,113 @@ IPSET_CBFN(ip_set_protocol, struct net *net, struct sock *ctnl,
                goto nlmsg_failure;
        if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL))
                goto nla_put_failure;
+       if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL_MIN, IPSET_PROTOCOL_MIN))
+               goto nla_put_failure;
+       nlmsg_end(skb2, nlh2);
+
+       ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+
+nla_put_failure:
+       nlmsg_cancel(skb2, nlh2);
+nlmsg_failure:
+       kfree_skb(skb2);
+       return -EMSGSIZE;
+}
+
+/* Get set by name or index, from userspace */
+
+static int
+IPSET_CBFN(ip_set_byname, struct net *net, struct sock *ctnl,
+          struct sk_buff *skb, const struct nlmsghdr *nlh,
+          const struct nlattr * const attr[],
+          struct netlink_ext_ack *extack)
+{
+       struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
+       struct sk_buff *skb2;
+       struct nlmsghdr *nlh2;
+       ip_set_id_t id = IPSET_INVALID_ID;
+       const struct ip_set *set;
+       int ret = 0;
+
+       if (unlikely(protocol_failed(attr) ||
+                    !attr[IPSET_ATTR_SETNAME]))
+               return -IPSET_ERR_PROTOCOL;
+
+       set = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]), &id);
+       if (id == IPSET_INVALID_ID)
+               return -ENOENT;
+
+       skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!skb2)
+               return -ENOMEM;
+
+       nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
+                        IPSET_CMD_GET_BYNAME);
+       if (!nlh2)
+               goto nlmsg_failure;
+       if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, protocol(attr)) ||
+           nla_put_u8(skb2, IPSET_ATTR_FAMILY, set->family) ||
+           nla_put_net16(skb2, IPSET_ATTR_INDEX, htons(id)))
+               goto nla_put_failure;
+       nlmsg_end(skb2, nlh2);
+
+       ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+
+nla_put_failure:
+       nlmsg_cancel(skb2, nlh2);
+nlmsg_failure:
+       kfree_skb(skb2);
+       return -EMSGSIZE;
+}
+
+static const struct nla_policy ip_set_index_policy[IPSET_ATTR_CMD_MAX + 1] = {
+       [IPSET_ATTR_PROTOCOL]   = { .type = NLA_U8 },
+       [IPSET_ATTR_INDEX]      = { .type = NLA_U16 },
+};
+
+static int
+IPSET_CBFN(ip_set_byindex, struct net *net, struct sock *ctnl,
+          struct sk_buff *skb, const struct nlmsghdr *nlh,
+          const struct nlattr * const attr[],
+          struct netlink_ext_ack *extack)
+{
+       struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
+       struct sk_buff *skb2;
+       struct nlmsghdr *nlh2;
+       ip_set_id_t id = IPSET_INVALID_ID;
+       const struct ip_set *set;
+       int ret = 0;
+
+       if (unlikely(protocol_failed(attr) ||
+                    !attr[IPSET_ATTR_INDEX]))
+               return -IPSET_ERR_PROTOCOL;
+
+       id = ip_set_get_h16(attr[IPSET_ATTR_INDEX]);
+       if (id >= inst->ip_set_max)
+               return -ENOENT;
+       set = ip_set(inst, id);
+       if (set == NULL)
+               return -ENOENT;
+
+       skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!skb2)
+               return -ENOMEM;
+
+       nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
+                        IPSET_CMD_GET_BYINDEX);
+       if (!nlh2)
+               goto nlmsg_failure;
+       if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, protocol(attr)) ||
+           nla_put_string(skb, IPSET_ATTR_SETNAME, set->name))
+               goto nla_put_failure;
        nlmsg_end(skb2, nlh2);
 
        ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
@@ -1952,6 +2074,16 @@ static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
                .attr_count     = IPSET_ATTR_CMD_MAX,
                .policy         = ip_set_protocol_policy,
        },
+       [IPSET_CMD_GET_BYNAME]  = {
+               .call           = ip_set_byname,
+               .attr_count     = IPSET_ATTR_CMD_MAX,
+               .policy         = ip_set_setname_policy,
+       },
+       [IPSET_CMD_GET_BYINDEX] = {
+               .call           = ip_set_byindex,
+               .attr_count     = IPSET_ATTR_CMD_MAX,
+               .policy         = ip_set_index_policy,
+       },
 };
 
 static struct nfnetlink_subsystem ip_set_netlink_subsys __read_mostly = {
@@ -1997,7 +2129,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
                        goto done;
                }
 
-               if (req_version->version != IPSET_PROTOCOL) {
+               if (req_version->version < IPSET_PROTOCOL_MIN) {
                        ret = -EPROTO;
                        goto done;
                }
index aa8fc647de0ad0abf1be6028b7d25bb15063050c..97a6b7c3781b0b7650a0f729f40c342b9fbc451b 100644 (file)
@@ -1,3 +1,5 @@
+PROTOCOL 6:
+
 req:   msg:    IPSET_CMD_PROTOCOL
        attr:   IPSET_ATTR_PROTOCOL
 
@@ -88,3 +90,18 @@ resp:        attr:   IPSET_ATTR_TYPENAME
                IPSET_ATTR_FAMILY
                IPSET_ATTR_REVISION     (version max)
                IPSET_ATTR_REVISION_MIN (version min, optional)
+
+PROTOCOL 7: PROTOCOL 6 +
+
+req:   msg:    IPSET_CMD_GET_BYNAME
+       attr:   IPSET_ATTR_PROTOCOL
+               IPSET_ATTR_SETNAME
+
+resp:  attr:   IPSET_ATTR_INDEX
+               IPSET_ATTR_FAMILY
+
+req:   msg:    IPSET_CMD_GET_BYINDEX
+       attr:   IPSET_ATTR_PROTOCOL
+               IPSET_ATTR_INDEX
+
+resp:  attr:   IPSET_ATTR_SETNAME
index f9327198e44eaeae6cac298dc01fc56acf68be85..a0cea4fc13ed1e0564b2808b4e44b8ed10d2a4af 100644 (file)
@@ -286,7 +286,7 @@ ipset_keyword(enum ipset_keywords i)
 }
 
 const char *
-ipset_ignored_optname(int opt)
+ipset_ignored_optname(unsigned int opt)
 {
        enum ipset_keywords i;
 
index 8372a2ffb8c4e6639e5561e8e28f191c661bca1a..9a7c861add3b4ce54b0a6d050287c7abe7cfff10 100644 (file)
@@ -44,6 +44,7 @@ struct ipset_data {
        uint32_t mark;
        uint16_t port;
        uint16_t port_to;
+       uint16_t index;
        union {
                /* RENAME/SWAP */
                char setname2[IPSET_MAXNAMELEN];
@@ -281,6 +282,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
        case IPSET_OPT_TIMEOUT:
                data->timeout = *(const uint32_t *) value;
                break;
+       case IPSET_OPT_INDEX:
+               data->index = *(const uint16_t *) value;
+               break;
        /* Create-specific options */
        case IPSET_OPT_GC:
                data->create.gc = *(const uint32_t *) value;
@@ -485,6 +489,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
                return &data->port_to;
        case IPSET_OPT_TIMEOUT:
                return &data->timeout;
+       case IPSET_OPT_INDEX:
+               return &data->index;
        /* Create-specific options */
        case IPSET_OPT_GC:
                return &data->create.gc;
@@ -588,6 +594,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
        case IPSET_OPT_PORT:
        case IPSET_OPT_PORT_TO:
        case IPSET_OPT_SKBQUEUE:
+       case IPSET_OPT_INDEX:
                return sizeof(uint16_t);
        case IPSET_SETNAME:
        case IPSET_OPT_NAME:
index c19191a32fabf054a066dc8c374d640d0c54f20b..768cc0581be3824302d6ff699f7827c5ab6d78da 100644 (file)
@@ -365,6 +365,10 @@ static const struct ipset_attr_policy cmd_attrs[] = {
                .type = MNL_TYPE_U32,
                .opt = IPSET_OPT_LINENO,
        },
+       [IPSET_ATTR_INDEX] = {
+               .type = MNL_TYPE_U16,
+               .opt = IPSET_OPT_INDEX,
+       },
 };
 
 static const struct ipset_attr_policy create_attrs[] = {