summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/chain.c40
-rw-r--r--src/expr/bitwise.c60
-rw-r--r--src/expr/masq.c16
-rw-r--r--src/expr/nat.c2
-rw-r--r--src/flowtable.c19
-rw-r--r--src/libnftnl.map4
-rw-r--r--src/set.c27
-rw-r--r--src/set_elem.c37
8 files changed, 192 insertions, 13 deletions
diff --git a/src/chain.c b/src/chain.c
index b4066e4..5f12130 100644
--- a/src/chain.c
+++ b/src/chain.c
@@ -43,6 +43,7 @@ struct nftnl_chain {
uint32_t policy;
uint32_t hooknum;
int32_t prio;
+ uint32_t chain_flags;
uint32_t use;
uint64_t packets;
uint64_t bytes;
@@ -165,6 +166,7 @@ void nftnl_chain_unset(struct nftnl_chain *c, uint16_t attr)
case NFTNL_CHAIN_PACKETS:
case NFTNL_CHAIN_HANDLE:
case NFTNL_CHAIN_FAMILY:
+ case NFTNL_CHAIN_FLAGS:
break;
case NFTNL_CHAIN_DEV:
xfree(c->dev);
@@ -189,6 +191,7 @@ static uint32_t nftnl_chain_validate[NFTNL_CHAIN_MAX + 1] = {
[NFTNL_CHAIN_PACKETS] = sizeof(uint64_t),
[NFTNL_CHAIN_HANDLE] = sizeof(uint64_t),
[NFTNL_CHAIN_FAMILY] = sizeof(uint32_t),
+ [NFTNL_CHAIN_FLAGS] = sizeof(uint32_t),
};
EXPORT_SYMBOL(nftnl_chain_set_data);
@@ -278,6 +281,9 @@ int nftnl_chain_set_data(struct nftnl_chain *c, uint16_t attr,
c->dev_array_len = len;
break;
+ case NFTNL_CHAIN_FLAGS:
+ memcpy(&c->chain_flags, data, sizeof(c->chain_flags));
+ break;
}
c->flags |= (1 << attr);
return 0;
@@ -319,6 +325,13 @@ int nftnl_chain_set_str(struct nftnl_chain *c, uint16_t attr, const char *str)
return nftnl_chain_set_data(c, attr, str, strlen(str) + 1);
}
+EXPORT_SYMBOL(nftnl_chain_set_array);
+int nftnl_chain_set_array(struct nftnl_chain *c, uint16_t attr,
+ const char **data)
+{
+ return nftnl_chain_set_data(c, attr, data, 0);
+}
+
EXPORT_SYMBOL(nftnl_chain_get_data);
const void *nftnl_chain_get_data(const struct nftnl_chain *c, uint16_t attr,
uint32_t *data_len)
@@ -364,7 +377,11 @@ const void *nftnl_chain_get_data(const struct nftnl_chain *c, uint16_t attr,
*data_len = strlen(c->dev) + 1;
return c->dev;
case NFTNL_CHAIN_DEVICES:
+ *data_len = 0;
return &c->dev_array[0];
+ case NFTNL_CHAIN_FLAGS:
+ *data_len = sizeof(uint32_t);
+ return &c->chain_flags;
}
return NULL;
}
@@ -426,6 +443,17 @@ uint8_t nftnl_chain_get_u8(const struct nftnl_chain *c, uint16_t attr)
return val ? *val : 0;
}
+EXPORT_SYMBOL(nftnl_chain_get_array);
+const char *const *nftnl_chain_get_array(const struct nftnl_chain *c, uint16_t attr)
+{
+ uint32_t data_len;
+ const char * const *val = nftnl_chain_get_data(c, attr, &data_len);
+
+ nftnl_assert(val, attr, attr == NFTNL_CHAIN_DEVICES);
+
+ return val;
+}
+
EXPORT_SYMBOL(nftnl_chain_nlmsg_build_payload);
void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_chain *c)
{
@@ -472,6 +500,8 @@ void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_ch
mnl_attr_put_u64(nlh, NFTA_CHAIN_HANDLE, be64toh(c->handle));
if (c->flags & (1 << NFTNL_CHAIN_TYPE))
mnl_attr_put_strz(nlh, NFTA_CHAIN_TYPE, c->type);
+ if (c->flags & (1 << NFTNL_CHAIN_FLAGS))
+ mnl_attr_put_u32(nlh, NFTA_CHAIN_FLAGS, htonl(c->chain_flags));
}
EXPORT_SYMBOL(nftnl_chain_rule_add);
@@ -526,6 +556,7 @@ static int nftnl_chain_parse_attr_cb(const struct nlattr *attr, void *data)
break;
case NFTA_CHAIN_POLICY:
case NFTA_CHAIN_USE:
+ case NFTA_CHAIN_FLAGS:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
abi_breakage();
break;
@@ -726,6 +757,10 @@ int nftnl_chain_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_chain *c)
return -1;
c->flags |= (1 << NFTNL_CHAIN_TYPE);
}
+ if (tb[NFTA_CHAIN_FLAGS]) {
+ c->chain_flags = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_FLAGS]));
+ c->flags |= (1 << NFTNL_CHAIN_FLAGS);
+ }
c->family = nfg->nfgen_family;
c->flags |= (1 << NFTNL_CHAIN_FAMILY);
@@ -787,6 +822,11 @@ static int nftnl_chain_snprintf_default(char *buf, size_t size,
ret = snprintf(buf + offset, remain, " } ");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
+ if (c->flags & (1 << NFTNL_CHAIN_FLAGS)) {
+ ret = snprintf(buf + offset, remain, " flags %x",
+ c->chain_flags);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+ }
}
return offset;
diff --git a/src/expr/bitwise.c b/src/expr/bitwise.c
index 9ea2f66..1ad4f08 100644
--- a/src/expr/bitwise.c
+++ b/src/expr/bitwise.c
@@ -29,6 +29,8 @@ struct nftnl_expr_bitwise {
union nftnl_data_reg mask;
union nftnl_data_reg xor;
union nftnl_data_reg data;
+ enum nft_registers mreg;
+ enum nft_registers xreg;
};
static int
@@ -51,10 +53,14 @@ nftnl_expr_bitwise_set(struct nftnl_expr *e, uint16_t type,
memcpy(&bitwise->len, data, sizeof(bitwise->len));
break;
case NFTNL_EXPR_BITWISE_MASK:
+ if (e->flags & (1 << NFTNL_EXPR_BITWISE_MREG))
+ return -1;
memcpy(&bitwise->mask.val, data, data_len);
bitwise->mask.len = data_len;
break;
case NFTNL_EXPR_BITWISE_XOR:
+ if (e->flags & (1 << NFTNL_EXPR_BITWISE_XREG))
+ return -1;
memcpy(&bitwise->xor.val, data, data_len);
bitwise->xor.len = data_len;
break;
@@ -62,6 +68,16 @@ nftnl_expr_bitwise_set(struct nftnl_expr *e, uint16_t type,
memcpy(&bitwise->data.val, data, data_len);
bitwise->data.len = data_len;
break;
+ case NFTNL_EXPR_BITWISE_MREG:
+ if (e->flags & (1 << NFTNL_EXPR_BITWISE_MASK))
+ return -1;
+ memcpy(&bitwise->mreg, data, sizeof(bitwise->mreg));
+ break;
+ case NFTNL_EXPR_BITWISE_XREG:
+ if (e->flags & (1 << NFTNL_EXPR_BITWISE_XOR))
+ return -1;
+ memcpy(&bitwise->xreg, data, sizeof(bitwise->xreg));
+ break;
default:
return -1;
}
@@ -96,6 +112,12 @@ nftnl_expr_bitwise_get(const struct nftnl_expr *e, uint16_t type,
case NFTNL_EXPR_BITWISE_DATA:
*data_len = bitwise->data.len;
return &bitwise->data.val;
+ case NFTNL_EXPR_BITWISE_MREG:
+ *data_len = sizeof(bitwise->mreg);
+ return &bitwise->mreg;
+ case NFTNL_EXPR_BITWISE_XREG:
+ *data_len = sizeof(bitwise->xreg);
+ return &bitwise->xreg;
}
return NULL;
}
@@ -113,6 +135,8 @@ static int nftnl_expr_bitwise_cb(const struct nlattr *attr, void *data)
case NFTA_BITWISE_DREG:
case NFTA_BITWISE_OP:
case NFTA_BITWISE_LEN:
+ case NFTA_BITWISE_MREG:
+ case NFTA_BITWISE_XREG:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
abi_breakage();
break;
@@ -165,6 +189,10 @@ nftnl_expr_bitwise_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
bitwise->data.val);
mnl_attr_nest_end(nlh, nest);
}
+ if (e->flags & (1 << NFTNL_EXPR_BITWISE_MREG))
+ mnl_attr_put_u32(nlh, NFTA_BITWISE_MREG, htonl(bitwise->mreg));
+ if (e->flags & (1 << NFTNL_EXPR_BITWISE_XREG))
+ mnl_attr_put_u32(nlh, NFTA_BITWISE_XREG, htonl(bitwise->xreg));
}
static int
@@ -205,13 +233,22 @@ nftnl_expr_bitwise_parse(struct nftnl_expr *e, struct nlattr *attr)
ret = nftnl_parse_data(&bitwise->data, tb[NFTA_BITWISE_DATA], NULL);
e->flags |= (1 << NFTNL_EXPR_BITWISE_DATA);
}
+ if (tb[NFTA_BITWISE_MREG]) {
+ bitwise->mreg = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_MREG]));
+ e->flags |= (1 << NFTNL_EXPR_BITWISE_MREG);
+ }
+ if (tb[NFTA_BITWISE_XREG]) {
+ bitwise->xreg = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_XREG]));
+ e->flags |= (1 << NFTNL_EXPR_BITWISE_XREG);
+ }
return ret;
}
static int
nftnl_expr_bitwise_snprintf_bool(char *buf, size_t size,
- const struct nftnl_expr_bitwise *bitwise)
+ const struct nftnl_expr_bitwise *bitwise,
+ uint32_t flags)
{
int remain = size, offset = 0, ret;
@@ -219,15 +256,25 @@ nftnl_expr_bitwise_snprintf_bool(char *buf, size_t size,
bitwise->dreg, bitwise->sreg);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- ret = nftnl_data_reg_snprintf(buf + offset, remain, &bitwise->mask,
- NFTNL_OUTPUT_DEFAULT, 0, DATA_VALUE);
+ if (flags & (1 << NFTA_BITWISE_MASK))
+ ret = nftnl_data_reg_snprintf(buf + offset, remain,
+ &bitwise->mask,
+ NFTNL_OUTPUT_DEFAULT, 0,
+ DATA_VALUE);
+ else
+ ret = snprintf(buf + offset, remain, "reg %u ", bitwise->mreg);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
ret = snprintf(buf + offset, remain, ") ^ ");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- ret = nftnl_data_reg_snprintf(buf + offset, remain, &bitwise->xor,
- NFTNL_OUTPUT_DEFAULT, 0, DATA_VALUE);
+ if (flags & (1 << NFTA_BITWISE_XOR))
+ ret = nftnl_data_reg_snprintf(buf + offset, remain,
+ &bitwise->xor,
+ NFTNL_OUTPUT_DEFAULT, 0,
+ DATA_VALUE);
+ else
+ ret = snprintf(buf + offset, remain, "reg %u ", bitwise->xreg);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
return offset;
@@ -260,7 +307,8 @@ static int nftnl_expr_bitwise_snprintf_default(char *buf, size_t size,
switch (bitwise->op) {
case NFT_BITWISE_BOOL:
- err = nftnl_expr_bitwise_snprintf_bool(buf, size, bitwise);
+ err = nftnl_expr_bitwise_snprintf_bool(buf, size, bitwise,
+ e->flags);
break;
case NFT_BITWISE_LSHIFT:
err = nftnl_expr_bitwise_snprintf_shift(buf, size, "<<", bitwise);
diff --git a/src/expr/masq.c b/src/expr/masq.c
index f6f3ceb..622ba28 100644
--- a/src/expr/masq.c
+++ b/src/expr/masq.c
@@ -135,16 +135,20 @@ static int nftnl_expr_masq_snprintf_default(char *buf, size_t len,
const struct nftnl_expr *e)
{
struct nftnl_expr_masq *masq = nftnl_expr_data(e);
+ int remain = len, offset = 0, ret = 0;
- if (e->flags & (1 << NFTNL_EXPR_MASQ_FLAGS))
- return snprintf(buf, len, "flags 0x%x ", masq->flags);
if (e->flags & (1 << NFTNL_EXPR_MASQ_REG_PROTO_MIN)) {
- return snprintf(buf, len,
- "proto_min reg %u proto_max reg %u ",
- masq->sreg_proto_min, masq->sreg_proto_max);
+ ret = snprintf(buf, remain,
+ "proto_min reg %u proto_max reg %u ",
+ masq->sreg_proto_min, masq->sreg_proto_max);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+ }
+ if (e->flags & (1 << NFTNL_EXPR_MASQ_FLAGS)) {
+ ret = snprintf(buf + offset, remain, "flags 0x%x ", masq->flags);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
- return 0;
+ return offset;
}
static int nftnl_expr_masq_snprintf(char *buf, size_t len, uint32_t type,
diff --git a/src/expr/nat.c b/src/expr/nat.c
index 6b7d50e..4085216 100644
--- a/src/expr/nat.c
+++ b/src/expr/nat.c
@@ -249,7 +249,7 @@ nftnl_expr_nat_snprintf_default(char *buf, size_t size,
}
if (e->flags & (1 << NFTNL_EXPR_NAT_FLAGS)) {
- ret = snprintf(buf + offset, remain, "flags %u", nat->flags);
+ ret = snprintf(buf + offset, remain, "flags 0x%x ", nat->flags);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
diff --git a/src/flowtable.c b/src/flowtable.c
index 1e235d0..19e2882 100644
--- a/src/flowtable.c
+++ b/src/flowtable.c
@@ -206,6 +206,13 @@ void nftnl_flowtable_set_u64(struct nftnl_flowtable *c, uint16_t attr, uint64_t
nftnl_flowtable_set_data(c, attr, &data, sizeof(uint64_t));
}
+EXPORT_SYMBOL(nftnl_flowtable_set_array);
+int nftnl_flowtable_set_array(struct nftnl_flowtable *c, uint16_t attr,
+ const char **data)
+{
+ return nftnl_flowtable_set_data(c, attr, data, 0);
+}
+
EXPORT_SYMBOL(nftnl_flowtable_get_data);
const void *nftnl_flowtable_get_data(const struct nftnl_flowtable *c,
uint16_t attr, uint32_t *data_len)
@@ -230,6 +237,7 @@ const void *nftnl_flowtable_get_data(const struct nftnl_flowtable *c,
*data_len = sizeof(int32_t);
return &c->family;
case NFTNL_FLOWTABLE_DEVICES:
+ *data_len = 0;
return &c->dev_array[0];
case NFTNL_FLOWTABLE_SIZE:
*data_len = sizeof(int32_t);
@@ -290,6 +298,17 @@ int32_t nftnl_flowtable_get_s32(const struct nftnl_flowtable *c, uint16_t attr)
return val ? *val : 0;
}
+EXPORT_SYMBOL(nftnl_flowtable_get_array);
+const char *const *nftnl_flowtable_get_array(const struct nftnl_flowtable *c, uint16_t attr)
+{
+ uint32_t data_len;
+ const char * const *val = nftnl_flowtable_get_data(c, attr, &data_len);
+
+ nftnl_assert(val, attr, attr == NFTNL_FLOWTABLE_DEVICES);
+
+ return val;
+}
+
EXPORT_SYMBOL(nftnl_flowtable_nlmsg_build_payload);
void nftnl_flowtable_nlmsg_build_payload(struct nlmsghdr *nlh,
const struct nftnl_flowtable *c)
diff --git a/src/libnftnl.map b/src/libnftnl.map
index 5ba8d99..f62640f 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -363,4 +363,8 @@ LIBNFTNL_13 {
LIBNFTNL_14 {
nftnl_udata_nest_start;
nftnl_udata_nest_end;
+ nftnl_chain_set_array;
+ nftnl_chain_get_array;
+ nftnl_flowtable_set_array;
+ nftnl_flowtable_get_array;
} LIBNFTNL_13;
diff --git a/src/set.c b/src/set.c
index 651dcfa..15fa29d 100644
--- a/src/set.c
+++ b/src/set.c
@@ -51,6 +51,8 @@ void nftnl_set_free(const struct nftnl_set *s)
xfree(s->name);
if (s->flags & (1 << NFTNL_SET_USERDATA))
xfree(s->user.data);
+ if (s->flags & (1 << NFTNL_SET_EXPR))
+ nftnl_expr_free(s->expr);
list_for_each_entry_safe(elem, tmp, &s->element_list, head) {
list_del(&elem->head);
@@ -96,6 +98,9 @@ void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
case NFTNL_SET_USERDATA:
xfree(s->user.data);
break;
+ case NFTNL_SET_EXPR:
+ nftnl_expr_free(s->expr);
+ break;
default:
return;
}
@@ -195,6 +200,12 @@ 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_EXPR:
+ if (s->flags & (1 << NFTNL_SET_EXPR))
+ nftnl_expr_free(s->expr);
+
+ s->expr = (void *)data;
+ break;
}
s->flags |= (1 << attr);
return 0;
@@ -283,6 +294,8 @@ const void *nftnl_set_get_data(const struct nftnl_set *s, uint16_t attr,
case NFTNL_SET_USERDATA:
*data_len = s->user.len;
return s->user.data;
+ case NFTNL_SET_EXPR:
+ return s->expr;
}
return NULL;
}
@@ -432,6 +445,13 @@ 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_EXPR)) {
+ struct nlattr *nest1;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_EXPR);
+ nftnl_expr_build_payload(nlh, s->expr);
+ mnl_attr_nest_end(nlh, nest1);
+ }
}
@@ -635,6 +655,13 @@ int nftnl_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s)
if (ret < 0)
return ret;
}
+ if (tb[NFTA_SET_EXPR]) {
+ s->expr = nftnl_expr_parse(tb[NFTA_SET_EXPR]);
+ if (!s->expr)
+ return -1;
+
+ s->flags |= (1 << NFTNL_SET_EXPR);
+ }
s->family = nfg->nfgen_family;
s->flags |= (1 << NFTNL_SET_FAMILY);
diff --git a/src/set_elem.c b/src/set_elem.c
index d3ce807..4421322 100644
--- a/src/set_elem.c
+++ b/src/set_elem.c
@@ -75,6 +75,7 @@ void nftnl_set_elem_unset(struct nftnl_set_elem *s, uint16_t attr)
break;
case NFTNL_SET_ELEM_FLAGS:
case NFTNL_SET_ELEM_KEY: /* NFTA_SET_ELEM_KEY */
+ case NFTNL_SET_ELEM_KEY_END: /* NFTA_SET_ELEM_KEY_END */
case NFTNL_SET_ELEM_VERDICT: /* NFTA_SET_ELEM_DATA */
case NFTNL_SET_ELEM_DATA: /* NFTA_SET_ELEM_DATA */
case NFTNL_SET_ELEM_TIMEOUT: /* NFTA_SET_ELEM_TIMEOUT */
@@ -118,6 +119,10 @@ int nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr,
memcpy(&s->key.val, data, data_len);
s->key.len = data_len;
break;
+ case NFTNL_SET_ELEM_KEY_END: /* NFTA_SET_ELEM_KEY_END */
+ memcpy(&s->key_end.val, data, data_len);
+ s->key_end.len = data_len;
+ break;
case NFTNL_SET_ELEM_VERDICT: /* NFTA_SET_ELEM_DATA */
memcpy(&s->data.verdict, data, sizeof(s->data.verdict));
break;
@@ -157,6 +162,12 @@ int nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr,
if (!s->objref)
return -1;
break;
+ case NFTNL_SET_ELEM_EXPR:
+ if (s->flags & (1 << NFTNL_SET_ELEM_EXPR))
+ nftnl_expr_free(s->expr);
+
+ s->expr = (void *)data;
+ break;
}
s->flags |= (1 << attr);
return 0;
@@ -193,6 +204,9 @@ const void *nftnl_set_elem_get(struct nftnl_set_elem *s, uint16_t attr, uint32_t
case NFTNL_SET_ELEM_KEY: /* NFTA_SET_ELEM_KEY */
*data_len = s->key.len;
return &s->key.val;
+ case NFTNL_SET_ELEM_KEY_END: /* NFTA_SET_ELEM_KEY_END */
+ *data_len = s->key_end.len;
+ return &s->key_end.val;
case NFTNL_SET_ELEM_VERDICT: /* NFTA_SET_ELEM_DATA */
*data_len = sizeof(s->data.verdict);
return &s->data.verdict;
@@ -287,6 +301,14 @@ void nftnl_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh,
mnl_attr_put(nlh, NFTA_DATA_VALUE, e->key.len, e->key.val);
mnl_attr_nest_end(nlh, nest1);
}
+ if (e->flags & (1 << NFTNL_SET_ELEM_KEY_END)) {
+ struct nlattr *nest1;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_KEY_END);
+ mnl_attr_put(nlh, NFTA_DATA_VALUE, e->key_end.len,
+ e->key_end.val);
+ mnl_attr_nest_end(nlh, nest1);
+ }
if (e->flags & (1 << NFTNL_SET_ELEM_VERDICT)) {
struct nlattr *nest1, *nest2;
@@ -310,6 +332,13 @@ void nftnl_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh,
mnl_attr_put(nlh, NFTA_SET_ELEM_USERDATA, e->user.len, e->user.data);
if (e->flags & (1 << NFTNL_SET_ELEM_OBJREF))
mnl_attr_put_strz(nlh, NFTA_SET_ELEM_OBJREF, e->objref);
+ if (e->flags & (1 << NFTNL_SET_ELEM_EXPR)) {
+ struct nlattr *nest1;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_EXPR);
+ nftnl_expr_build_payload(nlh, e->expr);
+ mnl_attr_nest_end(nlh, nest1);
+ }
}
static void nftnl_set_elem_nlmsg_build_def(struct nlmsghdr *nlh,
@@ -373,6 +402,7 @@ static int nftnl_set_elem_parse_attr_cb(const struct nlattr *attr, void *data)
abi_breakage();
break;
case NFTA_SET_ELEM_KEY:
+ case NFTA_SET_ELEM_KEY_END:
case NFTA_SET_ELEM_DATA:
case NFTA_SET_ELEM_EXPR:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
@@ -421,6 +451,13 @@ static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest
goto out_set_elem;
e->flags |= (1 << NFTNL_SET_ELEM_KEY);
}
+ if (tb[NFTA_SET_ELEM_KEY_END]) {
+ ret = nftnl_parse_data(&e->key_end, tb[NFTA_SET_ELEM_KEY_END],
+ &type);
+ if (ret < 0)
+ goto out_set_elem;
+ e->flags |= (1 << NFTNL_SET_ELEM_KEY_END);
+ }
if (tb[NFTA_SET_ELEM_DATA]) {
ret = nftnl_parse_data(&e->data, tb[NFTA_SET_ELEM_DATA], &type);
if (ret < 0)