* [PATCH nftables] src: add last statement
@ 2021-07-05 19:18 Pablo Neira Ayuso
0 siblings, 0 replies; only message in thread
From: Pablo Neira Ayuso @ 2021-07-05 19:18 UTC (permalink / raw)
To: netfilter-devel
This new statement allows you to know how long ago there was a matching
packet.
# nft list ruleset
table ip x {
chain y {
[...]
ip protocol icmp last used 49m54s884ms counter packets 1 bytes 64
}
}
if the statement never sees a packet, then the listing says:
ip protocol icmp last used never counter packets 0 bytes 0
Add tests/py in this patch too.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/parser.h | 1 +
include/statement.h | 10 ++++++++++
src/evaluate.c | 1 +
src/netlink_delinearize.c | 14 ++++++++++++++
src/netlink_linearize.c | 14 ++++++++++++++
src/parser_bison.y | 25 +++++++++++++++++++++++--
src/scanner.l | 9 ++++++++-
src/statement.c | 30 ++++++++++++++++++++++++++++++
tests/py/any/last.t | 13 +++++++++++++
tests/py/any/last.t.payload | 8 ++++++++
10 files changed, 122 insertions(+), 3 deletions(-)
create mode 100644 tests/py/any/last.t
create mode 100644 tests/py/any/last.t.payload
diff --git a/include/parser.h b/include/parser.h
index e8635b4c0feb..39128ae85d1a 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -36,6 +36,7 @@ enum startcond_type {
PARSER_SC_ETH,
PARSER_SC_IP,
PARSER_SC_IP6,
+ PARSER_SC_LAST,
PARSER_SC_LIMIT,
PARSER_SC_QUOTA,
PARSER_SC_SCTP,
diff --git a/include/statement.h b/include/statement.h
index 06221040fa0c..ce0aa9a63825 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -47,6 +47,13 @@ struct counter_stmt {
extern struct stmt *counter_stmt_alloc(const struct location *loc);
+struct last_stmt {
+ uint64_t used;
+ uint32_t set;
+};
+
+extern struct stmt *last_stmt_alloc(const struct location *loc);
+
struct exthdr_stmt {
struct expr *expr;
struct expr *val;
@@ -297,6 +304,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
* @STMT_MAP: map statement
* @STMT_SYNPROXY: synproxy statement
* @STMT_CHAIN: chain statement
+ * @STMT_LAST: last statement
*/
enum stmt_types {
STMT_INVALID,
@@ -326,6 +334,7 @@ enum stmt_types {
STMT_MAP,
STMT_SYNPROXY,
STMT_CHAIN,
+ STMT_LAST,
};
/**
@@ -375,6 +384,7 @@ struct stmt {
struct counter_stmt counter;
struct payload_stmt payload;
struct meta_stmt meta;
+ struct last_stmt last;
struct log_stmt log;
struct limit_stmt limit;
struct reject_stmt reject;
diff --git a/src/evaluate.c b/src/evaluate.c
index dbc773d164ed..585182d3599f 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -3707,6 +3707,7 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
switch (stmt->ops->type) {
case STMT_CONNLIMIT:
case STMT_COUNTER:
+ case STMT_LAST:
case STMT_LIMIT:
case STMT_QUOTA:
case STMT_NOTRACK:
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 71b69f622a76..744af3b064d7 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -923,6 +923,19 @@ static void netlink_parse_counter(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
}
+static void netlink_parse_last(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct stmt *stmt;
+
+ stmt = last_stmt_alloc(loc);
+ stmt->last.used = nftnl_expr_get_u64(nle, NFTNL_EXPR_LAST_MSECS);
+ stmt->last.set = nftnl_expr_get_u32(nle, NFTNL_EXPR_LAST_SET);
+
+ ctx->stmt = stmt;
+}
+
static void netlink_parse_log(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
@@ -1707,6 +1720,7 @@ static const struct expr_handler netlink_parsers[] = {
{ .name = "ct", .parse = netlink_parse_ct },
{ .name = "connlimit", .parse = netlink_parse_connlimit },
{ .name = "counter", .parse = netlink_parse_counter },
+ { .name = "last", .parse = netlink_parse_last },
{ .name = "log", .parse = netlink_parse_log },
{ .name = "limit", .parse = netlink_parse_limit },
{ .name = "range", .parse = netlink_parse_range },
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index b1f3feeeb4b7..e2122602dd33 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -924,6 +924,17 @@ static struct nftnl_expr *netlink_gen_quota_stmt(const struct stmt *stmt)
return nle;
}
+static struct nftnl_expr *netlink_gen_last_stmt(const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("last");
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LAST_SET, stmt->last.set);
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_LAST_MSECS, stmt->last.used);
+
+ return nle;
+}
+
struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt)
{
switch (stmt->ops->type) {
@@ -935,6 +946,8 @@ struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt)
return netlink_gen_limit_stmt(stmt);
case STMT_QUOTA:
return netlink_gen_quota_stmt(stmt);
+ case STMT_LAST:
+ return netlink_gen_last_stmt(stmt);
default:
BUG("unknown stateful statement type %s\n", stmt->ops->name);
}
@@ -1581,6 +1594,7 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
case STMT_COUNTER:
case STMT_LIMIT:
case STMT_QUOTA:
+ case STMT_LAST:
nle = netlink_gen_stmt_stateful(stmt);
nft_rule_add_expr(ctx, nle, &stmt->location);
break;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 872d7cdb92ad..c1fcedd7ecce 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -525,6 +525,9 @@ int nft_lex(void *, void *, void *);
%token BYTES "bytes"
%token AVGPKT "avgpkt"
+%token LAST "last"
+%token NEVER "never"
+
%token COUNTERS "counters"
%token QUOTAS "quotas"
%token LIMITS "limits"
@@ -676,8 +679,8 @@ int nft_lex(void *, void *, void *);
%destructor { stmt_list_free($$); xfree($$); } stmt_list stateful_stmt_list set_elem_stmt_list
%type <stmt> stmt match_stmt verdict_stmt set_elem_stmt
%destructor { stmt_free($$); } stmt match_stmt verdict_stmt set_elem_stmt
-%type <stmt> counter_stmt counter_stmt_alloc stateful_stmt
-%destructor { stmt_free($$); } counter_stmt counter_stmt_alloc stateful_stmt
+%type <stmt> counter_stmt counter_stmt_alloc stateful_stmt last_stmt
+%destructor { stmt_free($$); } counter_stmt counter_stmt_alloc stateful_stmt last_stmt
%type <stmt> payload_stmt
%destructor { stmt_free($$); } payload_stmt
%type <stmt> ct_stmt
@@ -915,6 +918,7 @@ opt_newline : NEWLINE
close_scope_arp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_ARP); };
close_scope_ct : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CT); };
close_scope_counter : { scanner_pop_start_cond(nft->scanner, PARSER_SC_COUNTER); };
+close_scope_last : { scanner_pop_start_cond(nft->scanner, PARSER_SC_LAST); };
close_scope_eth : { scanner_pop_start_cond(nft->scanner, PARSER_SC_ETH); };
close_scope_fib : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_FIB); };
close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); };
@@ -2790,6 +2794,7 @@ stateful_stmt : counter_stmt close_scope_counter
| limit_stmt
| quota_stmt
| connlimit_stmt
+ | last_stmt close_scope_last
;
stmt : verdict_stmt
@@ -2915,6 +2920,22 @@ counter_arg : PACKETS NUM
}
;
+last_stmt : LAST
+ {
+ $$ = last_stmt_alloc(&@$);
+ }
+ | LAST USED NEVER
+ {
+ $$ = last_stmt_alloc(&@$);
+ }
+ | LAST USED time_spec
+ {
+ $$ = last_stmt_alloc(&@$);
+ $$->last.used = $3;
+ $$->last.set = true;
+ }
+ ;
+
log_stmt : log_stmt_alloc
| log_stmt_alloc log_args
;
diff --git a/src/scanner.l b/src/scanner.l
index 6cc7778dd85e..1fc8143b4044 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -202,6 +202,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
%s SCANSTATE_ETH
%s SCANSTATE_IP
%s SCANSTATE_IP6
+%s SCANSTATE_LAST
%s SCANSTATE_LIMIT
%s SCANSTATE_QUOTA
%s SCANSTATE_SCTP
@@ -362,6 +363,11 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
<SCANSTATE_COUNTER,SCANSTATE_CT,SCANSTATE_LIMIT>"packets" { return PACKETS; }
<SCANSTATE_COUNTER,SCANSTATE_CT,SCANSTATE_LIMIT,SCANSTATE_QUOTA>"bytes" { return BYTES; }
+"last" { scanner_push_start_cond(yyscanner, SCANSTATE_LAST); return LAST; }
+<SCANSTATE_LAST>{
+ "never" { return NEVER; }
+}
+
"counters" { return COUNTERS; }
"quotas" { return QUOTAS; }
@@ -389,10 +395,11 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"quota" { scanner_push_start_cond(yyscanner, SCANSTATE_QUOTA); return QUOTA; }
<SCANSTATE_QUOTA>{
- "used" { return USED; }
"until" { return UNTIL; }
}
+<SCANSTATE_QUOTA,SCANSTATE_LAST>"used" { return USED; }
+
"second" { return SECOND; }
"minute" { return MINUTE; }
"hour" { return HOUR; }
diff --git a/src/statement.c b/src/statement.c
index dfd275104c59..b3e53451f5c7 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -248,6 +248,36 @@ struct stmt *counter_stmt_alloc(const struct location *loc)
return stmt;
}
+static void last_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "last");
+
+ if (nft_output_stateless(octx))
+ return;
+
+ nft_print(octx, " used ");
+
+ if (stmt->last.set)
+ time_print(stmt->last.used, octx);
+ else
+ nft_print(octx, "never");
+}
+
+static const struct stmt_ops last_stmt_ops = {
+ .type = STMT_LAST,
+ .name = "last",
+ .print = last_stmt_print,
+};
+
+struct stmt *last_stmt_alloc(const struct location *loc)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &last_stmt_ops);
+ stmt->flags |= STMT_F_STATEFUL;
+ return stmt;
+}
+
static const char *objref_type[NFT_OBJECT_MAX + 1] = {
[NFT_OBJECT_COUNTER] = "counter",
[NFT_OBJECT_QUOTA] = "quota",
diff --git a/tests/py/any/last.t b/tests/py/any/last.t
new file mode 100644
index 000000000000..5c530461479f
--- /dev/null
+++ b/tests/py/any/last.t
@@ -0,0 +1,13 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+*arp;test-arp;input
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress
+
+last;ok
+last used 300s;ok;last
+last used foo;fail
diff --git a/tests/py/any/last.t.payload b/tests/py/any/last.t.payload
new file mode 100644
index 000000000000..ed47d0f355eb
--- /dev/null
+++ b/tests/py/any/last.t.payload
@@ -0,0 +1,8 @@
+# last
+ip
+ [ last never ]
+
+# last used 300s
+ip
+ [ last 300000 ]
+
--
2.20.1
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2021-07-05 19:18 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-05 19:18 [PATCH nftables] src: add last statement 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).