netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH nft 0/2] fib expression fixes
@ 2025-06-24 16:37 Pablo Neira Ayuso
  2025-06-24 16:38 ` [PATCH nft 1/2] fib: allow to check if route exists in maps Pablo Neira Ayuso
  2025-06-24 16:38 ` [PATCH nft 2/2] fib: allow to use it in set statements Pablo Neira Ayuso
  0 siblings, 2 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2025-06-24 16:37 UTC (permalink / raw)
  To: netfilter-devel; +Cc: fw, phil

Hi,

This small series contains two fib expression fixes:

1) Allow to use fib expression in maps when check for presence, eg.

      fib daddr check vmap { missing : drop, exists : accept }

   NOTE: it should be possible to use this trick instead:

      fib daddr oif vmap { 0 : drop, * : accept }

   but the catch-all element did not exist at the time the fib
   expression was added, so this does not work in older kernels.

2) Allow to use fib expression in set statement.

   NOTE: There are two more expressions that are missing there too:
         exthdr_expr and xfrm_expr.

Pablo Neira Ayuso (2):
  fib: allow to check if route exists in maps
  fib: allow to use it in set statements

 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          | 22 ++++++++++++++++------
 src/scanner.l               |  4 ++++
 tests/py/inet/fib.t         |  8 ++++++--
 tests/py/inet/fib.t.payload | 16 +++++++++++++++-
 9 files changed, 58 insertions(+), 15 deletions(-)

-- 
2.30.2


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

* [PATCH nft 1/2] fib: allow to check if route exists in maps
  2025-06-24 16:37 [PATCH nft 0/2] fib expression fixes Pablo Neira Ayuso
@ 2025-06-24 16:38 ` Pablo Neira Ayuso
  2025-06-24 16:38 ` [PATCH nft 2/2] fib: allow to use it in set statements Pablo Neira Ayuso
  1 sibling, 0 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2025-06-24 16:38 UTC (permalink / raw)
  To: netfilter-devel; +Cc: fw, phil

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@netfilter.org>
---
 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


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

* [PATCH nft 2/2] fib: allow to use it in set statements
  2025-06-24 16:37 [PATCH nft 0/2] fib expression fixes Pablo Neira Ayuso
  2025-06-24 16:38 ` [PATCH nft 1/2] fib: allow to check if route exists in maps Pablo Neira Ayuso
@ 2025-06-24 16:38 ` Pablo Neira Ayuso
  1 sibling, 0 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2025-06-24 16:38 UTC (permalink / raw)
  To: netfilter-devel; +Cc: fw, phil

Allow to use fib expression in set statements, eg.

 meta mark set ip saddr . fib daddr check map { 1.2.3.4 . exists : 0x00000001 }

Fixes: 4a75ed32132d ("src: add fib expression")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/parser_bison.y          | 1 +
 tests/py/inet/fib.t         | 2 ++
 tests/py/inet/fib.t.payload | 8 ++++++++
 3 files changed, 11 insertions(+)

diff --git a/src/parser_bison.y b/src/parser_bison.y
index e1afbbb6e56e..f9cc909836bc 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -3873,6 +3873,7 @@ primary_stmt_expr	:	symbol_expr			{ $$ = $1; }
 			|	payload_expr			{ $$ = $1; }
 			|	keyword_expr			{ $$ = $1; }
 			|	socket_expr			{ $$ = $1; }
+			|	fib_expr			{ $$ = $1; }
 			|	osf_expr			{ $$ = $1; }
 			|	'('	basic_stmt_expr	')'	{ $$ = $2; }
 			;
diff --git a/tests/py/inet/fib.t b/tests/py/inet/fib.t
index f9c03b3ad2be..60b77a4ac00a 100644
--- a/tests/py/inet/fib.t
+++ b/tests/py/inet/fib.t
@@ -17,3 +17,5 @@ fib daddr check missing;ok
 fib daddr oif exists;ok;fib daddr check exists
 
 fib daddr check vmap { missing : drop, exists : accept };ok
+
+meta mark set fib daddr check . ct mark map { exists . 0x00000000 : 0x00000001 };ok
diff --git a/tests/py/inet/fib.t.payload b/tests/py/inet/fib.t.payload
index e09a260cc41e..02d92b57a477 100644
--- a/tests/py/inet/fib.t.payload
+++ b/tests/py/inet/fib.t.payload
@@ -36,3 +36,11 @@ ip test-ip prerouting
 ip test-ip prerouting
   [ fib daddr oif present => reg 1 ]
   [ lookup reg 1 set __map%d dreg 0 ]
+
+# meta mark set fib daddr check . ct mark map { exists . 0x00000000 : 0x00000001 }
+        element 00000001 00000000  : 00000001 0 [end]
+ip test-ip prerouting
+  [ fib daddr oif present => reg 1 ]
+  [ ct load mark => reg 9 ]
+  [ lookup reg 1 set __map%d dreg 1 ]
+  [ meta set mark with reg 1 ]
-- 
2.30.2


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

end of thread, other threads:[~2025-06-24 16:38 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-24 16:37 [PATCH nft 0/2] fib expression fixes Pablo Neira Ayuso
2025-06-24 16:38 ` [PATCH nft 1/2] fib: allow to check if route exists in maps Pablo Neira Ayuso
2025-06-24 16:38 ` [PATCH nft 2/2] fib: allow to use it in set statements Pablo Neira Ayuso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).