Netfilter-Devel Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH nft v2] src: Support maps as left side expressions
@ 2019-07-30 12:28 Brett Mastbergen
  2019-08-08 11:16 ` Pablo Neira Ayuso
  0 siblings, 1 reply; 3+ messages in thread
From: Brett Mastbergen @ 2019-07-30 12:28 UTC (permalink / raw)
  To: netfilter-devel

This change allows map expressions on the left side of comparisons:

nft add rule foo bar ip saddr map @map_a == 22 counter

It also allows map expressions as the left side expression of other
map expressions:

nft add rule foo bar ip saddr map @map_a map @map_b == 22 counter

To accomplish this, some additional context needs to be set during
evaluation and delinearization.  A tweak is also make to the parser
logic to allow map expressions as the left hand expression to other
map expressions.

By allowing maps as left side comparison expressions one can map
information in the packet to some arbitrary piece of data and use
the equality (or inequality) to make some decision about the traffic,
unlike today where the result of a map lookup is only usable as the
right side of a statement (like dnat or snat) that actually uses the
value as input.

v2: Add testcases

Signed-off-by: Brett Mastbergen <bmastbergen@untangle.com>
---
 src/evaluate.c                                     |  2 +-
 src/expression.c                                   | 12 +++++++++++-
 src/netlink_delinearize.c                          |  2 ++
 src/parser_bison.y                                 | 10 +++++++---
 .../shell/testcases/maps/dumps/left_side_map_0.nft | 10 ++++++++++
 tests/shell/testcases/maps/dumps/map_to_map_0.nft  | 14 ++++++++++++++
 tests/shell/testcases/maps/left_side_map_0         |  8 ++++++++
 tests/shell/testcases/maps/map_to_map_0            |  9 +++++++++
 8 files changed, 62 insertions(+), 5 deletions(-)
 create mode 100644 tests/shell/testcases/maps/dumps/left_side_map_0.nft
 create mode 100644 tests/shell/testcases/maps/dumps/map_to_map_0.nft
 create mode 100755 tests/shell/testcases/maps/left_side_map_0
 create mode 100755 tests/shell/testcases/maps/map_to_map_0

diff --git a/src/evaluate.c b/src/evaluate.c
index 48c65cd2..59538f27 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1385,6 +1385,7 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
 		    !set_is_datamap(map->mappings->set->flags))
 			return expr_error(ctx->msgs, map->mappings,
 					  "Expression is not a map");
+		expr_set_context(&ctx->ectx, map->mappings->set->datatype, map->mappings->set->datalen);
 		break;
 	default:
 		BUG("invalid mapping expression %s\n",
@@ -1399,7 +1400,6 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
 					 map->map->dtype->desc);
 
 	datatype_set(map, map->mappings->set->datatype);
-	map->flags |= EXPR_F_CONSTANT;
 
 	/* Data for range lookups needs to be in big endian order */
 	if (map->mappings->set->flags & NFT_SET_INTERVAL &&
diff --git a/src/expression.c b/src/expression.c
index cb49e0b7..e5979394 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1067,8 +1067,18 @@ static const struct expr_ops set_ref_expr_ops = {
 struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set)
 {
 	struct expr *expr;
+	const struct datatype *dtype;
+	unsigned int len;
 
-	expr = expr_alloc(loc, EXPR_SET_REF, set->key->dtype, 0, 0);
+	if (set->flags & NFT_SET_MAP) {
+		dtype = set->datatype;
+		len = set->datalen;
+	} else {
+		dtype = set->key->dtype;
+		len = set->key->len;
+	}
+
+	expr = expr_alloc(loc, EXPR_SET_REF, dtype, 0, len);
 	expr->set = set_get(set);
 	expr->flags |= EXPR_F_CONSTANT;
 	return expr;
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index fc2574b1..b70433f0 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -341,6 +341,8 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
 	if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOOKUP_DREG)) {
 		dreg = netlink_parse_register(nle, NFTNL_EXPR_LOOKUP_DREG);
 		expr = map_expr_alloc(loc, left, right);
+		expr_set_type(expr, right->dtype, right->byteorder);
+		expr->len = right->len;
 		if (dreg != NFT_REG_VERDICT)
 			return netlink_set_register(ctx, dreg, expr);
 	} else {
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 53e66952..9b998d65 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -668,8 +668,8 @@ int nft_lex(void *, void *, void *);
 %type <expr>			concat_expr
 %destructor { expr_free($$); }	concat_expr
 
-%type <expr>			map_expr
-%destructor { expr_free($$); }	map_expr
+%type <expr>			map_expr map_lhs_expr
+%destructor { expr_free($$); }	map_expr map_lhs_expr
 
 %type <expr>			verdict_map_stmt
 %destructor { expr_free($$); }	verdict_map_stmt
@@ -3378,7 +3378,11 @@ multiton_rhs_expr	:	prefix_rhs_expr
 			|	wildcard_expr
 			;
 
-map_expr		:	concat_expr	MAP	rhs_expr
+map_lhs_expr		:	concat_expr
+			|	map_expr
+			;
+
+map_expr		:	map_lhs_expr	MAP	rhs_expr
 			{
 				$$ = map_expr_alloc(&@$, $1, $3);
 			}
diff --git a/tests/shell/testcases/maps/dumps/left_side_map_0.nft b/tests/shell/testcases/maps/dumps/left_side_map_0.nft
new file mode 100644
index 00000000..b93948fc
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/left_side_map_0.nft
@@ -0,0 +1,10 @@
+table ip x {
+	map y {
+		type ipv4_addr : inet_service
+	}
+
+	chain z {
+		type filter hook output priority filter; policy accept;
+		ip saddr map @y 22 counter packets 0 bytes 0
+	}
+}
diff --git a/tests/shell/testcases/maps/dumps/map_to_map_0.nft b/tests/shell/testcases/maps/dumps/map_to_map_0.nft
new file mode 100644
index 00000000..fd7339f9
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/map_to_map_0.nft
@@ -0,0 +1,14 @@
+table ip x {
+	map y {
+		type ipv4_addr : mark
+	}
+
+	map yy {
+		type mark : inet_service
+	}
+
+	chain z {
+		type filter hook output priority filter; policy accept;
+		ip saddr map @y map @yy 22 counter packets 0 bytes 0
+	}
+}
diff --git a/tests/shell/testcases/maps/left_side_map_0 b/tests/shell/testcases/maps/left_side_map_0
new file mode 100755
index 00000000..93c721b7
--- /dev/null
+++ b/tests/shell/testcases/maps/left_side_map_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table x
+$NFT add map x y { type ipv4_addr : inet_service\; }
+$NFT add chain ip x z { type filter hook output priority 0 \; }
+$NFT add rule x z ip saddr map @y 22 counter
diff --git a/tests/shell/testcases/maps/map_to_map_0 b/tests/shell/testcases/maps/map_to_map_0
new file mode 100755
index 00000000..95a45f62
--- /dev/null
+++ b/tests/shell/testcases/maps/map_to_map_0
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table x
+$NFT add map x y { type ipv4_addr : mark\; }
+$NFT add map x yy { type mark : inet_service\; }
+$NFT add chain ip x z { type filter hook output priority 0 \; }
+$NFT add rule x z ip saddr map @y map@yy 22 counter
-- 
2.17.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH nft v2] src: Support maps as left side expressions
  2019-07-30 12:28 [PATCH nft v2] src: Support maps as left side expressions Brett Mastbergen
@ 2019-08-08 11:16 ` Pablo Neira Ayuso
  2019-08-09 13:56   ` Brett Mastbergen
  0 siblings, 1 reply; 3+ messages in thread
From: Pablo Neira Ayuso @ 2019-08-08 11:16 UTC (permalink / raw)
  To: Brett Mastbergen; +Cc: netfilter-devel

Hi brett,

On Tue, Jul 30, 2019 at 08:28:18AM -0400, Brett Mastbergen wrote:
> This change allows map expressions on the left side of comparisons:
> 
> nft add rule foo bar ip saddr map @map_a == 22 counter
> 
> It also allows map expressions as the left side expression of other
> map expressions:
> 
> nft add rule foo bar ip saddr map @map_a map @map_b == 22 counter

This is an interesting usage of the maps from the left-hand side of an
expression.

I have a fundamental question, that is, how this will be used from
rulesets? My impression is that this will result in many rules, e.g.

        ip saddr map @map_a map @map_b == 22 accept
        ip saddr map @map_a map @map_b == 21 drop
        ip saddr map @map_a map @map_b == 20 jump chain_0
        ...

This means that we need one rule per map lookup.

I think this feature will be more useful if this can be combined with
verdict maps, so the right hand side could be used to look up for an
action.

Thanks.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH nft v2] src: Support maps as left side expressions
  2019-08-08 11:16 ` Pablo Neira Ayuso
@ 2019-08-09 13:56   ` Brett Mastbergen
  0 siblings, 0 replies; 3+ messages in thread
From: Brett Mastbergen @ 2019-08-09 13:56 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

On 08-08-19, Pablo Neira Ayuso wrote:
> Hi brett,
> 
> On Tue, Jul 30, 2019 at 08:28:18AM -0400, Brett Mastbergen wrote:
> > This change allows map expressions on the left side of comparisons:
> > 
> > nft add rule foo bar ip saddr map @map_a == 22 counter
> > 
> > It also allows map expressions as the left side expression of other
> > map expressions:
> > 
> > nft add rule foo bar ip saddr map @map_a map @map_b == 22 counter
> 
> This is an interesting usage of the maps from the left-hand side of an
> expression.
> 
> I have a fundamental question, that is, how this will be used from
> rulesets? My impression is that this will result in many rules, e.g.
> 
>         ip saddr map @map_a map @map_b == 22 accept
>         ip saddr map @map_a map @map_b == 21 drop
>         ip saddr map @map_a map @map_b == 20 jump chain_0
>         ...
> 
> This means that we need one rule per map lookup.
> 
> I think this feature will be more useful if this can be combined with
> verdict maps, so the right hand side could be used to look up for an
> action.
>

Thats a good point.  I bet a map expression could feed into a verdict
map without too much trouble.  I'll take a look.

> Thanks.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, back to index

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-30 12:28 [PATCH nft v2] src: Support maps as left side expressions Brett Mastbergen
2019-08-08 11:16 ` Pablo Neira Ayuso
2019-08-09 13:56   ` Brett Mastbergen

Netfilter-Devel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/netfilter-devel/0 netfilter-devel/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 netfilter-devel netfilter-devel/ https://lore.kernel.org/netfilter-devel \
		netfilter-devel@vger.kernel.org netfilter-devel@archiver.kernel.org
	public-inbox-index netfilter-devel


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.netfilter-devel


AGPL code for this site: git clone https://public-inbox.org/ public-inbox