All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Subject: [PATCH nf-next 5/5] netfilter: nftables: netlink support for several set element expressions
Date: Mon,  7 Dec 2020 19:16:51 +0100	[thread overview]
Message-ID: <20201207181651.18771-6-pablo@netfilter.org> (raw)
In-Reply-To: <20201207181651.18771-1-pablo@netfilter.org>

This patch adds three new netlink attribute to encapsulate a list of
expressions per set elements:

- NFTA_SET_EXPRESSIONS: this attribute provides the set definition in
  terms of expressions. New set elements get attached the list of
  expressions that is specified by this new netlink attribute.
- NFTA_SET_ELEM_EXPRESSIONS: this attribute allows users to restore (or
  initialize) the stateful information of set elements when adding an
  element to the set.
- NFTA_DYNSET_EXPRESSIONS: this attribute specifies the list of
  expressions that the set element gets when it is inserted from the
  packet path.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/uapi/linux/netfilter/nf_tables.h |   3 +
 net/netfilter/nf_tables_api.c            | 101 ++++++++++++++++++++++-
 net/netfilter/nft_dynset.c               |  43 +++++++++-
 3 files changed, 142 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 98272cb5f617..42e4c4cb0daa 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -381,6 +381,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)
@@ -419,6 +420,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)
@@ -725,6 +727,7 @@ enum nft_dynset_attributes {
 	NFTA_DYNSET_SREG_DATA,
 	NFTA_DYNSET_TIMEOUT,
 	NFTA_DYNSET_EXPR,
+	NFTA_DYNSET_EXPRESSIONS,
 	NFTA_DYNSET_PAD,
 	NFTA_DYNSET_FLAGS,
 	__NFTA_DYNSET_MAX,
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index a98e4ce4e796..aa57c6083430 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -3596,6 +3596,7 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
 	[NFTA_SET_OBJ_TYPE]		= { .type = NLA_U32 },
 	[NFTA_SET_HANDLE]		= { .type = NLA_U64 },
 	[NFTA_SET_EXPR]			= { .type = NLA_NESTED },
+	[NFTA_SET_EXPRESSIONS]		= { .type = NLA_NESTED },
 };
 
 static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
@@ -3803,6 +3804,7 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
 	u32 portid = ctx->portid;
 	struct nlattr *nest;
 	u32 seq = ctx->seq;
+	int i;
 
 	event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
@@ -3877,6 +3879,25 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
 			goto nla_put_failure;
 
 		nla_nest_end(skb, nest);
+	} else if (set->num_exprs > 1) {
+		struct nlattr *nest_list;
+
+		nest = nla_nest_start_noflag(skb, NFTA_SET_EXPRESSIONS);
+		if (nest == NULL)
+			goto nla_put_failure;
+
+		for (i = 0; i < set->num_exprs; i++) {
+			nest_list = nla_nest_start_noflag(skb, NFTA_LIST_ELEM);
+			if (nest_list == NULL)
+				goto nla_put_failure;
+
+			if (nft_expr_dump(skb, NFTA_SET_ELEM_EXPR,
+					  set->exprs[i]) < 0)
+				goto nla_put_failure;
+
+			nla_nest_end(skb, nest_list);
+		}
+		nla_nest_end(skb, nest);
 	}
 
 	nlmsg_end(skb, nlh);
@@ -4245,7 +4266,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 			return err;
 	}
 
-	if (nla[NFTA_SET_EXPR])
+	if (nla[NFTA_SET_EXPR] || nla[NFTA_SET_EXPRESSIONS])
 		desc.expr = true;
 
 	table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family, genmask);
@@ -4311,6 +4332,33 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 		}
 		set->exprs[0] = expr;
 		set->num_exprs++;
+	} else if (nla[NFTA_SET_EXPRESSIONS]) {
+		struct nft_expr_info_array info_array = {
+			.size		= 0,
+			.num_exprs	= 0,
+		};
+		struct nft_expr *expr;
+		int err;
+
+		err = nft_expr_parse(&ctx, nla[NFTA_SET_EXPRESSIONS],
+				     &info_array, NFT_SET_EXPR_MAX);
+		if (err < 0)
+			return err;
+
+		for (i = 0; i < info_array.num_exprs; i++) {
+			expr = nft_set_elem_expr_alloc(&ctx, set,
+						       info_array.info[i].attr);
+			if (IS_ERR(expr))
+				goto err_set_init;
+
+			set->exprs[i] = expr;
+			set->num_exprs++;
+		}
+
+		if (set->num_exprs != info_array.num_exprs) {
+			err = -EOPNOTSUPP;
+			goto err_set_init;
+		}
 	}
 
 	udata = NULL;
@@ -4570,6 +4618,7 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
 	[NFTA_SET_ELEM_OBJREF]		= { .type = NLA_STRING,
 					    .len = NFT_OBJ_MAXNAMELEN - 1 },
 	[NFTA_SET_ELEM_KEY_END]		= { .type = NLA_NESTED },
+	[NFTA_SET_ELEM_EXPRESSIONS]	= { .type = NLA_NESTED },
 };
 
 static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
@@ -4608,6 +4657,7 @@ static int nft_set_elem_expr_dump(struct sk_buff *skb,
 				  const struct nft_set_ext *ext)
 {
 	struct nft_set_elem_expr *elem_expr;
+	struct nlattr *nest, *nest_list;
 	u32 size, num_exprs = 0;
 	struct nft_expr *expr;
 
@@ -4623,7 +4673,27 @@ static int nft_set_elem_expr_dump(struct sk_buff *skb,
 		return 0;
 	}
 
+	nest = nla_nest_start_noflag(skb, NFTA_SET_ELEM_EXPRESSIONS);
+	if (nest == NULL)
+		goto nla_put_failure;
+
+	nft_setelem_expr_foreach(expr, elem_expr, size) {
+		nest_list = nla_nest_start_noflag(skb, NFTA_LIST_ELEM);
+		if (nest_list == NULL)
+			goto nla_put_failure;
+
+		expr = nft_setelem_expr_at(elem_expr, size);
+		if (nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, expr) < 0)
+			goto nla_put_failure;
+
+		nla_nest_end(skb, nest_list);
+	}
+	nla_nest_end(skb, nest);
+
 	return 0;
+
+nla_put_failure:
+	return -1;
 }
 
 static int nf_tables_fill_setelem(struct sk_buff *skb,
@@ -5298,7 +5368,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
 	      nla[NFTA_SET_ELEM_TIMEOUT] ||
 	      nla[NFTA_SET_ELEM_EXPIRATION] ||
 	      nla[NFTA_SET_ELEM_USERDATA] ||
-	      nla[NFTA_SET_ELEM_EXPR]))
+	      nla[NFTA_SET_ELEM_EXPR] ||
+	      nla[NFTA_SET_ELEM_EXPRESSIONS]))
 		return -EINVAL;
 
 	timeout = 0;
@@ -5337,6 +5408,32 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
 			err = -EOPNOTSUPP;
 			goto err_set_elem_expr;
 		}
+	} else if (nla[NFTA_SET_ELEM_EXPRESSIONS] && set->num_exprs > 0) {
+		struct nft_expr_info_array info_array = {
+			.size		= 0,
+			.num_exprs	= 0,
+		};
+		struct nft_expr *expr;
+		int err;
+
+		err = nft_expr_parse(ctx, nla[NFTA_SET_ELEM_EXPRESSIONS],
+				     &info_array, NFT_SET_EXPR_MAX);
+		if (err < 0)
+			return err;
+
+		for (i = 0; i < info_array.num_exprs; i++) {
+			expr = nft_set_elem_expr_alloc(ctx, set,
+						       info_array.info[i].attr);
+			if (IS_ERR(expr))
+				goto err_set_elem_expr;
+
+			expr_array[i] = expr;
+		}
+
+		if (set->num_exprs != info_array.num_exprs) {
+			err = -EOPNOTSUPP;
+			goto err_set_elem_expr;
+		}
 	} else if (set->num_exprs > 0) {
 		err = nft_set_elem_expr_clone(ctx, set, expr_array);
 		if (err < 0)
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index 0ac9f1205b56..607d396e644a 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -153,6 +153,7 @@ static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = {
 	[NFTA_DYNSET_TIMEOUT]	= { .type = NLA_U64 },
 	[NFTA_DYNSET_EXPR]	= { .type = NLA_NESTED },
 	[NFTA_DYNSET_FLAGS]	= { .type = NLA_U32 },
+	[NFTA_DYNSET_EXPRESSIONS] = { .type = NLA_NESTED, },
 };
 
 static int nft_dynset_init(const struct nft_ctx *ctx,
@@ -232,12 +233,13 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
 	} else if (set->flags & NFT_SET_MAP)
 		return -EINVAL;
 
+	if ((tb[NFTA_DYNSET_EXPR] || tb[NFTA_DYNSET_EXPR]) &&
+	    !(set->flags & NFT_SET_EVAL))
+		return -EINVAL;
+
 	if (tb[NFTA_DYNSET_EXPR]) {
 		struct nft_expr *dynset_expr;
 
-		if (!(set->flags & NFT_SET_EVAL))
-			return -EINVAL;
-
 		dynset_expr = nft_dynset_expr_alloc(ctx, set,
 						    tb[NFTA_DYNSET_EXPR], 0);
 		if (IS_ERR(dynset_expr))
@@ -245,6 +247,28 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
 
 		priv->num_exprs++;
 		priv->expr_array[0] = dynset_expr;
+	} else if (tb[NFTA_DYNSET_EXPRESSIONS]) {
+		struct nft_expr_info_array info_array = {
+			.size		= 0,
+			.num_exprs	= 0,
+		};
+		struct nft_expr *dynset_expr;
+		int err;
+
+		err = nft_expr_parse(ctx, tb[NFTA_DYNSET_EXPRESSIONS],
+				     &info_array, NFT_SET_EXPR_MAX);
+		if (err < 0)
+			return err;
+
+		for (i = 0; i < info_array.num_exprs; i++) {
+			dynset_expr = nft_dynset_expr_alloc(ctx, set,
+							    info_array.info[i].attr, i);
+			if (IS_ERR(dynset_expr))
+				return PTR_ERR(dynset_expr);
+
+			priv->expr_array[i] = dynset_expr;
+			priv->num_exprs++;
+		}
 	}
 
 	nft_set_ext_prepare(&priv->tmpl);
@@ -329,6 +353,19 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
 	if (priv->num_exprs == 1) {
 		if (nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr_array[i]))
 			goto nla_put_failure;
+	} else if (priv->num_exprs > 1) {
+		struct nlattr *nest;
+
+		nest = nla_nest_start_noflag(skb, NFTA_DYNSET_EXPRESSIONS);
+		if (!nest)
+			goto nla_put_failure;
+
+		for (i = 0; i < priv->num_exprs; i++) {
+			if (nft_expr_dump(skb, NFTA_DYNSET_EXPR,
+					  priv->expr_array[i]))
+				goto nla_put_failure;
+		}
+		nla_nest_end(skb, nest);
 	}
 	if (nla_put_be32(skb, NFTA_DYNSET_FLAGS, htonl(flags)))
 		goto nla_put_failure;
-- 
2.20.1


  parent reply	other threads:[~2020-12-07 18:18 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-07 18:16 [PATCH nf-next 0/5] support for several expression in set elements Pablo Neira Ayuso
2020-12-07 18:16 ` [PATCH nf-next 1/5] netfilter: nftables: generalize set expressions support Pablo Neira Ayuso
2020-12-07 18:16 ` [PATCH nf-next 2/5] netfilter: nftables: move nft_expr before nft_set Pablo Neira Ayuso
2020-12-07 18:16 ` [PATCH nf-next 3/5] netfilter: nftables: generalize set extension to support for several expressions Pablo Neira Ayuso
2020-12-07 18:16 ` [PATCH nf-next 4/5] netfilter: nftables: add nft_expr_parse() helper function Pablo Neira Ayuso
2020-12-07 18:16 ` Pablo Neira Ayuso [this message]
2020-12-08 10:11   ` [PATCH nf-next 5/5] netfilter: nftables: netlink support for several set element expressions Florian Westphal

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=20201207181651.18771-6-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 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.