[PATCH nft,v1 1/2] src: add tunnel support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds support to attach tunnel metadata.

Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
---
 include/rule.h     | 15 +++++++++++
 src/evaluate.c     | 23 ++++++++++++++++
 src/mnl.c          | 38 +++++++++++++++++++++++++++
 src/netlink.c      | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/parser_bison.y | 50 ++++++++++++++++++++++++++++++++---
 src/rule.c         | 21 +++++++++++++++
 src/scanner.l      |  4 ++-
 7 files changed, 224 insertions(+), 4 deletions(-)

diff --git a/include/rule.h b/include/rule.h
index ee881b9ccd17..00c16e39e980 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -406,6 +406,18 @@ struct secmark {
 	char		ctx[NFT_SECMARK_CTX_MAXLEN];
 };
 
+struct tunnel {
+	const char	*type;
+	uint32_t	id;
+	struct expr	*src;
+	struct expr	*dst;
+	uint32_t	label;
+	uint16_t	sport;
+	uint16_t	dport;
+	uint8_t		tos;
+	uint8_t		ttl;
+};
+
 /**
  * struct obj - nftables stateful object statement
  *
@@ -426,6 +438,7 @@ struct obj {
 		struct quota		quota;
 		struct ct_helper	ct_helper;
 		struct limit		limit;
+		struct tunnel		tunnel;
 		struct ct_timeout	ct_timeout;
 		struct secmark		secmark;
 		struct ct_expect	ct_expect;
@@ -558,6 +571,8 @@ enum cmd_obj {
 	CMD_OBJ_CT_HELPERS,
 	CMD_OBJ_LIMIT,
 	CMD_OBJ_LIMITS,
+	CMD_OBJ_TUNNEL,
+	CMD_OBJ_TUNNELS,
 	CMD_OBJ_FLOWTABLE,
 	CMD_OBJ_FLOWTABLES,
 	CMD_OBJ_CT_TIMEOUT,
diff --git a/src/evaluate.c b/src/evaluate.c
index 48c65cd2f35a..0c2a8d0a9571 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -3520,9 +3520,31 @@ static int ct_timeout_evaluate(struct eval_ctx *ctx, struct obj *obj)
 	return 0;
 }
 
+static int tunnel_evaluate(struct eval_ctx *ctx, struct obj *obj)
+{
+	if (obj->tunnel.src != NULL) {
+		__expr_set_context(&ctx->ectx, &ipaddr_type,
+				   BYTEORDER_BIG_ENDIAN,
+				   sizeof(struct in_addr) * BITS_PER_BYTE, 0);
+		if (expr_evaluate(ctx, &obj->tunnel.src) < 0)
+			return -1;
+        }
+	if (obj->tunnel.dst != NULL) {
+		__expr_set_context(&ctx->ectx, &ipaddr_type,
+				   BYTEORDER_BIG_ENDIAN,
+				   sizeof(struct in_addr) * BITS_PER_BYTE, 0);
+		if (expr_evaluate(ctx, &obj->tunnel.dst) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
 static int obj_evaluate(struct eval_ctx *ctx, struct obj *obj)
 {
 	switch (obj->type) {
+	case NFT_OBJECT_TUNNEL:
+		return tunnel_evaluate(ctx, obj);
 	case NFT_OBJECT_CT_TIMEOUT:
 		return ct_timeout_evaluate(ctx, obj);
 	case NFT_OBJECT_CT_EXPECT:
@@ -3604,6 +3626,7 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
 	case CMD_OBJ_QUOTA:
 	case CMD_OBJ_CT_HELPER:
 	case CMD_OBJ_LIMIT:
+	case CMD_OBJ_TUNNEL:
 	case CMD_OBJ_CT_TIMEOUT:
 	case CMD_OBJ_SECMARK:
 	case CMD_OBJ_CT_EXPECT:
diff --git a/src/mnl.c b/src/mnl.c
index eab8d5486437..e9021e4515ae 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -951,6 +951,7 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 		    unsigned int flags)
 {
 	struct obj *obj = cmd->object;
+	struct nft_data_linearize nld;
 	struct nftnl_obj *nlo;
 	struct nlmsghdr *nlh;
 
@@ -985,6 +986,43 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 		nftnl_obj_set_u32(nlo, NFTNL_OBJ_LIMIT_TYPE, obj->limit.type);
 		nftnl_obj_set_u32(nlo, NFTNL_OBJ_LIMIT_FLAGS, obj->limit.flags);
 		break;
+	case NFT_OBJECT_TUNNEL:
+		nftnl_obj_set_u64(nlo, NFTNL_OBJ_TUNNEL_ID, obj->tunnel.id);
+		if (obj->tunnel.sport)
+			nftnl_obj_set_u16(nlo, NFTNL_OBJ_TUNNEL_SPORT,
+					  obj->tunnel.sport);
+		if (obj->tunnel.dport)
+			nftnl_obj_set_u16(nlo, NFTNL_OBJ_TUNNEL_DPORT,
+					  obj->tunnel.dport);
+		if (obj->tunnel.tos)
+			nftnl_obj_set_u16(nlo, NFTNL_OBJ_TUNNEL_TOS,
+					  obj->tunnel.tos);
+		if (obj->tunnel.ttl)
+			nftnl_obj_set_u16(nlo, NFTNL_OBJ_TUNNEL_TTL,
+					  obj->tunnel.ttl);
+		if (obj->tunnel.src) {
+			netlink_gen_data(obj->tunnel.src, &nld);
+			if (nld.len == sizeof(struct in_addr)) {
+				nftnl_obj_set_u32(nlo,
+						  NFTNL_OBJ_TUNNEL_IPV4_SRC,
+						  nld.value[0]);
+			}
+		} else {
+			nftnl_obj_set(nlo, NFTNL_OBJ_TUNNEL_IPV6_SRC,
+				      nld.value);
+		}
+		if (obj->tunnel.dst) {
+			netlink_gen_data(obj->tunnel.dst, &nld);
+			if (nld.len == sizeof(struct in_addr)) {
+				nftnl_obj_set_u32(nlo,
+						  NFTNL_OBJ_TUNNEL_IPV4_DST,
+						  nld.value[0]);
+			} else {
+				nftnl_obj_set(nlo, NFTNL_OBJ_TUNNEL_IPV6_DST,
+					      nld.value);
+			}
+		}
+		break;
 	case NFT_OBJECT_CT_HELPER:
 		nftnl_obj_set_str(nlo, NFTNL_OBJ_CT_HELPER_NAME,
 				  obj->ct_helper.name);
diff --git a/src/netlink.c b/src/netlink.c
index 14b0df410726..bcb5ecc6bb32 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -936,6 +936,51 @@ void netlink_dump_obj(struct nftnl_obj *nln, struct netlink_ctx *ctx)
 	fprintf(fp, "\n");
 }
 
+static struct in6_addr all_zeroes;
+
+static struct expr *netlink_obj_tunnel_parse_addr(struct nftnl_obj *nlo,
+						  int attr)
+{
+	struct nft_data_delinearize nld;
+	const struct datatype *dtype;
+	const uint32_t *addr6;
+	struct expr *expr;
+	uint32_t addr;
+
+	memset(&nld, 0, sizeof(nld));
+
+	switch (attr) {
+	case NFTNL_OBJ_TUNNEL_IPV4_SRC:
+	case NFTNL_OBJ_TUNNEL_IPV4_DST:
+		addr = nftnl_obj_get_u32(nlo, attr);
+		if (!addr)
+			return NULL;
+
+		dtype = &ipaddr_type;
+		nld.value = &addr;
+		nld.len = sizeof(struct in_addr);
+		break;
+	case NFTNL_OBJ_TUNNEL_IPV6_SRC:
+	case NFTNL_OBJ_TUNNEL_IPV6_DST:
+		addr6 = nftnl_obj_get(nlo, attr);
+		if (!memcmp(addr6, &all_zeroes, sizeof(all_zeroes)))
+			return NULL;
+
+		dtype = &ip6addr_type;
+		nld.value = addr6;
+		nld.len = sizeof(struct in6_addr);
+		break;
+	default:
+		return NULL;
+	}
+
+	expr = netlink_alloc_value(&netlink_location, &nld);
+	expr->dtype	= dtype;
+	expr->byteorder	= BYTEORDER_BIG_ENDIAN;
+
+	return expr;
+}
+
 struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
 				    struct nftnl_obj *nlo)
 {
@@ -1008,6 +1053,38 @@ struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
 		obj->ct_expect.size =
 			nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_EXPECT_SIZE);
 		break;
+	case NFT_OBJECT_TUNNEL:
+		obj->tunnel.id = nftnl_obj_get_u64(nlo, NFTNL_OBJ_TUNNEL_ID);
+		obj->tunnel.sport =
+			nftnl_obj_get_u16(nlo, NFTNL_OBJ_TUNNEL_SPORT);
+		obj->tunnel.dport =
+			nftnl_obj_get_u16(nlo, NFTNL_OBJ_TUNNEL_DPORT);
+		obj->tunnel.tos =
+			nftnl_obj_get_u16(nlo, NFTNL_OBJ_TUNNEL_TOS) >> 2;
+		obj->tunnel.ttl =
+			nftnl_obj_get_u16(nlo, NFTNL_OBJ_TUNNEL_TTL);
+
+		if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_IPV4_SRC)) {
+			obj->tunnel.src =
+				netlink_obj_tunnel_parse_addr(nlo,
+					NFTNL_OBJ_TUNNEL_IPV4_SRC);
+		}
+		if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_IPV4_DST)) {
+			obj->tunnel.dst =
+				netlink_obj_tunnel_parse_addr(nlo,
+					NFTNL_OBJ_TUNNEL_IPV4_DST);
+		}
+		if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_IPV6_SRC)) {
+			obj->tunnel.src =
+				netlink_obj_tunnel_parse_addr(nlo,
+					NFTNL_OBJ_TUNNEL_IPV6_SRC);
+		}
+		if (nftnl_obj_is_set(nlo, NFTNL_OBJ_TUNNEL_IPV6_DST)) {
+			obj->tunnel.dst =
+				netlink_obj_tunnel_parse_addr(nlo,
+					NFTNL_OBJ_TUNNEL_IPV6_DST);
+		}
+		break;
 	}
 	obj->type = type;
 
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 53e669521efa..d3b64b641700 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -459,6 +459,7 @@ int nft_lex(void *, void *, void *);
 %token COUNTERS			"counters"
 %token QUOTAS			"quotas"
 %token LIMITS			"limits"
+%token TUNNELS			"tunnels"
 %token HELPERS			"helpers"
 
 %token LOG			"log"
@@ -589,7 +590,7 @@ int nft_lex(void *, void *, void *);
 %type <flowtable>		flowtable_block_alloc flowtable_block
 %destructor { flowtable_free($$); }	flowtable_block_alloc
 
-%type <obj>			obj_block_alloc counter_block quota_block ct_helper_block ct_timeout_block ct_expect_block limit_block secmark_block
+%type <obj>			obj_block_alloc counter_block quota_block ct_helper_block ct_timeout_block ct_expect_block tunnel_block limit_block secmark_block
 %destructor { obj_free($$); }	obj_block_alloc
 
 %type <list>			stmt_list
@@ -697,8 +698,8 @@ int nft_lex(void *, void *, void *);
 %type <expr>			and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr
 %destructor { expr_free($$); }	and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr
 
-%type <obj>			counter_obj quota_obj ct_obj_alloc limit_obj secmark_obj
-%destructor { obj_free($$); }	counter_obj quota_obj ct_obj_alloc limit_obj secmark_obj
+%type <obj>			counter_obj quota_obj ct_obj_alloc limit_obj tunnel_obj secmark_obj
+%destructor { obj_free($$); }	counter_obj quota_obj ct_obj_alloc limit_obj tunnel_obj secmark_obj
 
 %type <expr>			relational_expr
 %destructor { expr_free($$); }	relational_expr
@@ -1009,6 +1010,10 @@ add_cmd			:	TABLE		table_spec
 			{
 				$$ = cmd_alloc(CMD_ADD, CMD_OBJ_SECMARK, &$2, &@$, $3);
 			}
+			|	TUNNEL		obj_spec	tunnel_obj	'{' tunnel_block '}'	stmt_separator
+			{
+				$$ = cmd_alloc_obj_ct(CMD_ADD, CMD_OBJ_TUNNEL, &$2, &@$, $3);
+			}
 			;
 
 replace_cmd		:	RULE		ruleid_spec	rule
@@ -1102,6 +1107,10 @@ create_cmd		:	TABLE		table_spec
 			{
 				$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SECMARK, &$2, &@$, $3);
 			}
+			|	TUNNEL		obj_spec	tunnel_obj	'{' tunnel_block '}'	stmt_separator
+			{
+				$$ = cmd_alloc_obj_ct(CMD_CREATE, CMD_OBJ_TUNNEL, &$2, &@$, $3);
+			}
 			;
 
 insert_cmd		:	RULE		rule_position	rule
@@ -1589,6 +1598,15 @@ table_block		:	/* empty */	{ $$ = $<table>-1; }
 				list_add_tail(&$4->list, &$1->objs);
 				$$ = $1;
 			}
+			|	table_block	TUNNEL	obj_identifier  obj_block_alloc '{'     tunnel_block     '}' stmt_separator
+			{
+				$4->location = @3;
+				$4->type = NFT_OBJECT_TUNNEL;
+				handle_merge(&$4->handle, &$3);
+				handle_free(&$3);
+				list_add_tail(&$4->list, &$1->objs);
+				$$ = $1;
+			}
 			;
 
 chain_block_alloc	:	/* empty */
@@ -3698,6 +3716,32 @@ limit_obj		:	limit_config
 			}
 			;
 
+tunnel_config		:	TYPE	string		stmt_separator	{	$<obj>0->tunnel.type = $2;	}
+			|	ID	NUM		stmt_separator	{	$<obj>0->tunnel.id = $2;	}
+			|	IP	SADDR	expr	stmt_separator	{	$<obj>0->tunnel.src = $3;	}
+			|	IP	DADDR	expr	stmt_separator	{	$<obj>0->tunnel.dst = $3;	}
+			|	SPORT	NUM		stmt_separator	{	$<obj>0->tunnel.sport = $2;	}
+			|	DPORT	NUM		stmt_separator	{	$<obj>0->tunnel.dport = $2;	}
+			|	DSCP	NUM		stmt_separator	{	$<obj>0->tunnel.tos = $2 << 2;	}
+			|	TTL	NUM		stmt_separator	{	$<obj>0->tunnel.ttl = $2;	}
+			;
+
+tunnel_block		:	/* empty */	{ $$ = $<obj>-1; }
+			|       tunnel_block     common_block
+			|       tunnel_block     stmt_separator
+			|       tunnel_block     tunnel_config
+			{
+				$$ = $1;
+			}
+			;
+
+tunnel_obj		:
+			{
+				$$ = obj_alloc(&@$);
+				$$->type = NFT_OBJECT_TUNNEL;
+			}
+			;
+
 relational_expr		:	expr	/* implicit */	rhs_expr
 			{
 				$$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
diff --git a/src/rule.c b/src/rule.c
index 293606576044..b99786ba967a 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1442,6 +1442,7 @@ void cmd_free(struct cmd *cmd)
 		case CMD_OBJ_CT_TIMEOUT:
 		case CMD_OBJ_CT_EXPECT:
 		case CMD_OBJ_LIMIT:
+		case CMD_OBJ_TUNNEL:
 		case CMD_OBJ_SECMARK:
 			obj_free(cmd->object);
 			break;
@@ -1533,6 +1534,7 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
 	case CMD_OBJ_CT_TIMEOUT:
 	case CMD_OBJ_CT_EXPECT:
 	case CMD_OBJ_LIMIT:
+	case CMD_OBJ_TUNNEL:
 	case CMD_OBJ_SECMARK:
 		return mnl_nft_obj_add(ctx, cmd, flags);
 	case CMD_OBJ_FLOWTABLE:
@@ -1617,6 +1619,8 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
 		return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_CT_EXPECT);
 	case CMD_OBJ_LIMIT:
 		return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_LIMIT);
+	case CMD_OBJ_TUNNEL:
+		return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_TUNNEL);
 	case CMD_OBJ_SECMARK:
 		return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_SECMARK);
 	case CMD_OBJ_FLOWTABLE:
@@ -1903,6 +1907,18 @@ static void obj_print_data(const struct obj *obj,
 		nft_print(octx, "%s", opts->nl);
 		}
 		break;
+	case NFT_OBJECT_TUNNEL:
+		nft_print(octx, " %s {%s", obj->handle.obj.name, opts->nl);
+
+		nft_print(octx, "%s%sid %u%s",
+			  opts->tab, opts->tab, obj->tunnel.id, opts->nl);
+
+		if (obj->tunnel.dst) {
+			nft_print(octx, "%s%sip daddr ",
+				  opts->tab, opts->tab);
+			expr_print(obj->tunnel.dst, octx);
+		}
+		break;
 	default:
 		nft_print(octx, " unknown {%s", opts->nl);
 		break;
@@ -1914,6 +1930,7 @@ static const char * const obj_type_name_array[] = {
 	[NFT_OBJECT_QUOTA]	= "quota",
 	[NFT_OBJECT_CT_HELPER]	= "ct helper",
 	[NFT_OBJECT_LIMIT]	= "limit",
+	[NFT_OBJECT_TUNNEL]	= "tunnel",
 	[NFT_OBJECT_CT_TIMEOUT] = "ct timeout",
 	[NFT_OBJECT_SECMARK]	= "secmark",
 	[NFT_OBJECT_CT_EXPECT]	= "ct expectation",
@@ -1931,6 +1948,7 @@ static uint32_t obj_type_cmd_array[NFT_OBJECT_MAX + 1] = {
 	[NFT_OBJECT_QUOTA]	= CMD_OBJ_QUOTA,
 	[NFT_OBJECT_CT_HELPER]	= CMD_OBJ_CT_HELPER,
 	[NFT_OBJECT_LIMIT]	= CMD_OBJ_LIMIT,
+	[NFT_OBJECT_TUNNEL]	= CMD_OBJ_TUNNEL,
 	[NFT_OBJECT_CT_TIMEOUT] = CMD_OBJ_CT_TIMEOUT,
 	[NFT_OBJECT_SECMARK]	= CMD_OBJ_SECMARK,
 	[NFT_OBJECT_CT_EXPECT]	= CMD_OBJ_CT_EXPECT,
@@ -2297,6 +2315,9 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
 	case CMD_OBJ_LIMIT:
 	case CMD_OBJ_LIMITS:
 		return do_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
+	case CMD_OBJ_TUNNEL:
+	case CMD_OBJ_TUNNELS:
+		return do_list_obj(ctx, cmd, NFT_OBJECT_TUNNEL);
 	case CMD_OBJ_SECMARK:
 	case CMD_OBJ_SECMARKS:
 		return do_list_obj(ctx, cmd, NFT_OBJECT_SECMARK);
diff --git a/src/scanner.l b/src/scanner.l
index 4ed5f9241381..f8575638a47b 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -326,6 +326,9 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "quotas"		{ return QUOTAS; }
 "limits"		{ return LIMITS; }
 
+"tunnel"		{ return TUNNEL; }
+"tunnels"		{ return TUNNELS; }
+
 "log"			{ return LOG; }
 "prefix"		{ return PREFIX; }
 "group"			{ return GROUP; }
@@ -577,7 +580,6 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "reqid"			{ return REQID; }
 "spnum"			{ return SPNUM; }
 "transport"		{ return TRANSPORT; }
-"tunnel"		{ return TUNNEL; }
 
 "in"			{ return IN; }
 "out"			{ return OUT; }
-- 
2.11.0




[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux