netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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


  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).