summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2022-10-14 23:19:22 +0200
committerPhil Sutter <phil@nwl.cc>2023-01-18 14:58:48 +0100
commit1694df2de79f39c5037f82601e02226022b2e38f (patch)
tree57c6b99a1c7de8a414b5693e86cd6cf36816fd42
parentce04d25b4a116ef04f27d0b71994f61a24114d6d (diff)
Implement 'reset rule' and 'reset rules' commands
Reset rule counters and quotas in kernel, i.e. without having to reload them. Requires respective kernel patch to support NFT_MSG_GETRULE_RESET message type. Signed-off-by: Phil Sutter <phil@nwl.cc>
-rw-r--r--doc/libnftables-json.adoc2
-rw-r--r--doc/nft.txt6
-rw-r--r--include/cache.h7
-rw-r--r--include/linux/netfilter/nf_tables.h1
-rw-r--r--include/mnl.h4
-rw-r--r--include/netlink.h3
-rw-r--r--include/rule.h1
-rw-r--r--src/cache.c43
-rw-r--r--src/evaluate.c2
-rw-r--r--src/json.c1
-rw-r--r--src/mnl.c18
-rw-r--r--src/netlink.c49
-rw-r--r--src/parser_bison.y16
-rw-r--r--src/parser_json.c35
-rw-r--r--src/rule.c10
-rw-r--r--src/scanner.l1
-rwxr-xr-xtests/shell/testcases/rule_management/0011reset_0168
-rw-r--r--tests/shell/testcases/rule_management/dumps/0011reset_0.nft31
18 files changed, 384 insertions, 14 deletions
diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc
index d985149a..f4aea36e 100644
--- a/doc/libnftables-json.adoc
+++ b/doc/libnftables-json.adoc
@@ -175,7 +175,7 @@ kind, optionally filtered by *family* and for some, also *table*.
____
*{ "reset":* 'RESET_OBJECT' *}*
-'RESET_OBJECT' := 'COUNTER' | 'COUNTERS' | 'QUOTA' | 'QUOTAS'
+'RESET_OBJECT' := 'COUNTER' | 'COUNTERS' | 'QUOTA' | 'QUOTAS' | 'RULE' | 'RULES'
____
Reset state in suitable objects, i.e. zero their internal counter.
diff --git a/doc/nft.txt b/doc/nft.txt
index eb8df1d9..18c18468 100644
--- a/doc/nft.txt
+++ b/doc/nft.txt
@@ -481,7 +481,10 @@ RULES
[verse]
{*add* | *insert*} *rule* ['family'] 'table' 'chain' [*handle* 'handle' | *index* 'index'] 'statement' ... [*comment* 'comment']
*replace rule* ['family'] 'table' 'chain' *handle* 'handle' 'statement' ... [*comment* 'comment']
-*delete rule* ['family'] 'table' 'chain' *handle* 'handle'
+{*delete* | *reset*} *rule* ['family'] 'table' 'chain' *handle* 'handle'
+*reset rules* ['family']
+*reset rules* *table* ['family'] 'table'
+*reset rules* *chain* ['family'] 'table' ['chain']
Rules are added to chains in the given table. If the family is not specified, the
ip family is used. Rules are constructed from two kinds of components according
@@ -509,6 +512,7 @@ case the rule is inserted after the specified rule.
beginning of the chain or before the specified rule.
*replace*:: Similar to *add*, but the rule replaces the specified rule.
*delete*:: Delete the specified rule.
+*reset*:: Reset rule-contained state, i.e. counter and quota statement values.
.*add a rule to ip table output chain*
-------------
diff --git a/include/cache.h b/include/cache.h
index 575381ef..5bf78fe0 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -3,6 +3,8 @@
#include <string.h>
+struct handle;
+
enum cache_level_bits {
NFT_CACHE_TABLE_BIT = (1 << 0),
NFT_CACHE_CHAIN_BIT = (1 << 1),
@@ -55,6 +57,7 @@ struct nft_cache_filter {
const char *chain;
const char *set;
const char *ft;
+ uint64_t rule_handle;
} list;
struct {
@@ -138,4 +141,8 @@ struct nft_cache {
void nft_chain_cache_update(struct netlink_ctx *ctx, struct table *table,
const char *chain);
+int rule_cache_dump(struct netlink_ctx *ctx, const struct handle *h,
+ const struct nft_cache_filter *filter,
+ bool dump, bool reset);
+
#endif /* _NFT_CACHE_H_ */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index e4b739d5..3d045030 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -124,6 +124,7 @@ enum nf_tables_msg_types {
NFT_MSG_NEWFLOWTABLE,
NFT_MSG_GETFLOWTABLE,
NFT_MSG_DELFLOWTABLE,
+ NFT_MSG_GETRULE_RESET,
NFT_MSG_MAX,
};
diff --git a/include/mnl.h b/include/mnl.h
index 8e0a7e3f..c0676691 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -34,7 +34,9 @@ int mnl_nft_rule_del(struct netlink_ctx *ctx, struct cmd *cmd);
int mnl_nft_rule_replace(struct netlink_ctx *ctx, struct cmd *cmd);
struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
- const char *table, const char *chain);
+ const char *table, const char *chain,
+ uint64_t rule_handle,
+ bool dump, bool reset);
int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
diff --git a/include/netlink.h b/include/netlink.h
index 5a7f6a1e..0d97f71c 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -183,6 +183,9 @@ extern int netlink_list_flowtables(struct netlink_ctx *ctx,
extern struct flowtable *netlink_delinearize_flowtable(struct netlink_ctx *ctx,
struct nftnl_flowtable *nlo);
+extern int netlink_reset_rules(struct netlink_ctx *ctx, const struct cmd *cmd,
+ bool dump);
+
extern void netlink_dump_chain(const struct nftnl_chain *nlc,
struct netlink_ctx *ctx);
extern void netlink_dump_rule(const struct nftnl_rule *nlr,
diff --git a/include/rule.h b/include/rule.h
index d829f484..22c611f6 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -620,6 +620,7 @@ enum cmd_obj {
CMD_OBJ_SETELEMS,
CMD_OBJ_SETS,
CMD_OBJ_RULE,
+ CMD_OBJ_RULES,
CMD_OBJ_CHAIN,
CMD_OBJ_CHAINS,
CMD_OBJ_TABLE,
diff --git a/src/cache.c b/src/cache.c
index 85de970f..0f5d1099 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -263,6 +263,30 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
return flags;
}
+static unsigned int evaluate_cache_reset(struct cmd *cmd, unsigned int flags,
+ struct nft_cache_filter *filter)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_RULES:
+ if (filter) {
+ if (cmd->handle.table.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ }
+ if (cmd->handle.chain.name)
+ filter->list.chain = cmd->handle.chain.name;
+ }
+ flags |= NFT_CACHE_SET | NFT_CACHE_FLOWTABLE |
+ NFT_CACHE_OBJECT | NFT_CACHE_CHAIN;
+ break;
+ default:
+ flags |= NFT_CACHE_TABLE;
+ break;
+ }
+
+ return flags;
+}
+
static int nft_handle_validate(const struct cmd *cmd, struct list_head *msgs)
{
const struct handle *h = &cmd->handle;
@@ -277,6 +301,7 @@ static int nft_handle_validate(const struct cmd *cmd, struct list_head *msgs)
}
break;
case CMD_OBJ_RULE:
+ case CMD_OBJ_RULES:
case CMD_OBJ_CHAIN:
case CMD_OBJ_CHAINS:
if (h->table.name &&
@@ -403,7 +428,7 @@ int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
flags = evaluate_cache_get(cmd, flags);
break;
case CMD_RESET:
- flags |= NFT_CACHE_TABLE;
+ flags |= evaluate_cache_reset(cmd, flags, filter);
break;
case CMD_LIST:
flags |= evaluate_cache_list(nft, cmd, flags, filter);
@@ -591,8 +616,8 @@ static int list_rule_cb(struct nftnl_rule *nlr, void *data)
table = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE);
chain = nftnl_rule_get_str(nlr, NFTNL_RULE_CHAIN);
- if (h->family != family ||
- strcmp(table, h->table.name) != 0 ||
+ if ((h->family != NFPROTO_UNSPEC && h->family != family) ||
+ (h->table.name && strcmp(table, h->table.name) != 0) ||
(h->chain.name && strcmp(chain, h->chain.name) != 0))
return 0;
@@ -604,19 +629,23 @@ static int list_rule_cb(struct nftnl_rule *nlr, void *data)
return 0;
}
-static int rule_cache_dump(struct netlink_ctx *ctx, const struct handle *h,
- const struct nft_cache_filter *filter)
+int rule_cache_dump(struct netlink_ctx *ctx, const struct handle *h,
+ const struct nft_cache_filter *filter,
+ bool dump, bool reset)
{
struct nftnl_rule_list *rule_cache;
const char *table = NULL;
const char *chain = NULL;
+ uint64_t rule_handle = 0;
if (filter) {
table = filter->list.table;
chain = filter->list.chain;
+ rule_handle = filter->list.rule_handle;
}
- rule_cache = mnl_nft_rule_dump(ctx, h->family, table, chain);
+ rule_cache = mnl_nft_rule_dump(ctx, h->family,
+ table, chain, rule_handle, dump, reset);
if (rule_cache == NULL) {
if (errno == EINTR)
return -1;
@@ -948,7 +977,7 @@ static int rule_init_cache(struct netlink_ctx *ctx, struct table *table,
struct chain *chain;
int ret;
- ret = rule_cache_dump(ctx, &table->handle, filter);
+ ret = rule_cache_dump(ctx, &table->handle, filter, true, false);
list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
chain = chain_cache_find(table, rule->handle.chain.name);
diff --git a/src/evaluate.c b/src/evaluate.c
index 21de1840..61ebcbfc 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -5286,6 +5286,8 @@ static int cmd_evaluate_reset(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_QUOTA:
case CMD_OBJ_COUNTERS:
case CMD_OBJ_QUOTAS:
+ case CMD_OBJ_RULES:
+ case CMD_OBJ_RULE:
if (cmd->handle.table.name == NULL)
return 0;
if (!table_cache_find(&ctx->nft->cache.table_cache,
diff --git a/src/json.c b/src/json.c
index f57f2f77..f15461d3 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1911,6 +1911,7 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_SET:
root = do_list_set_json(ctx, cmd, table);
break;
+ case CMD_OBJ_RULES:
case CMD_OBJ_RULESET:
root = do_list_ruleset_json(ctx, cmd);
break;
diff --git a/src/mnl.c b/src/mnl.c
index 46d86f0f..ca01516c 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -654,13 +654,21 @@ err_free:
}
struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
- const char *table, const char *chain)
+ const char *table, const char *chain,
+ uint64_t rule_handle,
+ bool dump, bool reset)
{
+ uint16_t nl_flags = dump ? NLM_F_DUMP : NLM_F_ACK;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_rule_list *nlr_list;
struct nftnl_rule *nlr = NULL;
struct nlmsghdr *nlh;
- int ret;
+ int msg_type, ret;
+
+ if (reset)
+ msg_type = NFT_MSG_GETRULE_RESET;
+ else
+ msg_type = NFT_MSG_GETRULE;
if (table) {
nlr = nftnl_rule_alloc();
@@ -670,14 +678,16 @@ struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, table);
if (chain)
nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, chain);
+ if (rule_handle)
+ nftnl_rule_set_u64(nlr, NFTNL_RULE_HANDLE, rule_handle);
}
nlr_list = nftnl_rule_list_alloc();
if (nlr_list == NULL)
memory_allocation_error();
- nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family,
- NLM_F_DUMP, ctx->seqnum);
+ nlh = nftnl_nlmsg_build_hdr(buf, msg_type, family,
+ nl_flags, ctx->seqnum);
if (nlr) {
nftnl_rule_nlmsg_build_payload(nlh, nlr);
nftnl_rule_free(nlr);
diff --git a/src/netlink.c b/src/netlink.c
index efae1251..f1452d48 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1767,6 +1767,55 @@ int netlink_reset_objs(struct netlink_ctx *ctx, const struct cmd *cmd,
return err;
}
+int netlink_reset_rules(struct netlink_ctx *ctx, const struct cmd *cmd,
+ bool dump)
+{
+ const struct handle *h = &cmd->handle;
+ struct nft_cache_filter f = {
+ .list.table = h->table.name,
+ .list.chain = h->chain.name,
+ .list.rule_handle = h->handle.id,
+ };
+ struct rule *rule, *next, *crule, *cnext;
+ struct table *table;
+ struct chain *chain;
+ int ret;
+
+ ret = rule_cache_dump(ctx, h, &f, dump, true);
+
+ list_for_each_entry_safe(rule, next, &ctx->list, list) {
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ rule->handle.table.name,
+ rule->handle.family);
+ if (!table)
+ continue;
+
+ chain = chain_cache_find(table, rule->handle.chain.name);
+ if (!chain)
+ continue;
+
+ list_del(&rule->list);
+ list_for_each_entry_safe(crule, cnext, &chain->rules, list) {
+ if (crule->handle.handle.id != rule->handle.handle.id)
+ continue;
+
+ list_replace(&crule->list, &rule->list);
+ rule_free(crule);
+ rule = NULL;
+ break;
+ }
+ if (rule) {
+ list_add_tail(&rule->list, &chain->rules);
+ }
+ }
+ list_for_each_entry_safe(rule, next, &ctx->list, list) {
+ list_del(&rule->list);
+ rule_free(rule);
+ }
+
+ return ret;
+}
+
struct flowtable *
netlink_delinearize_flowtable(struct netlink_ctx *ctx,
struct nftnl_flowtable *nlo)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index ccf07a30..62a4809b 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -1597,6 +1597,22 @@ reset_cmd : COUNTERS ruleset_spec
{
$$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTA, &$2, &@$, NULL);
}
+ | RULES ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &$2, &@$, NULL);
+ }
+ | RULES TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &$3, &@$, NULL);
+ }
+ | RULES CHAIN chain_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &$3, &@$, NULL);
+ }
+ | RULE ruleid_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULE, &$2, &@$, NULL);
+ }
;
flush_cmd : TABLE table_spec
diff --git a/src/parser_json.c b/src/parser_json.c
index ae683314..dfab3f9c 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -3763,6 +3763,39 @@ static struct cmd *json_parse_cmd_list(struct json_ctx *ctx,
return NULL;
}
+static struct cmd *json_parse_cmd_reset_rule(struct json_ctx *ctx,
+ json_t *root, enum cmd_ops op,
+ enum cmd_obj obj)
+{
+ struct handle h = {
+ .family = NFPROTO_UNSPEC,
+ };
+ const char *family = NULL, *table = NULL, *chain = NULL;
+
+
+ if (obj == CMD_OBJ_RULE &&
+ json_unpack_err(ctx, root, "{s:s, s:s, s:s, s:I}",
+ "family", &family, "table", &table,
+ "chain", &chain, "handle", &h.handle.id))
+ return NULL;
+ else if (obj == CMD_OBJ_RULES) {
+ json_unpack(root, "{s:s}", "family", &family);
+ json_unpack(root, "{s:s}", "table", &table);
+ json_unpack(root, "{s:s}", "chain", &chain);
+ }
+
+ if (family && parse_family(family, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", family);
+ return NULL;
+ }
+ if (table) {
+ h.table.name = xstrdup(table);
+ if (chain)
+ h.chain.name = xstrdup(chain);
+ }
+ return cmd_alloc(op, obj, &h, int_loc, NULL);
+}
+
static struct cmd *json_parse_cmd_reset(struct json_ctx *ctx,
json_t *root, enum cmd_ops op)
{
@@ -3776,6 +3809,8 @@ static struct cmd *json_parse_cmd_reset(struct json_ctx *ctx,
{ "counters", CMD_OBJ_COUNTERS, json_parse_cmd_list_multiple },
{ "quota", CMD_OBJ_QUOTA, json_parse_cmd_add_object },
{ "quotas", CMD_OBJ_QUOTAS, json_parse_cmd_list_multiple },
+ { "rule", CMD_OBJ_RULE, json_parse_cmd_reset_rule },
+ { "rules", CMD_OBJ_RULES, json_parse_cmd_reset_rule },
};
unsigned int i;
json_t *tmp;
diff --git a/src/rule.c b/src/rule.c
index 903c01f5..371c803a 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -2504,6 +2504,8 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_SET:
return do_list_set(ctx, cmd, table);
case CMD_OBJ_RULESET:
+ case CMD_OBJ_RULES:
+ case CMD_OBJ_RULE:
return do_list_ruleset(ctx, cmd);
case CMD_OBJ_METERS:
return do_list_sets(ctx, cmd);
@@ -2611,6 +2613,14 @@ static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_QUOTA:
type = NFT_OBJECT_QUOTA;
break;
+ case CMD_OBJ_RULES:
+ ret = netlink_reset_rules(ctx, cmd, true);
+ if (ret < 0)
+ return ret;
+
+ return do_command_list(ctx, cmd);
+ case CMD_OBJ_RULE:
+ return netlink_reset_rules(ctx, cmd, false);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
diff --git a/src/scanner.l b/src/scanner.l
index 9c85ee37..aa0a0a9f 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -402,6 +402,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
<SCANSTATE_CMD_LIST,SCANSTATE_CMD_RESET>{
"counters" { return COUNTERS; }
"quotas" { return QUOTAS; }
+ "rules" { return RULES; }
}
"log" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_LOG); return LOG; }
diff --git a/tests/shell/testcases/rule_management/0011reset_0 b/tests/shell/testcases/rule_management/0011reset_0
new file mode 100755
index 00000000..1a28b49f
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0011reset_0
@@ -0,0 +1,168 @@
+#!/bin/sh
+
+set -e
+
+echo "loading ruleset"
+$NFT -f - <<EOF
+table ip t {
+ set s {
+ type ipv4_addr
+ counter
+ elements = { 1.1.1.1 counter packets 1 bytes 11 }
+ }
+ chain c {
+ counter packets 1 bytes 11 update @s { ip saddr } accept
+ counter packets 2 bytes 12 drop
+ }
+
+ chain c2 {
+ counter packets 3 bytes 13 accept
+ counter packets 4 bytes 14 drop
+ }
+}
+table inet t {
+ chain c {
+ counter packets 5 bytes 15 accept
+ counter packets 6 bytes 16 drop
+ }
+}
+table ip t2 {
+ chain c2 {
+ counter packets 7 bytes 17 accept
+ counter packets 8 bytes 18 drop
+ }
+}
+EOF
+
+echo "resetting specific rule"
+handle=$($NFT -a list chain t c | sed -n 's/.*accept # handle \([0-9]*\)$/\1/p')
+$NFT reset rule t c handle $handle
+EXPECT='table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ elements = { 1.1.1.1 counter packets 1 bytes 11 }
+ }
+
+ chain c {
+ counter packets 0 bytes 0 update @s { ip saddr } accept
+ counter packets 2 bytes 12 drop
+ }
+
+ chain c2 {
+ counter packets 3 bytes 13 accept
+ counter packets 4 bytes 14 drop
+ }
+}
+table inet t {
+ chain c {
+ counter packets 5 bytes 15 accept
+ counter packets 6 bytes 16 drop
+ }
+}
+table ip t2 {
+ chain c2 {
+ counter packets 7 bytes 17 accept
+ counter packets 8 bytes 18 drop
+ }
+}'
+$DIFF -u <(echo "$EXPECT") <($NFT list ruleset)
+
+echo "resetting specific chain"
+EXPECT='table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ }
+
+ chain c2 {
+ counter packets 3 bytes 13 accept
+ counter packets 4 bytes 14 drop
+ }
+}'
+$DIFF -u <(echo "$EXPECT") <($NFT reset rules chain t c2)
+
+echo "resetting specific table"
+EXPECT='table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ }
+
+ chain c {
+ counter packets 0 bytes 0 update @s { ip saddr } accept
+ counter packets 2 bytes 12 drop
+ }
+
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}'
+$DIFF -u <(echo "$EXPECT") <($NFT reset rules table t)
+
+echo "resetting specific family"
+EXPECT='table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ }
+
+ chain c {
+ counter packets 0 bytes 0 update @s { ip saddr } accept
+ counter packets 0 bytes 0 drop
+ }
+
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}
+table ip t2 {
+ chain c2 {
+ counter packets 7 bytes 17 accept
+ counter packets 8 bytes 18 drop
+ }
+}'
+$DIFF -u <(echo "$EXPECT") <($NFT reset rules ip)
+
+echo "resetting whole ruleset"
+EXPECT='table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ }
+
+ chain c {
+ counter packets 0 bytes 0 update @s { ip saddr } accept
+ counter packets 0 bytes 0 drop
+ }
+
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}
+table inet t {
+ chain c {
+ counter packets 5 bytes 15 accept
+ counter packets 6 bytes 16 drop
+ }
+}
+table ip t2 {
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}'
+$DIFF -u <(echo "$EXPECT") <($NFT reset rules)
diff --git a/tests/shell/testcases/rule_management/dumps/0011reset_0.nft b/tests/shell/testcases/rule_management/dumps/0011reset_0.nft
new file mode 100644
index 00000000..3b4f5a11
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0011reset_0.nft
@@ -0,0 +1,31 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ elements = { 1.1.1.1 counter packets 1 bytes 11 }
+ }
+
+ chain c {
+ counter packets 0 bytes 0 update @s { ip saddr } accept
+ counter packets 0 bytes 0 drop
+ }
+
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}
+table inet t {
+ chain c {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}
+table ip t2 {
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}