This patch allows you to atomically dump and reset stateful objects, eg.
# nft list counters
table ip filter {
counter test {
packets 1024 bytes 100000
}
}
# nft reset quotas table filter
counter test {
packets 1024 bytes 100000
}
# nft reset quotas table filter
counter test {
packets 0 bytes 0
}
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nftnl_set *nls);
struct nftnl_obj_list *mnl_nft_obj_dump(struct mnl_socket *nf_sock, int family,
- const char *table);
+ const char *table, uint32_t type,
+ bool reset);
int mnl_nft_obj_batch_add(struct nftnl_obj *nln, unsigned int flags,
uint32_t seqnum);
int mnl_nft_obj_batch_del(struct nftnl_obj *nln, unsigned int flags,
const struct location *loc);
extern int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h,
- const struct location *loc);
+ const struct location *loc);
+extern int netlink_reset_objs(struct netlink_ctx *ctx, const struct handle *h,
+ const struct location *loc, uint32_t type);
extern int netlink_add_obj(struct netlink_ctx *ctx, const struct handle *h,
struct obj *obj, bool excl);
extern int netlink_delete_obj(struct netlink_ctx *ctx, const struct handle *h,
- struct location *loc, enum stmt_types type);
+ struct location *loc, uint32_t type);
extern void netlink_dump_table(const struct nftnl_table *nlt);
extern void netlink_dump_chain(const struct nftnl_chain *nlc);
* @CMD_INSERT: insert object
* @CMD_DELETE: delete object
* @CMD_LIST: list container
+ * @CMD_RESET: reset container
* @CMD_FLUSH: flush container
* @CMD_RENAME: rename object
* @CMD_EXPORT: export the ruleset in a given format
CMD_INSERT,
CMD_DELETE,
CMD_LIST,
+ CMD_RESET,
CMD_FLUSH,
CMD_RENAME,
CMD_EXPORT,
case CMD_DELETE:
return cmd_evaluate_delete(ctx, cmd);
case CMD_LIST:
+ case CMD_RESET:
return cmd_evaluate_list(ctx, cmd);
case CMD_FLUSH:
return cmd_evaluate_flush(ctx, cmd);
struct nftnl_obj_list *
-mnl_nft_obj_dump(struct mnl_socket *nf_sock, int family, const char *table)
+mnl_nft_obj_dump(struct mnl_socket *nf_sock, int family, const char *table,
+ uint32_t type, bool reset)
{
struct nftnl_obj_list *nln_list;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_obj *n;
struct nlmsghdr *nlh;
- int ret;
+ int msg_type, ret;
+
+ if (reset)
+ msg_type = NFT_MSG_GETOBJ_RESET;
+ else
+ msg_type = NFT_MSG_GETOBJ;
n = nftnl_obj_alloc();
if (n == NULL)
memory_allocation_error();
- nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETOBJ, family,
+ nlh = nftnl_nlmsg_build_hdr(buf, msg_type, family,
NLM_F_DUMP | NLM_F_ACK, seq);
if (table != NULL)
nftnl_obj_set(n, NFTNL_OBJ_TABLE, table);
+ if (type != NFT_OBJECT_UNSPEC)
+ nftnl_obj_set_u32(n, NFTNL_OBJ_TYPE, type);
nftnl_obj_nlmsg_build_payload(nlh, n);
nftnl_obj_free(n);
struct nftnl_obj_list *obj_cache;
int err;
- obj_cache = mnl_nft_obj_dump(nf_sock, h->family, h->table);
+ obj_cache = mnl_nft_obj_dump(nf_sock, h->family, h->table,
+ NFT_OBJECT_UNSPEC, false);
+ if (obj_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
+ return netlink_io_error(ctx, loc,
+ "Could not receive stateful objects from kernel: %s",
+ strerror(errno));
+ }
+
+ err = nftnl_obj_list_foreach(obj_cache, list_obj_cb, ctx);
+ nftnl_obj_list_free(obj_cache);
+ return err;
+}
+
+int netlink_reset_objs(struct netlink_ctx *ctx, const struct handle *h,
+ const struct location *loc, uint32_t type)
+{
+ struct nftnl_obj_list *obj_cache;
+ int err;
+
+ obj_cache = mnl_nft_obj_dump(nf_sock, h->family, h->table, type, true);
if (obj_cache == NULL) {
if (errno == EINTR)
return -1;
%token INSERT "insert"
%token DELETE "delete"
%token LIST "list"
+%token RESET "reset"
%token FLUSH "flush"
%token RENAME "rename"
%token DESCRIBE "describe"
%type <cmd> line
%destructor { cmd_free($$); } line
-%type <cmd> base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
-%destructor { cmd_free($$); } base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
+%type <cmd> base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
+%destructor { cmd_free($$); } base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
%type <handle> table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
%destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
| INSERT insert_cmd { $$ = $2; }
| DELETE delete_cmd { $$ = $2; }
| LIST list_cmd { $$ = $2; }
+ | RESET reset_cmd { $$ = $2; }
| FLUSH flush_cmd { $$ = $2; }
| RENAME rename_cmd { $$ = $2; }
| EXPORT export_cmd { $$ = $2; }
}
;
+reset_cmd : COUNTERS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$2, &@$, NULL);
+ }
+ | COUNTERS TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$3, &@$, NULL);
+ }
+ | QUOTAS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &$2, &@$, NULL);
+ }
+ | QUOTAS TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &$3, &@$, NULL);
+ }
+ ;
+
flush_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_TABLE, &$2, &@$, NULL);
return -1;
list_splice_tail_init(&ctx->list, &table->chains);
- /* Don't check for errors on listings, this would break nft with
- * old kernels with no stateful object support.
- */
- netlink_list_objs(ctx, &table->handle, &internal_location);
- list_splice_tail_init(&ctx->list, &table->objs);
+ if (cmd != CMD_RESET) {
+ /* Don't check for errors on listings, this would break
+ * nft with old kernels with no stateful object support.
+ */
+ netlink_list_objs(ctx, &table->handle, &internal_location);
+ list_splice_tail_init(&ctx->list, &table->objs);
+ }
/* Skip caching other objects to speed up things: We only need
* a full cache when listing the existing ruleset.
return 0;
}
+static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct obj *obj, *next;
+ struct table *table;
+ uint32_t type;
+ int ret;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_COUNTERS:
+ type = NFT_OBJECT_COUNTER;
+ break;
+ case CMD_OBJ_QUOTAS:
+ type = NFT_OBJECT_QUOTA;
+ break;
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+
+ ret = netlink_reset_objs(ctx, &cmd->handle, &cmd->location, type);
+ list_for_each_entry_safe(obj, next, &ctx->list, list) {
+ table = table_lookup(&obj->handle);
+ list_move(&obj->list, &table->objs);
+ }
+ if (ret < 0)
+ return ret;
+
+ return do_list_obj(ctx, cmd, type);
+}
+
static int do_command_flush(struct netlink_ctx *ctx, struct cmd *cmd)
{
switch (cmd->obj) {
return do_command_delete(ctx, cmd);
case CMD_LIST:
return do_command_list(ctx, cmd);
+ case CMD_RESET:
+ return do_command_reset(ctx, cmd);
case CMD_FLUSH:
return do_command_flush(ctx, cmd);
case CMD_RENAME:
"insert" { return INSERT; }
"delete" { return DELETE; }
"list" { return LIST; }
+"reset" { return RESET; }
"flush" { return FLUSH; }
"rename" { return RENAME; }
"export" { return EXPORT; }