From 7cd41b5387acf84088e9299a796f7c2c72339a1a Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Thu, 30 Jan 2020 01:16:33 +0100 Subject: set: Add support for NFTA_SET_DESC_CONCAT attributes If NFTNL_SET_DESC_CONCAT data is passed, pass that to the kernel as NFTA_SET_DESC_CONCAT attributes: it describes the length of single concatenated fields, in bytes. Similarly, parse NFTA_SET_DESC_CONCAT attributes if received from the kernel. This is the libnftnl counterpart for nftables patch: src: Add support for NFTNL_SET_DESC_CONCAT v4: - move NFTNL_SET_DESC_CONCAT to the end of enum nftnl_set_attr to avoid ABI breakage (Pablo Neira Ayuso) v3: - use NFTNL_SET_DESC_CONCAT and NFTA_SET_DESC_CONCAT instead of a stand-alone NFTA_SET_SUBKEY attribute (Pablo Neira Ayuso) - pass field length in bytes instead of bits, fields would get unnecessarily big otherwise v2: - fixed grammar in commit message - removed copy of array bytes in nftnl_set_nlmsg_build_subkey_payload(), we're simply passing values to htonl() (Phil Sutter) Signed-off-by: Stefano Brivio Signed-off-by: Pablo Neira Ayuso --- include/libnftnl/set.h | 1 + include/set.h | 2 + src/set.c | 111 ++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 95 insertions(+), 19 deletions(-) diff --git a/include/libnftnl/set.h b/include/libnftnl/set.h index db3fa68..bbbf58d 100644 --- a/include/libnftnl/set.h +++ b/include/libnftnl/set.h @@ -29,6 +29,7 @@ enum nftnl_set_attr { NFTNL_SET_USERDATA, NFTNL_SET_OBJ_TYPE, NFTNL_SET_HANDLE, + NFTNL_SET_DESC_CONCAT, __NFTNL_SET_MAX }; #define NFTNL_SET_MAX (__NFTNL_SET_MAX - 1) diff --git a/include/set.h b/include/set.h index 446acd2..895ffdb 100644 --- a/include/set.h +++ b/include/set.h @@ -25,6 +25,8 @@ struct nftnl_set { enum nft_set_policies policy; struct { uint32_t size; + uint8_t field_len[NFT_REG32_COUNT]; + uint8_t field_count; } desc; struct list_head element_list; diff --git a/src/set.c b/src/set.c index 78447c6..651dcfa 100644 --- a/src/set.c +++ b/src/set.c @@ -89,6 +89,7 @@ void nftnl_set_unset(struct nftnl_set *s, uint16_t attr) case NFTNL_SET_ID: case NFTNL_SET_POLICY: case NFTNL_SET_DESC_SIZE: + case NFTNL_SET_DESC_CONCAT: case NFTNL_SET_TIMEOUT: case NFTNL_SET_GC_INTERVAL: break; @@ -174,6 +175,10 @@ int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data, case NFTNL_SET_DESC_SIZE: memcpy(&s->desc.size, data, sizeof(s->desc.size)); break; + case NFTNL_SET_DESC_CONCAT: + memcpy(&s->desc.field_len, data, data_len); + while (s->desc.field_len[++s->desc.field_count]); + break; case NFTNL_SET_TIMEOUT: memcpy(&s->timeout, data, sizeof(s->timeout)); break; @@ -266,6 +271,9 @@ const void *nftnl_set_get_data(const struct nftnl_set *s, uint16_t attr, case NFTNL_SET_DESC_SIZE: *data_len = sizeof(uint32_t); return &s->desc.size; + case NFTNL_SET_DESC_CONCAT: + *data_len = s->desc.field_count; + return s->desc.field_len; case NFTNL_SET_TIMEOUT: *data_len = sizeof(uint64_t); return &s->timeout; @@ -351,13 +359,42 @@ err: return NULL; } +static void nftnl_set_nlmsg_build_desc_size_payload(struct nlmsghdr *nlh, + struct nftnl_set *s) +{ + mnl_attr_put_u32(nlh, NFTA_SET_DESC_SIZE, htonl(s->desc.size)); +} + +static void nftnl_set_nlmsg_build_desc_concat_payload(struct nlmsghdr *nlh, + struct nftnl_set *s) +{ + struct nlattr *nest; + int i; + + nest = mnl_attr_nest_start(nlh, NFTA_SET_DESC_CONCAT); + for (i = 0; i < NFT_REG32_COUNT && i < s->desc.field_count; i++) { + struct nlattr *nest_elem; + + nest_elem = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM); + mnl_attr_put_u32(nlh, NFTA_SET_FIELD_LEN, + htonl(s->desc.field_len[i])); + mnl_attr_nest_end(nlh, nest_elem); + } + mnl_attr_nest_end(nlh, nest); +} + static void nftnl_set_nlmsg_build_desc_payload(struct nlmsghdr *nlh, struct nftnl_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)); + + if (s->flags & (1 << NFTNL_SET_DESC_SIZE)) + nftnl_set_nlmsg_build_desc_size_payload(nlh, s); + if (s->flags & (1 << NFTNL_SET_DESC_CONCAT)) + nftnl_set_nlmsg_build_desc_concat_payload(nlh, s); + mnl_attr_nest_end(nlh, nest); } @@ -387,7 +424,7 @@ void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s) mnl_attr_put_u32(nlh, NFTA_SET_ID, htonl(s->id)); if (s->flags & (1 << NFTNL_SET_POLICY)) mnl_attr_put_u32(nlh, NFTA_SET_POLICY, htonl(s->policy)); - if (s->flags & (1 << NFTNL_SET_DESC_SIZE)) + if (s->flags & (1 << NFTNL_SET_DESC_SIZE | 1 << NFTNL_SET_DESC_CONCAT)) nftnl_set_nlmsg_build_desc_payload(nlh, s); if (s->flags & (1 << NFTNL_SET_TIMEOUT)) mnl_attr_put_u64(nlh, NFTA_SET_TIMEOUT, htobe64(s->timeout)); @@ -445,39 +482,75 @@ static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data) return MNL_CB_OK; } -static int nftnl_set_desc_parse_attr_cb(const struct nlattr *attr, void *data) +static int +nftnl_set_desc_concat_field_parse_attr_cb(const struct nlattr *attr, void *data) +{ + int type = mnl_attr_get_type(attr); + struct nftnl_set *s = data; + + if (type != NFTA_SET_FIELD_LEN) + return MNL_CB_OK; + + if (mnl_attr_validate(attr, MNL_TYPE_U32)) + return MNL_CB_ERROR; + + s->desc.field_len[s->desc.field_count] = ntohl(mnl_attr_get_u32(attr)); + s->desc.field_count++; + + return MNL_CB_OK; +} + +static int +nftnl_set_desc_concat_parse_attr_cb(const struct nlattr *attr, void *data) { - const struct nlattr **tb = data; int type = mnl_attr_get_type(attr); + struct nftnl_set *s = data; + + if (type != NFTA_LIST_ELEM) + return MNL_CB_OK; + + return mnl_attr_parse_nested(attr, + nftnl_set_desc_concat_field_parse_attr_cb, + s); +} + +static int nftnl_set_desc_parse_attr_cb(const struct nlattr *attr, void *data) +{ + int type = mnl_attr_get_type(attr), err; + struct nftnl_set *s = data; if (mnl_attr_type_valid(attr, NFTA_SET_DESC_MAX) < 0) return MNL_CB_OK; switch (type) { case NFTA_SET_DESC_SIZE: - if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { abi_breakage(); + break; + } + + s->desc.size = ntohl(mnl_attr_get_u32(attr)); + s->flags |= (1 << NFTNL_SET_DESC_SIZE); + break; + case NFTA_SET_DESC_CONCAT: + err = mnl_attr_parse_nested(attr, + nftnl_set_desc_concat_parse_attr_cb, + s); + if (err != MNL_CB_OK) + abi_breakage(); + + s->flags |= (1 << NFTNL_SET_DESC_CONCAT); + break; + default: break; } - tb[type] = attr; return MNL_CB_OK; } -static int nftnl_set_desc_parse(struct nftnl_set *s, - const struct nlattr *attr) +static int nftnl_set_desc_parse(struct nftnl_set *s, const struct nlattr *attr) { - struct nlattr *tb[NFTA_SET_DESC_MAX + 1] = {}; - - if (mnl_attr_parse_nested(attr, nftnl_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 << NFTNL_SET_DESC_SIZE); - } - - return 0; + return mnl_attr_parse_nested(attr, nftnl_set_desc_parse_attr_cb, s); } EXPORT_SYMBOL(nftnl_set_nlmsg_parse); -- cgit v1.2.3