From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Subject: [PATCH 2/3 libnftnl,v2] src: add NFTNL_SET_EXPRESSIONS
Date: Thu, 17 Dec 2020 17:38:22 +0100 [thread overview]
Message-ID: <20201217163823.24180-2-pablo@netfilter.org> (raw)
In-Reply-To: <20201217163823.24180-1-pablo@netfilter.org>
NFTNL_SET_EXPR defines the stateful expression type that this set stores
in each element. This provides the set definition in terms of stateful
expressions. The expression that is passed via NFNTL_SET_ELEM_EXPR must
equal to this set stateful expression type, otherwise the kernel bails
out.
This patch adds support for the set expression list, which generalizes
NFTNL_SET_EXPR.
This patch also adds nftnl_set_add_expr() to add new expressions to a set
and nftnl_set_elem_expr_foreach() to iterate over the list of expressions.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: constify first parameter of _foreach function
include/libnftnl/set.h | 7 +++
include/set.h | 2 +-
src/libnftnl.map | 2 +
src/set.c | 111 +++++++++++++++++++++++++++++++++++------
4 files changed, 105 insertions(+), 17 deletions(-)
diff --git a/include/libnftnl/set.h b/include/libnftnl/set.h
index 1804850dc92b..1eae024c8523 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);
diff --git a/include/set.h b/include/set.h
index 66ac129836de..55018b6b9ba9 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/src/libnftnl.map b/src/libnftnl.map
index ce1c0820de2d..7078a5d38ba8 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -376,6 +376,8 @@ LIBNFTNL_15 {
} LIBNFTNL_14;
LIBNFTNL_16 {
+ nftnl_set_add_expr;
+ nftnl_set_expr_foreach;
nftnl_set_elem_add_expr;
nftnl_set_elem_expr_foreach;
} LIBNFTNL_15;
diff --git a/src/set.c b/src/set.c
index 15fa29d5f02c..8c5025d16206 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,
--
2.20.1
next prev parent reply other threads:[~2020-12-17 16:39 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-12-17 16:38 [PATCH 1/3 libnftnl,v2] src: add NFTNL_SET_ELEM_EXPRESSIONS Pablo Neira Ayuso
2020-12-17 16:38 ` Pablo Neira Ayuso [this message]
2020-12-17 16:38 ` [PATCH 3/3 libnftnl,v2] src: add NFTNL_EXPR_DYNSET_EXPRESSIONS Pablo Neira Ayuso
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201217163823.24180-2-pablo@netfilter.org \
--to=pablo@netfilter.org \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).