@@ -29,6 +29,7 @@ enum nftnl_set_attr {
NFTNL_SET_USERDATA,
NFTNL_SET_OBJ_TYPE,
NFTNL_SET_HANDLE,
+ NFTNL_SET_SUBKEY,
__NFTNL_SET_MAX
};
#define NFTNL_SET_MAX (__NFTNL_SET_MAX - 1)
@@ -31,6 +31,8 @@ struct nftnl_set {
uint32_t flags;
uint32_t gc_interval;
uint64_t timeout;
+
+ uint8_t subkey_len[NFT_REG32_COUNT];
};
struct nftnl_set_list;
@@ -91,6 +91,7 @@ void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
case NFTNL_SET_DESC_SIZE:
case NFTNL_SET_TIMEOUT:
case NFTNL_SET_GC_INTERVAL:
+ case NFTNL_SET_SUBKEY:
break;
case NFTNL_SET_USERDATA:
xfree(s->user.data);
@@ -115,6 +116,7 @@ static uint32_t nftnl_set_validate[NFTNL_SET_MAX + 1] = {
[NFTNL_SET_DESC_SIZE] = sizeof(uint32_t),
[NFTNL_SET_TIMEOUT] = sizeof(uint64_t),
[NFTNL_SET_GC_INTERVAL] = sizeof(uint32_t),
+ [NFTNL_SET_SUBKEY] = sizeof(uint8_t) * NFT_REG32_COUNT,
};
EXPORT_SYMBOL(nftnl_set_set_data);
@@ -190,6 +192,9 @@ int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
memcpy(s->user.data, data, data_len);
s->user.len = data_len;
break;
+ case NFTNL_SET_SUBKEY:
+ memcpy(s->subkey_len, data, data_len);
+ break;
}
s->flags |= (1 << attr);
return 0;
@@ -361,6 +366,22 @@ nftnl_set_nlmsg_build_desc_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
mnl_attr_nest_end(nlh, nest);
}
+static void
+nftnl_set_nlmsg_build_subkey_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
+{
+ struct nlattr *nest;
+ int i;
+
+ nest = mnl_attr_nest_start(nlh, NFTA_SET_SUBKEY);
+
+ for (i = 0; i < NFT_REG32_COUNT && s->subkey_len[i]; i++) {
+ mnl_attr_put_u32(nlh, NFTA_SET_SUBKEY_LEN,
+ htonl(s->subkey_len[i]));
+ }
+
+ mnl_attr_nest_end(nlh, nest);
+}
+
EXPORT_SYMBOL(nftnl_set_nlmsg_build_payload);
void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
{
@@ -395,6 +416,8 @@ void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
mnl_attr_put_u32(nlh, NFTA_SET_GC_INTERVAL, htonl(s->gc_interval));
if (s->flags & (1 << NFTNL_SET_USERDATA))
mnl_attr_put(nlh, NFTA_SET_USERDATA, s->user.len, s->user.data);
+ if (s->flags & (1 << NFTNL_SET_SUBKEY))
+ nftnl_set_nlmsg_build_subkey_payload(nlh, s);
}
@@ -439,6 +462,10 @@ static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data)
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
abi_breakage();
break;
+ case NFTA_SET_SUBKEY:
+ if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+ abi_breakage();
+ break;
}
tb[type] = attr;
If the NFTNL_SET_SUBKEY flag is passed, send one NFTA_SET_SUBKEY attribute for each subkey_len attribute in the set description. Note that our internal representation, and nftables storage, for these attributes, is 8-bit wide, but the kernel uses 32 bits. As field length is expressed in bits, this is probably a good compromise to keep the UAPI future-proof and memory footprint to a minimum, for the moment being. This is the libnftnl counterpart for nftables patch: src: Add support for and export NFT_SET_SUBKEY attributes and it has a UAPI dependency on kernel patch: [PATCH nf-next 1/8] nf_tables: Support for subkeys, set with multiple ranged fields 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 <sbrivio@redhat.com> --- include/libnftnl/set.h | 1 + include/set.h | 2 ++ src/set.c | 27 +++++++++++++++++++++++++++ 3 files changed, 30 insertions(+)