All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nft] src: add multidevice support for netdev chain
@ 2019-10-18  9:50 Pablo Neira Ayuso
  0 siblings, 0 replies; only message in thread
From: Pablo Neira Ayuso @ 2019-10-18  9:50 UTC (permalink / raw)
  To: netfilter-devel

This patch allows you to specify multiple netdevices to be bound to the
netdev basechain, eg.

 # nft add chain netdev x y { \
	type filter hook ingress devices = { eth0, eth1 } priority 0\; }

json codebase has been updated to support for one single device with the
existing representation, no support for multidevice is included in this
patch.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/rule.h     |  4 +++-
 src/json.c         | 17 +++++++++++++----
 src/mnl.c          | 29 ++++++++++++++++++++++++-----
 src/netlink.c      | 20 +++++++++++++++++---
 src/parser_bison.y | 26 ++++++++++++++++++++------
 src/parser_json.c  | 18 +++++++++++++++---
 src/rule.c         | 22 +++++++++++++++++-----
 7 files changed, 109 insertions(+), 27 deletions(-)

diff --git a/include/rule.h b/include/rule.h
index 2708cbebc9f8..ba40db8806fc 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -208,7 +208,9 @@ struct chain {
 	struct prio_spec	priority;
 	struct expr		*policy;
 	const char		*type;
-	const char		*dev;
+	const char		**dev_array;
+	struct expr		*dev_expr;
+	int			dev_array_len;
 	struct scope		scope;
 	struct list_head	rules;
 };
diff --git a/src/json.c b/src/json.c
index 13a064249d90..56b20549bd73 100644
--- a/src/json.c
+++ b/src/json.c
@@ -222,9 +222,9 @@ static json_t *rule_print_json(struct output_ctx *octx,
 
 static json_t *chain_print_json(const struct chain *chain)
 {
+	int priority, policy, n = 0;
+	struct expr *dev, *expr;
 	json_t *root, *tmp;
-	int priority;
-	int policy;
 
 	root = json_pack("{s:s, s:s, s:s, s:I}",
 			 "family", family2str(chain->handle.family),
@@ -243,8 +243,17 @@ static json_t *chain_print_json(const struct chain *chain)
 						    chain->hooknum),
 				"prio", priority,
 				"policy", chain_policy2str(policy));
-		if (chain->dev)
-			json_object_set_new(tmp, "dev", json_string(chain->dev));
+		if (chain->dev_expr) {
+			list_for_each_entry(expr, &chain->dev_expr->expressions, list) {
+				dev = expr;
+				n++;
+			}
+		}
+
+		if (n == 1) {
+			json_object_set_new(tmp, "dev",
+					    json_string(dev->identifier));
+		}
 		json_object_update(root, tmp);
 		json_decref(tmp);
 	}
diff --git a/src/mnl.c b/src/mnl.c
index 75ab07b045aa..ee5d0a1a2a15 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -526,10 +526,12 @@ err:
 int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 		      unsigned int flags)
 {
+	int priority, policy, i = 0;
 	struct nftnl_chain *nlc;
+	const char **dev_array;
 	struct nlmsghdr *nlh;
-	int priority;
-	int policy;
+	struct expr *expr;
+	int dev_array_len;
 
 	nlc = nftnl_chain_alloc();
 	if (nlc == NULL)
@@ -555,9 +557,26 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 					BYTEORDER_HOST_ENDIAN, sizeof(int));
 			nftnl_chain_set_u32(nlc, NFTNL_CHAIN_POLICY, policy);
 		}
-		if (cmd->chain->dev != NULL)
-			nftnl_chain_set_str(nlc, NFTNL_CHAIN_DEV,
-					    cmd->chain->dev);
+		if (cmd->chain->dev_expr) {
+			dev_array = xmalloc(sizeof(char *) * 8);
+			dev_array_len = 8;
+			list_for_each_entry(expr, &cmd->chain->dev_expr->expressions, list) {
+				dev_array[i++] = expr->identifier;
+				if (i == dev_array_len) {
+					dev_array_len *= 2;
+					dev_array = xrealloc(dev_array,
+							     dev_array_len);
+				}
+			}
+
+			dev_array[i] = NULL;
+			if (i == 1)
+				nftnl_chain_set_str(nlc, NFTNL_CHAIN_DEV, dev_array[0]);
+			else if (i > 1)
+				nftnl_chain_set(nlc, NFTNL_CHAIN_DEVICES, dev_array);
+
+			xfree(dev_array);
+		}
 	}
 	netlink_dump_chain(nlc, ctx);
 
diff --git a/src/netlink.c b/src/netlink.c
index 1e669e5dcaa1..c47771d3c801 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -378,9 +378,9 @@ void netlink_dump_chain(const struct nftnl_chain *nlc, struct netlink_ctx *ctx)
 struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
 					const struct nftnl_chain *nlc)
 {
+	int priority, policy, len = 0, i;
+	const char * const *dev_array;
 	struct chain *chain;
-	int priority;
-	int policy;
 
 	chain = chain_alloc(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME));
 	chain->handle.family =
@@ -415,8 +415,22 @@ struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
 						    &policy);
 			nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY);
 		if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEV)) {
-			chain->dev	=
+			chain->dev_array = xmalloc(sizeof(char *));
+			chain->dev_array_len = 1;
+			chain->dev_array[0] =
 				xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_DEV));
+			chain->dev_array[1] = NULL;
+		} else if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEVICES)) {
+			dev_array = nftnl_chain_get(nlc, NFTNL_CHAIN_DEVICES);
+			while (dev_array[len])
+				len++;
+
+			chain->dev_array = xmalloc(len * sizeof(char *));
+			for (i = 0; i < len; i++)
+				chain->dev_array[i] = xstrdup(dev_array[i]);
+
+			chain->dev_array[i] = NULL;
+			chain->dev_array_len = len;
 		}
 		chain->flags        |= CHAIN_F_BASECHAIN;
 	}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 11f0dc8b2153..7f9b1752f41d 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -564,11 +564,11 @@ int nft_lex(void *, void *, void *);
 %type <val>			family_spec family_spec_explicit
 %type <val32>			int_num	chain_policy
 %type <prio_spec>		extended_prio_spec prio_spec
-%type <string>			extended_prio_name
-%destructor { xfree($$); }	extended_prio_name
+%type <string>			extended_prio_name quota_unit
+%destructor { xfree($$); }	extended_prio_name quota_unit
 
-%type <string>			dev_spec quota_unit
-%destructor { xfree($$); }	dev_spec quota_unit
+%type <expr>			dev_spec
+%destructor { xfree($$); }	dev_spec
 
 %type <table>			table_block_alloc table_block
 %destructor { close_scope(state); table_free($$); }	table_block_alloc
@@ -1992,7 +1992,7 @@ hook_spec		:	TYPE		STRING		HOOK		STRING		dev_spec	prio_spec
 				}
 				xfree($4);
 
-				$<chain>0->dev		= $5;
+				$<chain>0->dev_expr	= $5;
 				$<chain>0->priority	= $6;
 				$<chain>0->flags	|= CHAIN_F_BASECHAIN;
 			}
@@ -2072,7 +2072,21 @@ int_num			:	NUM			{ $$ = $1; }
 			|	DASH	NUM		{ $$ = -$2; }
 			;
 
-dev_spec		:	DEVICE	string		{ $$ = $2; }
+dev_spec		:	DEVICE	string
+			{
+				struct expr *expr;
+
+				expr = constant_expr_alloc(&@$, &string_type,
+							   BYTEORDER_HOST_ENDIAN,
+							   strlen($2) * BITS_PER_BYTE, $2);
+				$$ = compound_expr_alloc(&@$, EXPR_LIST);
+				compound_expr_add($$, expr);
+
+			}
+			|	DEVICES		'='	flowtable_expr
+			{
+				$$ = $3;
+			}
 			|	/* empty */		{ $$ = NULL; }
 			;
 
diff --git a/src/parser_json.c b/src/parser_json.c
index 55dbc177cc98..0c79189ec526 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -17,6 +17,7 @@
 #include <netinet/icmp6.h>
 #include <netinet/ip.h>
 #include <netinet/ip_icmp.h>
+#include <net/if.h>
 #include <linux/xfrm.h>
 
 #include <linux/netfilter.h>
@@ -2581,8 +2582,9 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
 		.table.location = *int_loc,
 	};
 	const char *family = "", *policy = "", *type, *hookstr;
-	int prio;
+	const char name[IFNAMSIZ];
 	struct chain *chain;
+	int prio;
 
 	if (json_unpack_err(ctx, root, "{s:s, s:s}",
 			    "family", &family,
@@ -2626,8 +2628,18 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
 		return NULL;
 	}
 
-	if (!json_unpack(root, "{s:s}", "dev", &chain->dev))
-		chain->dev = xstrdup(chain->dev);
+	if (!json_unpack(root, "{s:s}", "dev", &name)) {
+		struct expr *dev_expr, *expr;
+
+		dev_expr = compound_expr_alloc(int_loc, EXPR_LIST);
+		expr = constant_expr_alloc(int_loc, &integer_type,
+					   BYTEORDER_HOST_ENDIAN,
+					   strlen(name) * BITS_PER_BYTE,
+					   name);
+		compound_expr_add(dev_expr, expr);
+		chain->dev_expr = dev_expr;
+	}
+
 	if (!json_unpack(root, "{s:s}", "policy", &policy)) {
 		chain->policy = parse_policy(policy);
 		if (chain->policy < 0) {
diff --git a/src/rule.c b/src/rule.c
index 55894cbdb766..ec7bcb97425e 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -813,6 +813,7 @@ struct chain *chain_get(struct chain *chain)
 void chain_free(struct chain *chain)
 {
 	struct rule *rule, *next;
+	int i;
 
 	if (--chain->refcnt > 0)
 		return;
@@ -821,8 +822,10 @@ void chain_free(struct chain *chain)
 	handle_free(&chain->handle);
 	scope_release(&chain->scope);
 	xfree(chain->type);
-	if (chain->dev != NULL)
-		xfree(chain->dev);
+	expr_free(chain->dev_expr);
+	for (i = 0; i < chain->dev_array_len; i++)
+		xfree(chain->dev_array[i]);
+	xfree(chain->dev_array);
 	expr_free(chain->priority.expr);
 	expr_free(chain->policy);
 	xfree(chain);
@@ -1101,7 +1104,7 @@ static void chain_print_declaration(const struct chain *chain,
 				    struct output_ctx *octx)
 {
 	char priobuf[STD_PRIO_BUFSIZE];
-	int policy;
+	int policy, i;
 
 	nft_print(octx, "\tchain %s {", chain->handle.chain.name);
 	if (nft_output_handle(octx))
@@ -1110,8 +1113,17 @@ static void chain_print_declaration(const struct chain *chain,
 	if (chain->flags & CHAIN_F_BASECHAIN) {
 		nft_print(octx, "\t\ttype %s hook %s", chain->type,
 			  hooknum2str(chain->handle.family, chain->hooknum));
-		if (chain->dev != NULL)
-			nft_print(octx, " device \"%s\"", chain->dev);
+		if (chain->dev_array_len == 1) {
+			nft_print(octx, " device \"%s\"", chain->dev_array[0]);
+		} else if (chain->dev_array_len > 1) {
+			nft_print(octx, " devices = { ");
+			for (i = 0; i < chain->dev_array_len; i++) {
+				nft_print(octx, "%s", chain->dev_array[i]);
+					if (i + 1 != chain->dev_array_len)
+						nft_print(octx, ", ");
+			}
+			nft_print(octx, " }");
+		}
 		nft_print(octx, " priority %s;",
 			  prio2str(octx, priobuf, sizeof(priobuf),
 				   chain->handle.family, chain->hooknum,
-- 
2.11.0


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2019-10-18  9:50 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-18  9:50 [PATCH nft] src: add multidevice support for netdev chain Pablo Neira Ayuso

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.