[PATCH nft 1/2] fib: allow to check if route exists in maps

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

 



f686a17eafa0 ("fib: Support existence check") adds EXPR_F_BOOLEAN as a
workaround to infer from the rhs of the relational expression if the fib
lookup wants to check for a specific output interface or, instead,
simply check for existence. This, however, does not work with maps.

The NFT_FIB_F_PRESENT flag can be used both with NFT_FIB_RESULT_OIF and
NFT_FIB_RESULT_OFINAME, my understanding is that they serve the same
purpose which is to check if a route exists, so they are redundant.

Add a 'check' fib result to check for routes while still keeping the
inference workaround for backward compatibility, but prefer the new
syntax in the listing.

Update man nft(8) and tests/py.

Fixes: f686a17eafa0 ("fib: Support existence check")
Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
---
 doc/data-types.txt          |  2 +-
 doc/primary-expression.txt  |  5 ++++-
 include/fib.h               |  2 +-
 src/fib.c                   | 12 ++++++++++--
 src/json.c                  |  2 +-
 src/parser_bison.y          | 21 +++++++++++++++------
 src/scanner.l               |  4 ++++
 tests/py/inet/fib.t         |  6 ++++--
 tests/py/inet/fib.t.payload |  8 +++++++-
 9 files changed, 47 insertions(+), 15 deletions(-)

diff --git a/doc/data-types.txt b/doc/data-types.txt
index 6c0e2f9420fe..46b0867cb5a4 100644
--- a/doc/data-types.txt
+++ b/doc/data-types.txt
@@ -166,7 +166,7 @@ Check TCP option header existence.
 .Boolean specification
 ----------------------
 # match if route exists
-filter input fib daddr . iif oif exists
+filter input fib daddr . iif check exists
 
 # match only non-fragmented packets in IPv6 traffic
 filter input exthdr frag missing
diff --git a/doc/primary-expression.txt b/doc/primary-expression.txt
index 40aca3d3fcf6..ea231fe57f7b 100644
--- a/doc/primary-expression.txt
+++ b/doc/primary-expression.txt
@@ -312,7 +312,7 @@ FIB EXPRESSIONS
 [verse]
 *fib* 'FIB_TUPLE' 'FIB_RESULT'
 'FIB_TUPLE' := { *saddr* | *daddr*} [ *.* { *iif* | *oif* } *.* *mark* ]
-'FIB_RESULT'  := { *oif* | *oifname* | *type* }
+'FIB_RESULT'  := { *oif* | *oifname* | *check* | *type* }
 
 
 A fib expression queries the fib (forwarding information base) to obtain information
@@ -355,6 +355,9 @@ address types can be shown with *nft* *describe* *fib_addrtype*.
 |oif|
 Output interface index|
 iface_index
+|check|
+Output interface check|
+boolean
 |oifname|
 Output interface name|
 ifname
diff --git a/include/fib.h b/include/fib.h
index 67edccfea0d5..07bb2210d223 100644
--- a/include/fib.h
+++ b/include/fib.h
@@ -3,7 +3,7 @@
 
 #include <linux/netfilter/nf_tables.h>
 
-extern const char *fib_result_str(enum nft_fib_result result);
+extern const char *fib_result_str(const struct expr *expr);
 extern struct expr *fib_expr_alloc(const struct location *loc,
 				   unsigned int flags,
 				   unsigned int result);
diff --git a/src/fib.c b/src/fib.c
index 5a7c1170b240..e28c52243f42 100644
--- a/src/fib.c
+++ b/src/fib.c
@@ -53,8 +53,16 @@ const struct datatype fib_addr_type = {
 	.sym_tbl	= &addrtype_tbl,
 };
 
-const char *fib_result_str(enum nft_fib_result result)
+const char *fib_result_str(const struct expr *expr)
 {
+	enum nft_fib_result result = expr->fib.result;
+	uint32_t flags = expr->fib.flags;
+
+	/* Exception: check if route exists. */
+	if (result == NFT_FIB_RESULT_OIF &&
+	    flags & NFTA_FIB_F_PRESENT)
+		return "check";
+
 	if (result <= NFT_FIB_RESULT_MAX)
 		return fib_result[result];
 
@@ -87,7 +95,7 @@ static void fib_expr_print(const struct expr *expr, struct output_ctx *octx)
 	if (flags)
 		nft_print(octx, "0x%x", flags);
 
-	nft_print(octx, " %s", fib_result_str(expr->fib.result));
+	nft_print(octx, " %s", fib_result_str(expr));
 }
 
 static bool fib_expr_cmp(const struct expr *e1, const struct expr *e2)
diff --git a/src/json.c b/src/json.c
index 5bd5daf3f7fa..f0430776851c 100644
--- a/src/json.c
+++ b/src/json.c
@@ -938,7 +938,7 @@ json_t *fib_expr_json(const struct expr *expr, struct output_ctx *octx)
 	unsigned int flags = expr->fib.flags & ~NFTA_FIB_F_PRESENT;
 	json_t *root;
 
-	root = nft_json_pack("{s:s}", "result", fib_result_str(expr->fib.result));
+	root = nft_json_pack("{s:s}", "result", fib_result_str(expr));
 
 	if (flags) {
 		json_t *tmp = json_array();
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 9278b67a2931..e1afbbb6e56e 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -284,6 +284,7 @@ int nft_lex(void *, void *, void *);
 %token UNDEFINE			"undefine"
 
 %token FIB			"fib"
+%token CHECK			"check"
 
 %token SOCKET			"socket"
 %token TRANSPARENT		"transparent"
@@ -4360,30 +4361,38 @@ primary_expr		:	symbol_expr			{ $$ = $1; }
 
 fib_expr		:	FIB	fib_tuple	fib_result	close_scope_fib
 			{
-				if (($2 & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) == 0) {
+				uint32_t flags = $2, result = $3;
+
+				if (result == __NFT_FIB_RESULT_MAX) {
+					result = NFT_FIB_RESULT_OIF;
+					flags |= NFTA_FIB_F_PRESENT;
+				}
+
+				if ((flags & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) == 0) {
 					erec_queue(error(&@2, "fib: need either saddr or daddr"), state->msgs);
 					YYERROR;
 				}
 
-				if (($2 & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) ==
-					  (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) {
+				if ((flags & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) ==
+					     (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) {
 					erec_queue(error(&@2, "fib: saddr and daddr are mutually exclusive"), state->msgs);
 					YYERROR;
 				}
 
-				if (($2 & (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) ==
-					  (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) {
+				if ((flags & (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) ==
+					     (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) {
 					erec_queue(error(&@2, "fib: iif and oif are mutually exclusive"), state->msgs);
 					YYERROR;
 				}
 
-				$$ = fib_expr_alloc(&@$, $2, $3);
+				$$ = fib_expr_alloc(&@$, flags, result);
 			}
 			;
 
 fib_result		:	OIF	{ $$ =NFT_FIB_RESULT_OIF; }
 			|	OIFNAME { $$ =NFT_FIB_RESULT_OIFNAME; }
 			|	TYPE	close_scope_type	{ $$ =NFT_FIB_RESULT_ADDRTYPE; }
+			|	CHECK	{ $$ = __NFT_FIB_RESULT_MAX; }	/* actually, NFT_FIB_F_PRESENT. */
 			;
 
 fib_flag		:       SADDR	{ $$ = NFTA_FIB_F_SADDR; }
diff --git a/src/scanner.l b/src/scanner.l
index 4787cc12f993..b69d8e81fd8c 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -795,6 +795,10 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 
 "fib"			{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_FIB); return FIB; }
 
+<SCANSTATE_EXPR_FIB>{
+	"check"		{ return CHECK; }
+}
+
 "osf"			{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_OSF); return OSF; }
 
 "synproxy"		{ scanner_push_start_cond(yyscanner, SCANSTATE_STMT_SYNPROXY); return SYNPROXY; }
diff --git a/tests/py/inet/fib.t b/tests/py/inet/fib.t
index dbe45d95b4cf..f9c03b3ad2be 100644
--- a/tests/py/inet/fib.t
+++ b/tests/py/inet/fib.t
@@ -13,5 +13,7 @@ fib daddr . iif type local;ok
 fib daddr . iif type vmap { blackhole : drop, prohibit : drop, unicast : accept };ok
 fib daddr . oif type local;fail
 
-fib daddr oif exists;ok
-fib daddr oif missing;ok
+fib daddr check missing;ok
+fib daddr oif exists;ok;fib daddr check exists
+
+fib daddr check vmap { missing : drop, exists : accept };ok
diff --git a/tests/py/inet/fib.t.payload b/tests/py/inet/fib.t.payload
index 050857d96994..e09a260cc41e 100644
--- a/tests/py/inet/fib.t.payload
+++ b/tests/py/inet/fib.t.payload
@@ -26,7 +26,13 @@ ip test-ip prerouting
   [ fib daddr oif present => reg 1 ]
   [ cmp eq reg 1 0x00000001 ]
 
-# fib daddr oif missing
+# fib daddr check missing
 ip test-ip prerouting
   [ fib daddr oif present => reg 1 ]
   [ cmp eq reg 1 0x00000000 ]
+
+# fib daddr check vmap { missing : drop, exists : accept }
+        element 00000000  : drop 0 [end]        element 00000001  : accept 0 [end]
+ip test-ip prerouting
+  [ fib daddr oif present => reg 1 ]
+  [ lookup reg 1 set __map%d dreg 0 ]
-- 
2.30.2





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

  Powered by Linux