]> git.ipfire.org Git - thirdparty/libnftnl.git/commitdiff
set: add support for set mechanism selection
authorArturo Borrero <arturo.borrero.glez@gmail.com>
Mon, 14 Jul 2014 08:41:26 +0000 (10:41 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 24 Jul 2014 10:49:13 +0000 (12:49 +0200)
This patch adds support to select the set mechanism.
The kernel support was added in commit:

 c50b960 netfilter: nf_tables: implement proper set selection

Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/libnftnl/set.h
src/internal.h
src/set.c

index 4d08f168b5dfc534be75d984f64b5f6762e781c1..864a8034c6290c21f2e036d9d03b87869a3e7fe7 100644 (file)
@@ -18,6 +18,8 @@ enum {
        NFT_SET_ATTR_DATA_LEN,
        NFT_SET_ATTR_FAMILY,
        NFT_SET_ATTR_ID,
+       NFT_SET_ATTR_POLICY,
+       NFT_SET_ATTR_DESC_SIZE,
        __NFT_SET_ATTR_MAX
 };
 #define NFT_SET_ATTR_MAX (__NFT_SET_ATTR_MAX - 1)
index 7b848db09b14230c97a50c123a05433c2d718166..e76a5cb2b0db8498e9d93bec34732324f963de7c 100644 (file)
@@ -14,6 +14,7 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <libnftnl/common.h>
+#include <linux/netfilter/nf_tables.h>
 
 #define BASE_DEC 10
 #define BASE_HEX 16
@@ -168,6 +169,10 @@ struct nft_set {
        uint32_t                data_type;
        uint32_t                data_len;
        uint32_t                id;
+       enum nft_set_policies   policy;
+       struct {
+               uint32_t                size;
+       } desc;
        struct list_head        element_list;
 
        uint32_t                flags;
index ee7f98348a2ec614d1d66cbc73c7cf37bb280590..3c38334b1e9a5674fdf8a5f8a5465edb20bcdeee 100644 (file)
--- a/src/set.c
+++ b/src/set.c
@@ -88,6 +88,8 @@ void nft_set_attr_unset(struct nft_set *s, uint16_t attr)
        case NFT_SET_ATTR_DATA_LEN:
        case NFT_SET_ATTR_FAMILY:
        case NFT_SET_ATTR_ID:
+       case NFT_SET_ATTR_POLICY:
+       case NFT_SET_ATTR_DESC_SIZE:
                break;
        default:
                return;
@@ -104,6 +106,8 @@ static uint32_t nft_set_attr_validate[NFT_SET_ATTR_MAX + 1] = {
        [NFT_SET_ATTR_DATA_TYPE]        = sizeof(uint32_t),
        [NFT_SET_ATTR_DATA_LEN]         = sizeof(uint32_t),
        [NFT_SET_ATTR_FAMILY]           = sizeof(uint32_t),
+       [NFT_SET_ATTR_POLICY]           = sizeof(uint32_t),
+       [NFT_SET_ATTR_DESC_SIZE]        = sizeof(uint32_t),
 };
 
 void nft_set_attr_set_data(struct nft_set *s, uint16_t attr, const void *data,
@@ -148,6 +152,12 @@ void nft_set_attr_set_data(struct nft_set *s, uint16_t attr, const void *data,
        case NFT_SET_ATTR_ID:
                s->id = *((uint32_t *)data);
                break;
+       case NFT_SET_ATTR_POLICY:
+               s->policy = *((uint32_t *)data);
+               break;
+       case NFT_SET_ATTR_DESC_SIZE:
+               s->desc.size = *((uint32_t *)data);
+               break;
        }
        s->flags |= (1 << attr);
 }
@@ -203,6 +213,12 @@ const void *nft_set_attr_get_data(struct nft_set *s, uint16_t attr,
        case NFT_SET_ATTR_ID:
                *data_len = sizeof(uint32_t);
                return &s->id;
+       case NFT_SET_ATTR_POLICY:
+               *data_len = sizeof(uint32_t);
+               return &s->policy;
+       case NFT_SET_ATTR_DESC_SIZE:
+               *data_len = sizeof(uint32_t);
+               return &s->desc.size;
        }
        return NULL;
 }
@@ -232,6 +248,16 @@ uint32_t nft_set_attr_get_u32(struct nft_set *s, uint16_t attr)
 }
 EXPORT_SYMBOL(nft_set_attr_get_u32);
 
+static void
+nft_set_nlmsg_build_desc_payload(struct nlmsghdr *nlh, struct nft_set *s)
+{
+       struct nlattr *nest;
+
+       nest = mnl_attr_nest_start(nlh, NFTA_SET_DESC);
+       mnl_attr_put_u32(nlh, NFTA_SET_DESC_SIZE, htonl(s->desc.size));
+       mnl_attr_nest_end(nlh, nest);
+}
+
 void nft_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_set *s)
 {
        if (s->flags & (1 << NFT_SET_ATTR_TABLE))
@@ -251,6 +277,10 @@ void nft_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_set *s)
                mnl_attr_put_u32(nlh, NFTA_SET_DATA_LEN, htonl(s->data_len));
        if (s->flags & (1 << NFT_SET_ATTR_ID))
                mnl_attr_put_u32(nlh, NFTA_SET_ID, htonl(s->id));
+       if (s->flags & (1 << NFT_SET_ATTR_POLICY))
+               mnl_attr_put_u32(nlh, NFTA_SET_POLICY, htonl(s->policy));
+       if (s->flags & (1 << NFT_SET_ATTR_DESC_SIZE))
+               nft_set_nlmsg_build_desc_payload(nlh, s);
 }
 EXPORT_SYMBOL(nft_set_nlmsg_build_payload);
 
@@ -274,6 +304,30 @@ static int nft_set_parse_attr_cb(const struct nlattr *attr, void *data)
        case NFTA_SET_DATA_TYPE:
        case NFTA_SET_DATA_LEN:
        case NFTA_SET_ID:
+       case NFTA_SET_POLICY:
+               if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+                       abi_breakage();
+               break;
+       case NFTA_SET_DESC:
+               if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+                       abi_breakage();
+               break;
+       }
+
+       tb[type] = attr;
+       return MNL_CB_OK;
+}
+
+static int nft_set_desc_parse_attr_cb(const struct nlattr *attr, void *data)
+{
+       const struct nlattr **tb = data;
+       int type = mnl_attr_get_type(attr);
+
+       if (mnl_attr_type_valid(attr, NFTA_SET_MAX) < 0)
+               return MNL_CB_OK;
+
+       switch (type) {
+       case NFTA_SET_DESC_SIZE:
                if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
                        abi_breakage();
                break;
@@ -283,10 +337,45 @@ static int nft_set_parse_attr_cb(const struct nlattr *attr, void *data)
        return MNL_CB_OK;
 }
 
+static int nft_set_desc_parse(struct nft_set *s,
+                             const struct nlattr *attr)
+{
+       struct nlattr *tb[NFTA_SET_MAX+1] = {};
+
+       if (mnl_attr_parse_nested(attr, nft_set_desc_parse_attr_cb, tb) < 0)
+               return -1;
+
+       if (tb[NFTA_SET_DESC_SIZE]) {
+               s->desc.size = ntohl(mnl_attr_get_u32(tb[NFTA_SET_DESC_SIZE]));
+               s->flags |= (1 << NFT_SET_ATTR_DESC_SIZE);
+       }
+
+       return 0;
+}
+
+static int nft_set_nlmsg_desc_parse(const struct nlattr *nest,
+                                   struct nft_set *s)
+{
+       struct nlattr *attr;
+       int ret = 0;
+
+       mnl_attr_for_each_nested(attr, nest) {
+               if (mnl_attr_get_type(attr) != NFTA_SET_DESC)
+                       return -1;
+
+               ret = nft_set_desc_parse(s, attr);
+               if (ret != 0)
+                       break;
+       }
+
+       return ret;
+}
+
 int nft_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set *s)
 {
        struct nlattr *tb[NFTA_SET_MAX+1] = {};
        struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+       int ret = 0;
 
        if (mnl_attr_parse(nlh, sizeof(*nfg), nft_set_parse_attr_cb, tb) < 0)
                return -1;
@@ -323,10 +412,17 @@ int nft_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set *s)
                s->id = ntohl(mnl_attr_get_u32(tb[NFTA_SET_ID]));
                s->flags |= (1 << NFT_SET_ATTR_ID);
        }
+       if (tb[NFTA_SET_POLICY]) {
+               s->policy = ntohl(mnl_attr_get_u32(tb[NFTA_SET_POLICY]));
+               s->flags |= (1 << NFT_SET_ATTR_POLICY);
+       }
+       if (tb[NFTA_SET_DESC])
+               ret = nft_set_nlmsg_desc_parse(tb[NFTA_SET_DESC], s);
+
        s->family = nfg->nfgen_family;
        s->flags |= (1 << NFT_SET_ATTR_FAMILY);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL(nft_set_nlmsg_parse);
 
@@ -335,7 +431,7 @@ int nft_jansson_parse_set(struct nft_set *s, json_t *tree,
                          struct nft_parse_err *err)
 {
        json_t *root, *array, *json_elem;
-       uint32_t flags, key_type, key_len, data_type, data_len;
+       uint32_t flags, key_type, key_len, data_type, data_len, policy, size;
        int family, i;
        const char *name, *table;
        struct nft_set_elem *elem;
@@ -386,6 +482,22 @@ int nft_jansson_parse_set(struct nft_set *s, json_t *tree,
                nft_set_attr_set_u32(s, NFT_SET_ATTR_DATA_LEN, data_len);
        }
 
+       if (nft_jansson_node_exist(root, "policy")) {
+               if (nft_jansson_parse_val(root, "policy", NFT_TYPE_U32,
+                                         &policy, err) < 0)
+                       return -1;
+
+               nft_set_attr_set_u32(s, NFT_SET_ATTR_POLICY, policy);
+       }
+
+       if (nft_jansson_node_exist(root, "desc_size")) {
+               if (nft_jansson_parse_val(root, "desc_size", NFT_TYPE_U32,
+                                         &size, err) < 0)
+                       return -1;
+
+               nft_set_attr_set_u32(s, NFT_SET_ATTR_DESC_SIZE, size);
+       }
+
        if (nft_jansson_node_exist(root, "set_elem")) {
                array = json_object_get(root, "set_elem");
                for (i = 0; i < json_array_size(array); i++) {
@@ -442,7 +554,7 @@ int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s,
        const char *name, *table;
        int family;
        uint32_t set_flags, key_type, key_len;
-       uint32_t data_type, data_len;
+       uint32_t data_type, data_len, policy, size;
 
        name = nft_mxml_str_parse(tree, "name", MXML_DESCEND_FIRST,
                                  NFT_XML_MAND, err);
@@ -487,6 +599,16 @@ int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s,
 
        }
 
+       if (nft_mxml_num_parse(tree, "policy", MXML_DESCEND_FIRST,
+                              BASE_DEC, &policy, NFT_TYPE_U32,
+                              NFT_XML_OPT, err) == 0)
+               nft_set_attr_set_u32(s, NFT_SET_ATTR_POLICY, policy);
+
+       if (nft_mxml_num_parse(tree, "desc_size", MXML_DESCEND_FIRST,
+                              BASE_DEC, &size, NFT_TYPE_U32,
+                              NFT_XML_OPT, err) == 0)
+               nft_set_attr_set_u32(s, NFT_SET_ATTR_DESC_SIZE, policy);
+
        for (node = mxmlFindElement(tree, tree, "set_elem", NULL,
                                    NULL, MXML_DESCEND);
                node != NULL;
@@ -613,6 +735,19 @@ static int nft_set_snprintf_json(char *buf, size_t size, struct nft_set *s,
                ret = snprintf(buf + offset, len, ",\"data_len\":%u", s->data_len);
                SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
        }
+
+       if (s->flags & (1 << NFT_SET_ATTR_POLICY)) {
+               ret = snprintf(buf + offset, len, ",\"policy\":%u",
+                              s->policy);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+
+       if (s->flags & (1 << NFT_SET_ATTR_DESC_SIZE)) {
+               ret = snprintf(buf + offset, len, ",\"desc_size\":%u",
+                              s->desc.size);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+
        /* Empty set? Skip printinf of elements */
        if (list_empty(&s->element_list)){
                ret = snprintf(buf + offset, len, "}}");
@@ -654,6 +789,16 @@ static int nft_set_snprintf_default(char *buf, size_t size, struct nft_set *s,
                        s->name, s->table, s->set_flags);
        SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
+       if (s->flags & (1 << NFT_SET_ATTR_POLICY)) {
+               ret = snprintf(buf + offset, len, " policy %u", s->policy);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+
+       if (s->flags & (1 << NFT_SET_ATTR_DESC_SIZE)) {
+               ret = snprintf(buf + offset, len, " size %u", s->desc.size);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+
        /* Empty set? Skip printinf of elements */
        if (list_empty(&s->element_list))
                return offset;
@@ -727,6 +872,18 @@ static int nft_set_snprintf_xml(char *buf, size_t size, struct nft_set *s,
                SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
        }
 
+       if (s->flags & (1 << NFT_SET_ATTR_POLICY)) {
+               ret = snprintf(buf + offset, len, "<policy>%u</policy>",
+                              s->policy);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+
+       if (s->flags & (1 << NFT_SET_ATTR_DESC_SIZE)) {
+               ret = snprintf(buf + offset, len, "<desc_size>%u</desc_size>",
+                              s->desc.size);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+
        if (!list_empty(&s->element_list)) {
                list_for_each_entry(elem, &s->element_list, head) {
                        ret = nft_set_elem_snprintf(buf + offset, len, elem,