diff options
| author | Pablo Neira Ayuso <pablo@netfilter.org> | 2025-06-24 18:11:06 +0200 |
|---|---|---|
| committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2025-06-27 00:39:05 +0200 |
| commit | f4b646032acff4d743ad4f734aaca68e9264bdbb (patch) | |
| tree | 9cd4d2172b7b61a7cc17c33b51a8a6d3e6baea34 /src | |
| parent | 646acfaceb1f550c982c31ba6e60996b0bb012d7 (diff) | |
fib: allow to check if route exists in maps
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>
Diffstat (limited to 'src')
| -rw-r--r-- | src/fib.c | 12 | ||||
| -rw-r--r-- | src/json.c | 2 | ||||
| -rw-r--r-- | src/parser_bison.y | 21 | ||||
| -rw-r--r-- | src/parser_json.c | 12 | ||||
| -rw-r--r-- | src/scanner.l | 4 |
5 files changed, 40 insertions, 11 deletions
@@ -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) @@ -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 9278b67a..e1afbbb6 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/parser_json.c b/src/parser_json.c index 3195d529..ce944740 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -1157,6 +1157,7 @@ static struct expr *json_parse_fib_expr(struct json_ctx *ctx, [NFT_FIB_RESULT_OIF] = "oif", [NFT_FIB_RESULT_OIFNAME] = "oifname", [NFT_FIB_RESULT_ADDRTYPE] = "type", + [__NFT_FIB_RESULT_MAX] = "check", /* Actually, NFT_FIB_F_PRESENT. */ }; enum nft_fib_result resultval = NFT_FIB_RESULT_UNSPEC; const char *result; @@ -1172,12 +1173,19 @@ static struct expr *json_parse_fib_expr(struct json_ctx *ctx, break; } } - if (resultval == NFT_FIB_RESULT_UNSPEC) { + switch (resultval) { + case NFT_FIB_RESULT_UNSPEC: json_error(ctx, "Invalid fib result '%s'.", result); return NULL; + case __NFT_FIB_RESULT_MAX: + resultval = NFT_FIB_RESULT_OIF; + flagval = NFTA_FIB_F_PRESENT; + break; + default: + break; } - flagval = parse_flags_array(ctx, root, "flags", fib_flag_parse); + flagval |= parse_flags_array(ctx, root, "flags", fib_flag_parse); if (flagval < 0) return NULL; diff --git a/src/scanner.l b/src/scanner.l index 4787cc12..b69d8e81 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; } |
