All of lore.kernel.org
 help / color / mirror / Atom feed
From: Florian Westphal <fw@strlen.de>
To: <netfilter-devel@vger.kernel.org>
Cc: Florian Westphal <fw@strlen.de>
Subject: [PATCH nft 1/2] expressions: concat: add typeof support
Date: Wed, 26 Feb 2020 13:26:26 +0100	[thread overview]
Message-ID: <20200226122627.27835-1-fw@strlen.de> (raw)

Previous patches allow to pass concatenations as the mapped-to
data type.

This doesn't work with typeof() because the concat expression has
no support to store the typeof data in the kernel, leading to:

map t2 {
    typeof numgen inc mod 2 : ip daddr . tcp dport

being shown as
     type 0 : ipv4_addr . inet_service

... which can't be parsed back by nft.

This allows the concat expression to store the sub-expressions
in set of nested attributes.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 src/expression.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 136 insertions(+)

diff --git a/src/expression.c b/src/expression.c
index a2694f4ab0e4..863cf86ec1d0 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -829,6 +829,140 @@ static void concat_expr_print(const struct expr *expr, struct output_ctx *octx)
 	compound_expr_print(expr, " . ", octx);
 }
 
+#define NFTNL_UDATA_SET_KEY_CONCAT_NEST 0
+#define NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX  NFT_REG32_SIZE
+
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE 0
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA 1
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_MAX  2
+
+static int concat_expr_build_udata(struct nftnl_udata_buf *udbuf,
+				    const struct expr *concat_expr)
+{
+	struct nftnl_udata *nest;
+	unsigned int i = 0;
+	struct expr *expr;
+
+	list_for_each_entry(expr, &concat_expr->expressions, list) {
+		struct nftnl_udata *nest_expr;
+		int err;
+
+		if (!expr_ops(expr)->build_udata || i >= NFT_REG32_SIZE)
+			return -1;
+
+		nest = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_NEST + i);
+		nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE, expr->etype);
+		nest_expr = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA);
+		err = expr_ops(expr)->build_udata(udbuf, expr);
+		if (err < 0)
+			return err;
+		nftnl_udata_nest_end(udbuf, nest_expr);
+		nftnl_udata_nest_end(udbuf, nest);
+		i++;
+	}
+
+	return 0;
+}
+
+static int concat_parse_udata_nest(const struct nftnl_udata *attr, void *data)
+{
+	const struct nftnl_udata **ud = data;
+	uint8_t type = nftnl_udata_type(attr);
+	uint8_t len = nftnl_udata_len(attr);
+
+	if (type >= NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX)
+		return -1;
+
+	if (len <= sizeof(uint32_t))
+		return -1;
+
+	ud[type] = attr;
+	return 0;
+}
+
+static int concat_parse_udata_nested(const struct nftnl_udata *attr, void *data)
+{
+	const struct nftnl_udata **ud = data;
+	uint8_t type = nftnl_udata_type(attr);
+	uint8_t len = nftnl_udata_len(attr);
+
+	switch (type) {
+	case NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE:
+		if (len != sizeof(uint32_t))
+			return -1;
+		break;
+	case NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA:
+		if (len <= sizeof(uint32_t))
+			return -1;
+		break;
+	default:
+		return 0;
+	}
+
+	ud[type] = attr;
+	return 0;
+}
+
+static struct expr *concat_expr_parse_udata(const struct nftnl_udata *attr)
+{
+	const struct nftnl_udata *ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX] = {};
+	struct expr *concat_expr;
+	struct datatype *dtype;
+	unsigned int i;
+	int err;
+
+	err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+				concat_parse_udata_nest, ud);
+	if (err < 0)
+		return NULL;
+
+	concat_expr = concat_expr_alloc(&internal_location);
+	if (!concat_expr)
+		return NULL;
+
+	dtype = xzalloc(sizeof(*dtype));
+
+	for (i = 0; i < array_size(ud); i++) {
+		const struct nftnl_udata *nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_MAX];
+		const struct nftnl_udata *nested, *subdata;
+		const struct expr_ops *ops;
+		struct expr *expr;
+		uint32_t etype;
+
+		if (ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST + i] == NULL)
+			break;
+
+		nested = ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST + i];
+		err = nftnl_udata_parse(nftnl_udata_get(nested), nftnl_udata_len(nested),
+					concat_parse_udata_nested, nest_ud);
+		if (err < 0)
+			goto err_free;
+
+		etype = nftnl_udata_get_u32(nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE]);
+		ops = expr_ops_by_type(etype);
+		if (!ops || !ops->parse_udata)
+			goto err_free;
+
+		subdata = nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA];
+		expr = ops->parse_udata(subdata);
+		if (!expr)
+			goto err_free;
+
+		dtype->subtypes++;
+		compound_expr_add(concat_expr, expr);
+		dtype->size += round_up(expr->len, BITS_PER_BYTE * sizeof(uint32_t));
+	}
+
+	concat_expr->dtype = dtype;
+	concat_expr->len = dtype->size;
+
+	return concat_expr;
+
+err_free:
+	expr_free(concat_expr);
+	return NULL;
+}
+
 static const struct expr_ops concat_expr_ops = {
 	.type		= EXPR_CONCAT,
 	.name		= "concat",
@@ -836,6 +970,8 @@ static const struct expr_ops concat_expr_ops = {
 	.json		= concat_expr_json,
 	.clone		= compound_expr_clone,
 	.destroy	= concat_expr_destroy,
+	.build_udata	= concat_expr_build_udata,
+	.parse_udata	= concat_expr_parse_udata,
 };
 
 struct expr *concat_expr_alloc(const struct location *loc)
-- 
2.24.1


             reply	other threads:[~2020-02-26 12:26 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-26 12:26 Florian Westphal [this message]
2020-02-26 12:26 ` [PATCH nft 2/2] tests: update nat_addr_port with typeof+concat maps Florian Westphal
2020-02-26 12:31 ` [PATCH nft 1/2] expressions: concat: add typeof support 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=20200226122627.27835-1-fw@strlen.de \
    --to=fw@strlen.de \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.