summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2021-03-17 07:56:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2021-03-17 07:56:20 +0000
commit98a6e8cb7ff3300b4eadea85017c2d5d622b44be (patch)
tree7c6d84bda380de4c65ea3d741c8e8ba703752736
parentReleasing progress-linux version 1.1.8-2~progress5+u1. (diff)
downloadlibnftnl-98a6e8cb7ff3300b4eadea85017c2d5d622b44be.tar.xz
libnftnl-98a6e8cb7ff3300b4eadea85017c2d5d622b44be.zip
Merging upstream version 1.1.9.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--Make_global.am2
-rw-r--r--Makefile.in2
-rwxr-xr-xconfigure20
-rw-r--r--configure.ac2
-rw-r--r--examples/Makefile.in2
-rw-r--r--include/data_reg.h4
-rw-r--r--include/expr_ops.h1
-rw-r--r--include/libnftnl/expr.h8
-rw-r--r--include/libnftnl/set.h14
-rw-r--r--include/linux/netfilter/nf_tables.h3
-rw-r--r--include/set.h2
-rw-r--r--include/set_elem.h2
-rw-r--r--src/Makefile.in2
-rw-r--r--src/expr.c3
-rw-r--r--src/expr/bitwise.c2
-rw-r--r--src/expr/data_reg.c6
-rw-r--r--src/expr/dynset.c126
-rw-r--r--src/libnftnl.map9
-rw-r--r--src/set.c111
-rw-r--r--src/set_elem.c133
-rw-r--r--tests/Makefile.in2
21 files changed, 383 insertions, 73 deletions
diff --git a/Make_global.am b/Make_global.am
index b2f2f66..70ca28b 100644
--- a/Make_global.am
+++ b/Make_global.am
@@ -18,7 +18,7 @@
# set age to 0.
# </snippet>
#
-LIBVERSION=15:0:4
+LIBVERSION=16:0:5
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_srcdir}/include ${LIBMNL_CFLAGS} ${LIBMXML_CFLAGS}
AM_CFLAGS = ${regular_CFLAGS} ${GCC_FVISIBILITY_HIDDEN}
diff --git a/Makefile.in b/Makefile.in
index 4da356c..40d5eea 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -387,7 +387,7 @@ top_srcdir = @top_srcdir@
# set age to 0.
# </snippet>
#
-LIBVERSION = 15:0:4
+LIBVERSION = 16:0:5
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_srcdir}/include ${LIBMNL_CFLAGS} ${LIBMXML_CFLAGS}
AM_CFLAGS = ${regular_CFLAGS} ${GCC_FVISIBILITY_HIDDEN}
ACLOCAL_AMFLAGS = -I m4
diff --git a/configure b/configure
index bc56aa9..b6353f9 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libnftnl 1.1.8.
+# Generated by GNU Autoconf 2.69 for libnftnl 1.1.9.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='libnftnl'
PACKAGE_TARNAME='libnftnl'
-PACKAGE_VERSION='1.1.8'
-PACKAGE_STRING='libnftnl 1.1.8'
+PACKAGE_VERSION='1.1.9'
+PACKAGE_STRING='libnftnl 1.1.9'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1333,7 +1333,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures libnftnl 1.1.8 to adapt to many kinds of systems.
+\`configure' configures libnftnl 1.1.9 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1404,7 +1404,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of libnftnl 1.1.8:";;
+ short | recursive ) echo "Configuration of libnftnl 1.1.9:";;
esac
cat <<\_ACEOF
@@ -1522,7 +1522,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-libnftnl configure 1.1.8
+libnftnl configure 1.1.9
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1800,7 +1800,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by libnftnl $as_me 1.1.8, which was
+It was created by libnftnl $as_me 1.1.9, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3821,7 +3821,7 @@ fi
# Define the identity of the package.
PACKAGE='libnftnl'
- VERSION='1.1.8'
+ VERSION='1.1.9'
cat >>confdefs.h <<_ACEOF
@@ -13577,7 +13577,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by libnftnl $as_me 1.1.8, which was
+This file was extended by libnftnl $as_me 1.1.9, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -13643,7 +13643,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-libnftnl config.status 1.1.8
+libnftnl config.status 1.1.9
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 3d6ce92..d62a88f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
dnl Process this file with autoconf to create configure.
-AC_INIT([libnftnl], [1.1.8])
+AC_INIT([libnftnl], [1.1.9])
AC_CONFIG_AUX_DIR([build-aux])
AC_CANONICAL_HOST
AC_CONFIG_MACRO_DIR([m4])
diff --git a/examples/Makefile.in b/examples/Makefile.in
index cc11de2..570dbd1 100644
--- a/examples/Makefile.in
+++ b/examples/Makefile.in
@@ -538,7 +538,7 @@ top_srcdir = @top_srcdir@
# set age to 0.
# </snippet>
#
-LIBVERSION = 15:0:4
+LIBVERSION = 16:0:5
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_srcdir}/include ${LIBMNL_CFLAGS} ${LIBMXML_CFLAGS}
AM_CFLAGS = ${regular_CFLAGS} ${GCC_FVISIBILITY_HIDDEN}
nft_table_add_SOURCES = nft-table-add.c
diff --git a/include/data_reg.h b/include/data_reg.h
index d9578aa..0d6b778 100644
--- a/include/data_reg.h
+++ b/include/data_reg.h
@@ -13,6 +13,10 @@ enum {
DATA_CHAIN,
};
+enum {
+ DATA_F_NOPFX = 1 << 0,
+};
+
union nftnl_data_reg {
struct {
uint32_t val[NFT_DATA_VALUE_MAXLEN / sizeof(uint32_t)];
diff --git a/include/expr_ops.h b/include/expr_ops.h
index a7f1b9a..5237ac7 100644
--- a/include/expr_ops.h
+++ b/include/expr_ops.h
@@ -12,6 +12,7 @@ struct expr_ops {
const char *name;
uint32_t alloc_len;
int max_attr;
+ void (*init)(const struct nftnl_expr *e);
void (*free)(const struct nftnl_expr *e);
int (*set)(struct nftnl_expr *e, uint16_t type, const void *data, uint32_t data_len);
const void *(*get)(const struct nftnl_expr *e, uint16_t type, uint32_t *data_len);
diff --git a/include/libnftnl/expr.h b/include/libnftnl/expr.h
index c2b2d86..8e90a6a 100644
--- a/include/libnftnl/expr.h
+++ b/include/libnftnl/expr.h
@@ -38,6 +38,12 @@ const char *nftnl_expr_get_str(const struct nftnl_expr *expr, uint16_t type);
void nftnl_expr_build_payload(struct nlmsghdr *nlh, struct nftnl_expr *expr);
+/* For dynset expressions. */
+void nftnl_expr_add_expr(struct nftnl_expr *expr, uint32_t type, struct nftnl_expr *e);
+int nftnl_expr_expr_foreach(const struct nftnl_expr *e,
+ int (*cb)(struct nftnl_expr *e, void *data),
+ void *data);
+
int nftnl_expr_snprintf(char *buf, size_t buflen, const struct nftnl_expr *expr, uint32_t type, uint32_t flags);
int nftnl_expr_fprintf(FILE *fp, const struct nftnl_expr *expr, uint32_t type, uint32_t flags);
@@ -167,6 +173,8 @@ enum {
NFTNL_EXPR_DYNSET_SET_NAME,
NFTNL_EXPR_DYNSET_SET_ID,
NFTNL_EXPR_DYNSET_EXPR,
+ NFTNL_EXPR_DYNSET_EXPRESSIONS,
+ NFTNL_EXPR_DYNSET_FLAGS,
};
enum {
diff --git a/include/libnftnl/set.h b/include/libnftnl/set.h
index 961ce5d..1eae024 100644
--- a/include/libnftnl/set.h
+++ b/include/libnftnl/set.h
@@ -31,6 +31,7 @@ enum nftnl_set_attr {
NFTNL_SET_HANDLE,
NFTNL_SET_DESC_CONCAT,
NFTNL_SET_EXPR,
+ NFTNL_SET_EXPRESSIONS,
__NFTNL_SET_MAX
};
#define NFTNL_SET_MAX (__NFTNL_SET_MAX - 1)
@@ -80,6 +81,12 @@ int nftnl_set_list_foreach(struct nftnl_set_list *set_list, int (*cb)(struct nft
struct nftnl_set *nftnl_set_list_lookup_byname(struct nftnl_set_list *set_list,
const char *set);
+struct nftnl_expr;
+void nftnl_set_add_expr(struct nftnl_set *s, struct nftnl_expr *expr);
+int nftnl_set_expr_foreach(const struct nftnl_set *s,
+ int (*cb)(struct nftnl_expr *e, void *data),
+ void *data);
+
struct nftnl_set_list_iter;
struct nftnl_set_list_iter *nftnl_set_list_iter_create(const struct nftnl_set_list *l);
struct nftnl_set *nftnl_set_list_iter_cur(const struct nftnl_set_list_iter *iter);
@@ -107,6 +114,7 @@ enum {
NFTNL_SET_ELEM_EXPR,
NFTNL_SET_ELEM_OBJREF,
NFTNL_SET_ELEM_KEY_END,
+ NFTNL_SET_ELEM_EXPRESSIONS,
__NFTNL_SET_ELEM_MAX
};
#define NFTNL_SET_ELEM_MAX (__NFTNL_SET_ELEM_MAX - 1)
@@ -144,6 +152,12 @@ int nftnl_set_elem_parse_file(struct nftnl_set_elem *e, enum nftnl_parse_type ty
int nftnl_set_elem_snprintf(char *buf, size_t size, const struct nftnl_set_elem *s, uint32_t type, uint32_t flags);
int nftnl_set_elem_fprintf(FILE *fp, const struct nftnl_set_elem *se, uint32_t type, uint32_t flags);
+struct nftnl_expr;
+void nftnl_set_elem_add_expr(struct nftnl_set_elem *e, struct nftnl_expr *expr);
+int nftnl_set_elem_expr_foreach(struct nftnl_set_elem *e,
+ int (*cb)(struct nftnl_expr *e, void *data),
+ void *data);
+
int nftnl_set_elem_foreach(struct nftnl_set *s, int (*cb)(struct nftnl_set_elem *e, void *data), void *data);
struct nftnl_set_elems_iter;
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index e4cdf78..5cf3faf 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -367,6 +367,7 @@ enum nft_set_attributes {
NFTA_SET_OBJ_TYPE,
NFTA_SET_HANDLE,
NFTA_SET_EXPR,
+ NFTA_SET_EXPRESSIONS,
__NFTA_SET_MAX
};
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
@@ -405,6 +406,7 @@ enum nft_set_elem_attributes {
NFTA_SET_ELEM_PAD,
NFTA_SET_ELEM_OBJREF,
NFTA_SET_ELEM_KEY_END,
+ NFTA_SET_ELEM_EXPRESSIONS,
__NFTA_SET_ELEM_MAX
};
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
@@ -712,6 +714,7 @@ enum nft_dynset_attributes {
NFTA_DYNSET_EXPR,
NFTA_DYNSET_PAD,
NFTA_DYNSET_FLAGS,
+ NFTA_DYNSET_EXPRESSIONS,
__NFTA_DYNSET_MAX,
};
#define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1)
diff --git a/include/set.h b/include/set.h
index 66ac129..55018b6 100644
--- a/include/set.h
+++ b/include/set.h
@@ -33,7 +33,7 @@ struct nftnl_set {
uint32_t flags;
uint32_t gc_interval;
uint64_t timeout;
- struct nftnl_expr *expr;
+ struct list_head expr_list;
};
struct nftnl_set_list;
diff --git a/include/set_elem.h b/include/set_elem.h
index 52f185a..9239557 100644
--- a/include/set_elem.h
+++ b/include/set_elem.h
@@ -10,7 +10,7 @@ struct nftnl_set_elem {
union nftnl_data_reg key;
union nftnl_data_reg key_end;
union nftnl_data_reg data;
- struct nftnl_expr *expr;
+ struct list_head expr_list;
uint64_t timeout;
uint64_t expiration;
const char *objref;
diff --git a/src/Makefile.in b/src/Makefile.in
index 3e92aa4..6f199a4 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -396,7 +396,7 @@ top_srcdir = @top_srcdir@
# set age to 0.
# </snippet>
#
-LIBVERSION = 15:0:4
+LIBVERSION = 16:0:5
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_srcdir}/include ${LIBMNL_CFLAGS} ${LIBMXML_CFLAGS}
AM_CFLAGS = ${regular_CFLAGS} ${GCC_FVISIBILITY_HIDDEN}
lib_LTLIBRARIES = libnftnl.la
diff --git a/src/expr.c b/src/expr.c
index ed2f60e..8e0bce2 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -42,6 +42,9 @@ struct nftnl_expr *nftnl_expr_alloc(const char *name)
expr->flags |= (1 << NFTNL_EXPR_NAME);
expr->ops = ops;
+ if (ops->init)
+ ops->init(expr);
+
return expr;
}
diff --git a/src/expr/bitwise.c b/src/expr/bitwise.c
index 9ea2f66..ba379a8 100644
--- a/src/expr/bitwise.c
+++ b/src/expr/bitwise.c
@@ -215,7 +215,7 @@ nftnl_expr_bitwise_snprintf_bool(char *buf, size_t size,
{
int remain = size, offset = 0, ret;
- ret = snprintf(buf, remain, "reg %u = (reg=%u & ",
+ ret = snprintf(buf, remain, "reg %u = ( reg %u & ",
bitwise->dreg, bitwise->sreg);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
diff --git a/src/expr/data_reg.c b/src/expr/data_reg.c
index 4e35a79..d3ccc61 100644
--- a/src/expr/data_reg.c
+++ b/src/expr/data_reg.c
@@ -29,10 +29,14 @@ nftnl_data_reg_value_snprintf_default(char *buf, size_t size,
const union nftnl_data_reg *reg,
uint32_t flags)
{
+ const char *pfx = flags & DATA_F_NOPFX ? "" : "0x";
int remain = size, offset = 0, ret, i;
+
+
for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
- ret = snprintf(buf + offset, remain, "0x%.8x ", reg->val[i]);
+ ret = snprintf(buf + offset, remain,
+ "%s%.8x ", pfx, reg->val[i]);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
diff --git a/src/expr/dynset.c b/src/expr/dynset.c
index 91dbea9..a9b11f2 100644
--- a/src/expr/dynset.c
+++ b/src/expr/dynset.c
@@ -26,9 +26,10 @@ struct nftnl_expr_dynset {
enum nft_registers sreg_data;
enum nft_dynset_ops op;
uint64_t timeout;
- struct nftnl_expr *expr;
+ struct list_head expr_list;
char *set_name;
uint32_t set_id;
+ uint32_t dynset_flags;
};
static int
@@ -36,6 +37,7 @@ nftnl_expr_dynset_set(struct nftnl_expr *e, uint16_t type,
const void *data, uint32_t data_len)
{
struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
+ struct nftnl_expr *expr, *next;
switch (type) {
case NFTNL_EXPR_DYNSET_SREG_KEY:
@@ -59,7 +61,14 @@ nftnl_expr_dynset_set(struct nftnl_expr *e, uint16_t type,
memcpy(&dynset->set_id, data, sizeof(dynset->set_id));
break;
case NFTNL_EXPR_DYNSET_EXPR:
- dynset->expr = (void *)data;
+ list_for_each_entry_safe(expr, next, &dynset->expr_list, head)
+ nftnl_expr_free(expr);
+
+ expr = (void *)data;
+ list_add(&expr->head, &dynset->expr_list);
+ break;
+ case NFTNL_EXPR_DYNSET_FLAGS:
+ memcpy(&dynset->dynset_flags, data, sizeof(dynset->dynset_flags));
break;
default:
return -1;
@@ -72,6 +81,7 @@ nftnl_expr_dynset_get(const struct nftnl_expr *e, uint16_t type,
uint32_t *data_len)
{
struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
+ struct nftnl_expr *expr;
switch (type) {
case NFTNL_EXPR_DYNSET_SREG_KEY:
@@ -93,7 +103,12 @@ nftnl_expr_dynset_get(const struct nftnl_expr *e, uint16_t type,
*data_len = sizeof(dynset->set_id);
return &dynset->set_id;
case NFTNL_EXPR_DYNSET_EXPR:
- return dynset->expr;
+ list_for_each_entry(expr, &dynset->expr_list, head)
+ break;
+ return expr;
+ case NFTNL_EXPR_DYNSET_FLAGS:
+ *data_len = sizeof(dynset->dynset_flags);
+ return &dynset->dynset_flags;
}
return NULL;
}
@@ -111,6 +126,7 @@ static int nftnl_expr_dynset_cb(const struct nlattr *attr, void *data)
case NFTA_DYNSET_SREG_DATA:
case NFTA_DYNSET_SET_ID:
case NFTA_DYNSET_OP:
+ case NFTA_DYNSET_FLAGS:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
abi_breakage();
break;
@@ -137,6 +153,7 @@ nftnl_expr_dynset_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
{
struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
struct nlattr *nest;
+ int num_exprs = 0;
if (e->flags & (1 << NFTNL_EXPR_DYNSET_SREG_KEY))
mnl_attr_put_u32(nlh, NFTA_DYNSET_SREG_KEY, htonl(dynset->sreg_key));
@@ -150,11 +167,58 @@ nftnl_expr_dynset_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
mnl_attr_put_strz(nlh, NFTA_DYNSET_SET_NAME, dynset->set_name);
if (e->flags & (1 << NFTNL_EXPR_DYNSET_SET_ID))
mnl_attr_put_u32(nlh, NFTA_DYNSET_SET_ID, htonl(dynset->set_id));
- if (e->flags & (1 << NFTNL_EXPR_DYNSET_EXPR)) {
- nest = mnl_attr_nest_start(nlh, NFTA_DYNSET_EXPR);
- nftnl_expr_build_payload(nlh, dynset->expr);
- mnl_attr_nest_end(nlh, nest);
+ if (!list_empty(&dynset->expr_list)) {
+ struct nftnl_expr *expr;
+
+ list_for_each_entry(expr, &dynset->expr_list, head)
+ num_exprs++;
+
+ if (num_exprs == 1) {
+ nest = mnl_attr_nest_start(nlh, NFTA_DYNSET_EXPR);
+ list_for_each_entry(expr, &dynset->expr_list, head)
+ nftnl_expr_build_payload(nlh, expr);
+ mnl_attr_nest_end(nlh, nest);
+ } else if (num_exprs > 1) {
+ struct nlattr *nest1, *nest2;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_DYNSET_EXPRESSIONS);
+ list_for_each_entry(expr, &dynset->expr_list, head) {
+ nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
+ nftnl_expr_build_payload(nlh, expr);
+ mnl_attr_nest_end(nlh, nest2);
+ }
+ mnl_attr_nest_end(nlh, nest1);
+ }
+ }
+ if (e->flags & (1 << NFTNL_EXPR_DYNSET_FLAGS))
+ mnl_attr_put_u32(nlh, NFTA_DYNSET_FLAGS,
+ htonl(dynset->dynset_flags));
+}
+
+EXPORT_SYMBOL(nftnl_expr_add_expr);
+void nftnl_expr_add_expr(struct nftnl_expr *e, uint32_t type,
+ struct nftnl_expr *expr)
+{
+ struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
+
+ list_add_tail(&expr->head, &dynset->expr_list);
+}
+
+EXPORT_SYMBOL(nftnl_expr_expr_foreach);
+int nftnl_expr_expr_foreach(const struct nftnl_expr *e,
+ int (*cb)(struct nftnl_expr *e, void *data),
+ void *data)
+{
+ struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
+ struct nftnl_expr *cur, *tmp;
+ int ret;
+
+ list_for_each_entry_safe(cur, tmp, &dynset->expr_list, head) {
+ ret = cb(cur, data);
+ if (ret < 0)
+ return ret;
}
+ return 0;
}
static int
@@ -162,6 +226,7 @@ nftnl_expr_dynset_parse(struct nftnl_expr *e, struct nlattr *attr)
{
struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
struct nlattr *tb[NFTA_SET_MAX+1] = {};
+ struct nftnl_expr *expr, *next;
int ret = 0;
if (mnl_attr_parse_nested(attr, nftnl_expr_dynset_cb, tb) < 0)
@@ -195,13 +260,38 @@ nftnl_expr_dynset_parse(struct nftnl_expr *e, struct nlattr *attr)
e->flags |= (1 << NFTNL_EXPR_DYNSET_SET_ID);
}
if (tb[NFTA_DYNSET_EXPR]) {
- e->flags |= (1 << NFTNL_EXPR_DYNSET_EXPR);
- dynset->expr = nftnl_expr_parse(tb[NFTA_DYNSET_EXPR]);
- if (dynset->expr == NULL)
+ expr = nftnl_expr_parse(tb[NFTA_DYNSET_EXPR]);
+ if (expr == NULL)
return -1;
+
+ list_add(&expr->head, &dynset->expr_list);
+ e->flags |= (1 << NFTNL_EXPR_DYNSET_EXPR);
+ } else if (tb[NFTA_DYNSET_EXPRESSIONS]) {
+ struct nlattr *attr2;
+
+ mnl_attr_for_each_nested(attr2, tb[NFTA_DYNSET_EXPRESSIONS]) {
+ if (mnl_attr_get_type(attr2) != NFTA_LIST_ELEM)
+ goto out_dynset_expr;
+
+ expr = nftnl_expr_parse(attr2);
+ if (!expr)
+ goto out_dynset_expr;
+
+ list_add_tail(&expr->head, &dynset->expr_list);
+ }
+ e->flags |= (1 << NFTNL_EXPR_DYNSET_EXPRESSIONS);
+ }
+ if (tb[NFTA_DYNSET_FLAGS]) {
+ dynset->dynset_flags = ntohl(mnl_attr_get_u32(tb[NFTA_DYNSET_FLAGS]));
+ e->flags |= (1 << NFTNL_EXPR_DYNSET_FLAGS);
}
return ret;
+out_dynset_expr:
+ list_for_each_entry_safe(expr, next, &dynset->expr_list, head)
+ nftnl_expr_free(expr);
+
+ return -1;
}
static const char *op2str_array[] = {
@@ -239,8 +329,7 @@ nftnl_expr_dynset_snprintf_default(char *buf, size_t size,
dynset->timeout);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
- if (e->flags & (1 << NFTNL_EXPR_DYNSET_EXPR)) {
- expr = dynset->expr;
+ list_for_each_entry(expr, &dynset->expr_list, head) {
ret = snprintf(buf + offset, remain, "expr [ %s ",
expr->ops->name);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
@@ -272,19 +361,28 @@ nftnl_expr_dynset_snprintf(char *buf, size_t size, uint32_t type,
return -1;
}
+static void nftnl_expr_dynset_init(const struct nftnl_expr *e)
+{
+ struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
+
+ INIT_LIST_HEAD(&dynset->expr_list);
+}
+
static void nftnl_expr_dynset_free(const struct nftnl_expr *e)
{
struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
+ struct nftnl_expr *expr, *next;
xfree(dynset->set_name);
- if (dynset->expr)
- nftnl_expr_free(dynset->expr);
+ list_for_each_entry_safe(expr, next, &dynset->expr_list, head)
+ nftnl_expr_free(expr);
}
struct expr_ops expr_ops_dynset = {
.name = "dynset",
.alloc_len = sizeof(struct nftnl_expr_dynset),
.max_attr = NFTA_DYNSET_MAX,
+ .init = nftnl_expr_dynset_init,
.free = nftnl_expr_dynset_free,
.set = nftnl_expr_dynset_set,
.get = nftnl_expr_dynset_get,
diff --git a/src/libnftnl.map b/src/libnftnl.map
index 2d35ace..e707b89 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -374,3 +374,12 @@ LIBNFTNL_15 {
nftnl_expr_build_payload;
nftnl_rule_del_expr;
} LIBNFTNL_14;
+
+LIBNFTNL_16 {
+ nftnl_set_add_expr;
+ nftnl_set_expr_foreach;
+ nftnl_set_elem_add_expr;
+ nftnl_set_elem_expr_foreach;
+ nftnl_expr_add_expr;
+ nftnl_expr_expr_foreach;
+} LIBNFTNL_15;
diff --git a/src/set.c b/src/set.c
index 15fa29d..8c5025d 100644
--- a/src/set.c
+++ b/src/set.c
@@ -37,6 +37,7 @@ struct nftnl_set *nftnl_set_alloc(void)
return NULL;
INIT_LIST_HEAD(&s->element_list);
+ INIT_LIST_HEAD(&s->expr_list);
return s;
}
@@ -44,6 +45,7 @@ EXPORT_SYMBOL(nftnl_set_free);
void nftnl_set_free(const struct nftnl_set *s)
{
struct nftnl_set_elem *elem, *tmp;
+ struct nftnl_expr *expr, *next;
if (s->flags & (1 << NFTNL_SET_TABLE))
xfree(s->table);
@@ -51,8 +53,9 @@ 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(expr, next, &s->expr_list, head)
+ nftnl_expr_free(expr);
list_for_each_entry_safe(elem, tmp, &s->element_list, head) {
list_del(&elem->head);
@@ -70,6 +73,8 @@ bool nftnl_set_is_set(const struct nftnl_set *s, uint16_t attr)
EXPORT_SYMBOL(nftnl_set_unset);
void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
{
+ struct nftnl_expr *expr, *tmp;
+
if (!(s->flags & (1 << attr)))
return;
@@ -99,7 +104,9 @@ void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
xfree(s->user.data);
break;
case NFTNL_SET_EXPR:
- nftnl_expr_free(s->expr);
+ case NFTNL_SET_EXPRESSIONS:
+ list_for_each_entry_safe(expr, tmp, &s->expr_list, head)
+ nftnl_expr_free(expr);
break;
default:
return;
@@ -127,6 +134,8 @@ EXPORT_SYMBOL(nftnl_set_set_data);
int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
uint32_t data_len)
{
+ struct nftnl_expr *expr, *tmp;
+
nftnl_assert_attr_exists(attr, NFTNL_SET_MAX);
nftnl_assert_validate(data, nftnl_set_validate, attr, data_len);
@@ -201,10 +210,11 @@ int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
s->user.len = data_len;
break;
case NFTNL_SET_EXPR:
- if (s->flags & (1 << NFTNL_SET_EXPR))
- nftnl_expr_free(s->expr);
+ list_for_each_entry_safe(expr, tmp, &s->expr_list, head)
+ nftnl_expr_free(expr);
- s->expr = (void *)data;
+ expr = (void *)data;
+ list_add(&expr->head, &s->expr_list);
break;
}
s->flags |= (1 << attr);
@@ -239,6 +249,8 @@ EXPORT_SYMBOL(nftnl_set_get_data);
const void *nftnl_set_get_data(const struct nftnl_set *s, uint16_t attr,
uint32_t *data_len)
{
+ struct nftnl_expr *expr;
+
if (!(s->flags & (1 << attr)))
return NULL;
@@ -295,7 +307,9 @@ const void *nftnl_set_get_data(const struct nftnl_set *s, uint16_t attr,
*data_len = s->user.len;
return s->user.data;
case NFTNL_SET_EXPR:
- return s->expr;
+ list_for_each_entry(expr, &s->expr_list, head)
+ break;
+ return expr;
}
return NULL;
}
@@ -414,6 +428,8 @@ nftnl_set_nlmsg_build_desc_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
EXPORT_SYMBOL(nftnl_set_nlmsg_build_payload);
void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
{
+ int num_exprs = 0;
+
if (s->flags & (1 << NFTNL_SET_TABLE))
mnl_attr_put_strz(nlh, NFTA_SET_TABLE, s->table);
if (s->flags & (1 << NFTNL_SET_NAME))
@@ -445,15 +461,55 @@ 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);
+ if (!list_empty(&s->expr_list)) {
+ struct nftnl_expr *expr;
+
+ list_for_each_entry(expr, &s->expr_list, head)
+ num_exprs++;
+
+ if (num_exprs == 1) {
+ struct nlattr *nest1;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_EXPR);
+ list_for_each_entry(expr, &s->expr_list, head)
+ nftnl_expr_build_payload(nlh, expr);
+
+ mnl_attr_nest_end(nlh, nest1);
+ } else if (num_exprs > 1) {
+ struct nlattr *nest1, *nest2;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_EXPRESSIONS);
+ list_for_each_entry(expr, &s->expr_list, head) {
+ nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
+ nftnl_expr_build_payload(nlh, expr);
+ mnl_attr_nest_end(nlh, nest2);
+ }
+ mnl_attr_nest_end(nlh, nest1);
+ }
}
}
+EXPORT_SYMBOL(nftnl_set_add_expr);
+void nftnl_set_add_expr(struct nftnl_set *s, struct nftnl_expr *expr)
+{
+ list_add_tail(&expr->head, &s->expr_list);
+}
+
+EXPORT_SYMBOL(nftnl_set_expr_foreach);
+int nftnl_set_expr_foreach(const struct nftnl_set *s,
+ int (*cb)(struct nftnl_expr *e, void *data),
+ void *data)
+{
+ struct nftnl_expr *cur, *tmp;
+ int ret;
+
+ list_for_each_entry_safe(cur, tmp, &s->expr_list, head) {
+ ret = cb(cur, data);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data)
{
@@ -493,6 +549,8 @@ static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data)
abi_breakage();
break;
case NFTA_SET_DESC:
+ case NFTA_SET_EXPR:
+ case NFTA_SET_EXPRESSIONS:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
abi_breakage();
break;
@@ -578,6 +636,7 @@ int nftnl_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s)
{
struct nlattr *tb[NFTA_SET_MAX+1] = {};
struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+ struct nftnl_expr *expr, *next;
int ret;
if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_set_parse_attr_cb, tb) < 0)
@@ -656,17 +715,37 @@ int nftnl_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s)
return ret;
}
if (tb[NFTA_SET_EXPR]) {
- s->expr = nftnl_expr_parse(tb[NFTA_SET_EXPR]);
- if (!s->expr)
- return -1;
+ expr = nftnl_expr_parse(tb[NFTA_SET_EXPR]);
+ if (!expr)
+ goto out_set_expr;
+ list_add(&expr->head, &s->expr_list);
s->flags |= (1 << NFTNL_SET_EXPR);
+ } else if (tb[NFTA_SET_EXPRESSIONS]) {
+ struct nlattr *attr;
+
+ mnl_attr_for_each_nested(attr, tb[NFTA_SET_EXPRESSIONS]) {
+ if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM)
+ goto out_set_expr;
+
+ expr = nftnl_expr_parse(attr);
+ if (expr == NULL)
+ goto out_set_expr;
+
+ list_add_tail(&expr->head, &s->expr_list);
+ }
+ s->flags |= (1 << NFTNL_SET_EXPRESSIONS);
}
s->family = nfg->nfgen_family;
s->flags |= (1 << NFTNL_SET_FAMILY);
return 0;
+out_set_expr:
+ list_for_each_entry_safe(expr, next, &s->expr_list, head)
+ nftnl_expr_free(expr);
+
+ return -1;
}
static int nftnl_set_do_parse(struct nftnl_set *s, enum nftnl_parse_type type,
diff --git a/src/set_elem.c b/src/set_elem.c
index e82684b..8f634e7 100644
--- a/src/set_elem.c
+++ b/src/set_elem.c
@@ -36,17 +36,21 @@ struct nftnl_set_elem *nftnl_set_elem_alloc(void)
if (s == NULL)
return NULL;
+ INIT_LIST_HEAD(&s->expr_list);
+
return s;
}
EXPORT_SYMBOL(nftnl_set_elem_free);
void nftnl_set_elem_free(struct nftnl_set_elem *s)
{
+ struct nftnl_expr *e, *tmp;
+
if (s->flags & (1 << NFTNL_SET_ELEM_CHAIN))
xfree(s->data.chain);
- if (s->flags & (1 << NFTNL_SET_ELEM_EXPR))
- nftnl_expr_free(s->expr);
+ list_for_each_entry_safe(e, tmp, &s->expr_list, head)
+ nftnl_expr_free(e);
if (s->flags & (1 << NFTNL_SET_ELEM_USERDATA))
xfree(s->user.data);
@@ -66,6 +70,8 @@ bool nftnl_set_elem_is_set(const struct nftnl_set_elem *s, uint16_t attr)
EXPORT_SYMBOL(nftnl_set_elem_unset);
void nftnl_set_elem_unset(struct nftnl_set_elem *s, uint16_t attr)
{
+ struct nftnl_expr *expr, *tmp;
+
if (!(s->flags & (1 << attr)))
return;
@@ -85,7 +91,9 @@ void nftnl_set_elem_unset(struct nftnl_set_elem *s, uint16_t attr)
xfree(s->user.data);
break;
case NFTNL_SET_ELEM_EXPR:
- nftnl_expr_free(s->expr);
+ case NFTNL_SET_ELEM_EXPRESSIONS:
+ list_for_each_entry_safe(expr, tmp, &s->expr_list, head)
+ nftnl_expr_free(expr);
break;
case NFTNL_SET_ELEM_OBJREF:
xfree(s->objref);
@@ -108,6 +116,8 @@ EXPORT_SYMBOL(nftnl_set_elem_set);
int nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr,
const void *data, uint32_t data_len)
{
+ struct nftnl_expr *expr, *tmp;
+
nftnl_assert_attr_exists(attr, NFTNL_SET_ELEM_MAX);
nftnl_assert_validate(data, nftnl_set_elem_validate, attr, data_len);
@@ -163,10 +173,11 @@ int nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr,
return -1;
break;
case NFTNL_SET_ELEM_EXPR:
- if (s->flags & (1 << NFTNL_SET_ELEM_EXPR))
- nftnl_expr_free(s->expr);
+ list_for_each_entry_safe(expr, tmp, &s->expr_list, head)
+ nftnl_expr_free(expr);
- s->expr = (void *)data;
+ expr = (void *)data;
+ list_add(&expr->head, &s->expr_list);
break;
}
s->flags |= (1 << attr);
@@ -194,6 +205,8 @@ int nftnl_set_elem_set_str(struct nftnl_set_elem *s, uint16_t attr, const char *
EXPORT_SYMBOL(nftnl_set_elem_get);
const void *nftnl_set_elem_get(struct nftnl_set_elem *s, uint16_t attr, uint32_t *data_len)
{
+ struct nftnl_expr *expr;
+
if (!(s->flags & (1 << attr)))
return NULL;
@@ -226,7 +239,9 @@ const void *nftnl_set_elem_get(struct nftnl_set_elem *s, uint16_t attr, uint32_t
*data_len = s->user.len;
return s->user.data;
case NFTNL_SET_ELEM_EXPR:
- return s->expr;
+ list_for_each_entry(expr, &s->expr_list, head)
+ break;
+ return expr;
case NFTNL_SET_ELEM_OBJREF:
*data_len = strlen(s->objref) + 1;
return s->objref;
@@ -288,6 +303,9 @@ err:
void nftnl_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh,
struct nftnl_set_elem *e)
{
+ struct nftnl_expr *expr;
+ int num_exprs = 0;
+
if (e->flags & (1 << NFTNL_SET_ELEM_FLAGS))
mnl_attr_put_u32(nlh, NFTA_SET_ELEM_FLAGS, htonl(e->set_elem_flags));
if (e->flags & (1 << NFTNL_SET_ELEM_TIMEOUT))
@@ -332,12 +350,30 @@ 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);
+ if (!list_empty(&e->expr_list)) {
+ list_for_each_entry(expr, &e->expr_list, head)
+ num_exprs++;
+
+ if (num_exprs == 1) {
+ struct nlattr *nest1;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_EXPR);
+ list_for_each_entry(expr, &e->expr_list, head)
+ nftnl_expr_build_payload(nlh, expr);
+
+ mnl_attr_nest_end(nlh, nest1);
+ } else if (num_exprs > 1) {
+ struct nlattr *nest1, *nest2;
+
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_EXPRESSIONS);
+ list_for_each_entry(expr, &e->expr_list, head) {
+ nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
+ nftnl_expr_build_payload(nlh, expr);
+ mnl_attr_nest_end(nlh, nest2);
+ }
+ mnl_attr_nest_end(nlh, nest1);
+ }
}
}
@@ -383,6 +419,28 @@ void nftnl_set_elems_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set
mnl_attr_nest_end(nlh, nest1);
}
+EXPORT_SYMBOL(nftnl_set_elem_add_expr);
+void nftnl_set_elem_add_expr(struct nftnl_set_elem *e, struct nftnl_expr *expr)
+{
+ list_add_tail(&expr->head, &e->expr_list);
+}
+
+EXPORT_SYMBOL(nftnl_set_elem_expr_foreach);
+int nftnl_set_elem_expr_foreach(struct nftnl_set_elem *e,
+ int (*cb)(struct nftnl_expr *e, void *data),
+ void *data)
+{
+ struct nftnl_expr *cur, *tmp;
+ int ret;
+
+ list_for_each_entry_safe(cur, tmp, &e->expr_list, head) {
+ ret = cb(cur, data);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
static int nftnl_set_elem_parse_attr_cb(const struct nlattr *attr, void *data)
{
const struct nlattr **tb = data;
@@ -405,6 +463,7 @@ static int nftnl_set_elem_parse_attr_cb(const struct nlattr *attr, void *data)
case NFTA_SET_ELEM_KEY_END:
case NFTA_SET_ELEM_DATA:
case NFTA_SET_ELEM_EXPR:
+ case NFTA_SET_ELEM_EXPRESSIONS:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
abi_breakage();
break;
@@ -476,12 +535,32 @@ static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest
}
}
if (tb[NFTA_SET_ELEM_EXPR]) {
- e->expr = nftnl_expr_parse(tb[NFTA_SET_ELEM_EXPR]);
- if (e->expr == NULL) {
+ struct nftnl_expr *expr;
+
+ expr = nftnl_expr_parse(tb[NFTA_SET_ELEM_EXPR]);
+ if (expr == NULL) {
ret = -1;
goto out_set_elem;
}
+ list_add_tail(&expr->head, &e->expr_list);
e->flags |= (1 << NFTNL_SET_ELEM_EXPR);
+ } else if (tb[NFTA_SET_ELEM_EXPRESSIONS]) {
+ struct nftnl_expr *expr;
+ struct nlattr *attr;
+
+ mnl_attr_for_each_nested(attr, tb[NFTA_SET_ELEM_EXPRESSIONS]) {
+ if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM) {
+ ret = -1;
+ goto out_set_elem;
+ }
+ expr = nftnl_expr_parse(attr);
+ if (expr == NULL) {
+ ret = -1;
+ goto out_set_elem;
+ }
+ list_add_tail(&expr->head, &e->expr_list);
+ }
+ e->flags |= (1 << NFTNL_SET_ELEM_EXPRESSIONS);
}
if (tb[NFTA_SET_ELEM_USERDATA]) {
const void *udata =
@@ -494,7 +573,7 @@ static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest
e->user.data = malloc(e->user.len);
if (e->user.data == NULL) {
ret = -1;
- goto out_expr;
+ goto out_set_elem;
}
memcpy(e->user.data, udata, e->user.len);
e->flags |= (1 << NFTNL_RULE_USERDATA);
@@ -512,8 +591,6 @@ static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest
list_add_tail(&e->head, &s->element_list);
return 0;
-out_expr:
- nftnl_expr_free(e->expr);
out_set_elem:
nftnl_set_elem_free(e);
return ret;
@@ -629,18 +706,28 @@ static int nftnl_set_elem_snprintf_default(char *buf, size_t size,
ret = snprintf(buf, remain, "element ");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- for (i = 0; i < div_round_up(e->key.len, sizeof(uint32_t)); i++) {
- ret = snprintf(buf + offset, remain, "%.8x ", e->key.val[i]);
+ ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->key,
+ NFTNL_OUTPUT_DEFAULT,
+ DATA_F_NOPFX, DATA_VALUE);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+
+ if (e->flags & (1 << NFTNL_SET_ELEM_KEY_END)) {
+ ret = snprintf(buf + offset, remain, " - ");
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+
+ ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->key_end,
+ NFTNL_OUTPUT_DEFAULT,
+ DATA_F_NOPFX, DATA_VALUE);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
ret = snprintf(buf + offset, remain, " : ");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- for (i = 0; i < div_round_up(e->data.len, sizeof(uint32_t)); i++) {
- ret = snprintf(buf + offset, remain, "%.8x ", e->data.val[i]);
- SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- }
+ ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->data,
+ NFTNL_OUTPUT_DEFAULT,
+ DATA_F_NOPFX, DATA_VALUE);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
ret = snprintf(buf + offset, remain, "%u [end]", e->set_elem_flags);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
diff --git a/tests/Makefile.in b/tests/Makefile.in
index c0de030..b104881 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -730,7 +730,7 @@ top_srcdir = @top_srcdir@
# set age to 0.
# </snippet>
#
-LIBVERSION = 15:0:4
+LIBVERSION = 16:0:5
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_srcdir}/include ${LIBMNL_CFLAGS} ${LIBMXML_CFLAGS}
AM_CFLAGS = ${regular_CFLAGS} ${GCC_FVISIBILITY_HIDDEN}
TESTS = $(check_PROGRAMS)