]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: single cache_update() call to build cache before evaluation
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 4 Jun 2019 10:02:18 +0000 (12:02 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 6 Jun 2019 09:16:25 +0000 (11:16 +0200)
This patch allows us to make one single cache_update() call. Thus, there
is not need to rebuild an incomplete cache from the middle of the batch
processing.

Note that nft_run_cmd_from_filename() does not need a full netlink dump
to build the cache anymore, this should speed nft -f with incremental
updates and very large rulesets.

cache_evaluate() calculates the netlink dump to populate the cache that
this batch needs.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/rule.h
src/Makefile.am
src/cache.c [new file with mode: 0644]
src/evaluate.c
src/libnftables.c
src/mnl.c
src/rule.c

index 8e70c129fcce060837ec4c05107182cd3d84802c..bf3f39636efb52fbc4b2fbfec43da466d997e793 100644 (file)
@@ -631,6 +631,7 @@ extern struct error_record *rule_postprocess(struct rule *rule);
 struct netlink_ctx;
 extern int do_command(struct netlink_ctx *ctx, struct cmd *cmd);
 
+extern int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds);
 extern int cache_update(struct nft_ctx *ctx, enum cmd_ops cmd,
                        struct list_head *msgs);
 extern void cache_flush(struct nft_ctx *ctx, enum cmd_ops cmd,
index 8e1a4d8795dcd18dae9154c6473f21b92ef54c4b..fd641755b7a44e4d5037ad257e5cfa0f8275b7cf 100644 (file)
@@ -31,6 +31,7 @@ lib_LTLIBRARIES = libnftables.la
 libnftables_la_SOURCES =                       \
                rule.c                          \
                statement.c                     \
+               cache.c                         \
                datatype.c                      \
                expression.c                    \
                evaluate.c                      \
diff --git a/src/cache.c b/src/cache.c
new file mode 100644 (file)
index 0000000..2a0f04d
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2019 Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <expression.h>
+#include <statement.h>
+#include <rule.h>
+#include <erec.h>
+#include <utils.h>
+
+static unsigned int evaluate_cache_add(struct cmd *cmd)
+{
+       unsigned int completeness = CMD_INVALID;
+
+       switch (cmd->obj) {
+       case CMD_OBJ_SETELEM:
+       case CMD_OBJ_SET:
+       case CMD_OBJ_CHAIN:
+       case CMD_OBJ_FLOWTABLE:
+               completeness = cmd->op;
+               break;
+       case CMD_OBJ_RULE:
+               /* XXX index is set to zero unless this handle_merge() call is
+                * invoked, this handle_merge() call is done from the
+                * evaluation, which is too late.
+                */
+               handle_merge(&cmd->rule->handle, &cmd->handle);
+
+               if (cmd->rule->handle.index.id)
+                       completeness = CMD_LIST;
+               break;
+       default:
+               break;
+       }
+
+       return completeness;
+}
+
+static unsigned int evaluate_cache_del(struct cmd *cmd)
+{
+       unsigned int completeness = CMD_INVALID;
+
+       switch (cmd->obj) {
+       case CMD_OBJ_SETELEM:
+               completeness = cmd->op;
+               break;
+       default:
+               break;
+       }
+
+       return completeness;
+}
+
+static unsigned int evaluate_cache_flush(struct cmd *cmd)
+{
+       unsigned int completeness = CMD_INVALID;
+
+       switch (cmd->obj) {
+       case CMD_OBJ_SET:
+       case CMD_OBJ_MAP:
+       case CMD_OBJ_METER:
+               completeness = cmd->op;
+               break;
+       default:
+               break;
+       }
+
+       return completeness;
+}
+
+static unsigned int evaluate_cache_rename(struct cmd *cmd)
+{
+       unsigned int completeness = CMD_INVALID;
+
+       switch (cmd->obj) {
+       case CMD_OBJ_CHAIN:
+               completeness = cmd->op;
+               break;
+       default:
+               break;
+       }
+
+       return completeness;
+}
+
+int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
+{
+       unsigned int echo_completeness = CMD_INVALID;
+       unsigned int completeness = CMD_INVALID;
+       struct cmd *cmd;
+
+       list_for_each_entry(cmd, cmds, list) {
+               switch (cmd->op) {
+               case CMD_ADD:
+               case CMD_INSERT:
+               case CMD_REPLACE:
+                       if (nft_output_echo(&nft->output))
+                               echo_completeness = cmd->op;
+
+                       /* Fall through */
+               case CMD_CREATE:
+                       completeness = evaluate_cache_add(cmd);
+                       break;
+               case CMD_DELETE:
+                       completeness = evaluate_cache_del(cmd);
+                       break;
+               case CMD_GET:
+               case CMD_LIST:
+               case CMD_RESET:
+               case CMD_EXPORT:
+               case CMD_MONITOR:
+                       completeness = cmd->op;
+                       break;
+               case CMD_FLUSH:
+                       completeness = evaluate_cache_flush(cmd);
+                       break;
+               case CMD_RENAME:
+                       completeness = evaluate_cache_rename(cmd);
+                       break;
+               case CMD_DESCRIBE:
+               case CMD_IMPORT:
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return max(completeness, echo_completeness);
+}
index 55fb3b6131e0444871647ac6fe38880413edc9d0..63be2dde8fa2e5cdc105ab16e63d2f16353e7e45 100644 (file)
@@ -226,7 +226,6 @@ static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
        struct table *table;
        struct set *set;
        struct expr *new;
-       int ret;
 
        switch ((*expr)->symtype) {
        case SYMBOL_VALUE:
@@ -238,10 +237,6 @@ static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
                }
                break;
        case SYMBOL_SET:
-               ret = cache_update(ctx->nft, ctx->cmd->op, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
                table = table_lookup_global(ctx);
                if (table == NULL)
                        return table_not_found(ctx);
@@ -3191,12 +3186,6 @@ static int rule_translate_index(struct eval_ctx *ctx, struct rule *rule)
        struct chain *chain;
        uint64_t index = 0;
        struct rule *r;
-       int ret;
-
-       /* update cache with CMD_LIST so that rules are fetched, too */
-       ret = cache_update(ctx->nft, CMD_LIST, ctx->msgs);
-       if (ret < 0)
-               return ret;
 
        table = table_lookup(&rule->handle, &ctx->nft->cache);
        if (!table)
@@ -3412,38 +3401,20 @@ static int table_evaluate(struct eval_ctx *ctx, struct table *table)
 
 static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
 {
-       int ret;
-
        switch (cmd->obj) {
        case CMD_OBJ_SETELEM:
-               ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
                return setelem_evaluate(ctx, &cmd->expr);
        case CMD_OBJ_SET:
-               ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
                handle_merge(&cmd->set->handle, &cmd->handle);
                return set_evaluate(ctx, cmd->set);
        case CMD_OBJ_RULE:
                handle_merge(&cmd->rule->handle, &cmd->handle);
                return rule_evaluate(ctx, cmd->rule);
        case CMD_OBJ_CHAIN:
-               ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
                return chain_evaluate(ctx, cmd->chain);
        case CMD_OBJ_TABLE:
                return table_evaluate(ctx, cmd->table);
        case CMD_OBJ_FLOWTABLE:
-               ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
                handle_merge(&cmd->flowtable->handle, &cmd->handle);
                return flowtable_evaluate(ctx, cmd->flowtable);
        case CMD_OBJ_COUNTER:
@@ -3460,14 +3431,8 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
 
 static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
 {
-       int ret;
-
        switch (cmd->obj) {
        case CMD_OBJ_SETELEM:
-               ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
                return setelem_evaluate(ctx, &cmd->expr);
        case CMD_OBJ_SET:
        case CMD_OBJ_RULE:
@@ -3490,11 +3455,6 @@ static int cmd_evaluate_get(struct eval_ctx *ctx, struct cmd *cmd)
 {
        struct table *table;
        struct set *set;
-       int ret;
-
-       ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-       if (ret < 0)
-               return ret;
 
        switch (cmd->obj) {
        case CMD_OBJ_SETELEM:
@@ -3553,11 +3513,6 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
 {
        struct table *table;
        struct set *set;
-       int ret;
-
-       ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-       if (ret < 0)
-               return ret;
 
        switch (cmd->obj) {
        case CMD_OBJ_TABLE:
@@ -3648,12 +3603,6 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
 
 static int cmd_evaluate_reset(struct eval_ctx *ctx, struct cmd *cmd)
 {
-       int ret;
-
-       ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-       if (ret < 0)
-               return ret;
-
        switch (cmd->obj) {
        case CMD_OBJ_COUNTER:
        case CMD_OBJ_QUOTA:
@@ -3674,7 +3623,6 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
 {
        struct table *table;
        struct set *set;
-       int ret;
 
        switch (cmd->obj) {
        case CMD_OBJ_RULESET:
@@ -3688,10 +3636,6 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
                /* Chains don't hold sets */
                break;
        case CMD_OBJ_SET:
-               ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
                table = table_lookup(&cmd->handle, &ctx->nft->cache);
                if (table == NULL)
                        return table_not_found(ctx);
@@ -3703,10 +3647,6 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
 
                return 0;
        case CMD_OBJ_MAP:
-               ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
                table = table_lookup(&cmd->handle, &ctx->nft->cache);
                if (table == NULL)
                        return table_not_found(ctx);
@@ -3718,10 +3658,6 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
 
                return 0;
        case CMD_OBJ_METER:
-               ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
                table = table_lookup(&cmd->handle, &ctx->nft->cache);
                if (table == NULL)
                        return table_not_found(ctx);
@@ -3741,14 +3677,9 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
 static int cmd_evaluate_rename(struct eval_ctx *ctx, struct cmd *cmd)
 {
        struct table *table;
-       int ret;
 
        switch (cmd->obj) {
        case CMD_OBJ_CHAIN:
-               ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
                table = table_lookup(&ctx->cmd->handle, &ctx->nft->cache);
                if (table == NULL)
                        return table_not_found(ctx);
@@ -3840,11 +3771,6 @@ static uint32_t monitor_flags[CMD_MONITOR_EVENT_MAX][CMD_MONITOR_OBJ_MAX] = {
 static int cmd_evaluate_monitor(struct eval_ctx *ctx, struct cmd *cmd)
 {
        uint32_t event;
-       int ret;
-
-       ret = cache_update(ctx->nft, cmd->op, ctx->msgs);
-       if (ret < 0)
-               return ret;
 
        if (cmd->monitor->event == NULL)
                event = CMD_MONITOR_EVENT_ANY;
@@ -3870,7 +3796,7 @@ static int cmd_evaluate_export(struct eval_ctx *ctx, struct cmd *cmd)
                return cmd_error(ctx, &cmd->location,
                                 "JSON export is no longer supported, use 'nft -j list ruleset' instead");
 
-       return cache_update(ctx->nft, cmd->op, ctx->msgs);
+       return 0;
 }
 
 static int cmd_evaluate_import(struct eval_ctx *ctx, struct cmd *cmd)
index f459ecd50e456ad11832f7c48acf414ab335bb76..4bb770c07819639948736fee3c72351bd2ea0542 100644 (file)
@@ -381,8 +381,13 @@ static int nft_parse_bison_filename(struct nft_ctx *nft, const char *filename,
 static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
                        struct list_head *cmds)
 {
+       unsigned int completeness;
        struct cmd *cmd;
 
+       completeness = cache_evaluate(nft, cmds);
+       if (cache_update(nft, completeness, msgs) < 0)
+               return -1;
+
        list_for_each_entry(cmd, cmds, list) {
                struct eval_ctx ectx = {
                        .nft    = nft,
@@ -454,10 +459,6 @@ int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename)
        LIST_HEAD(msgs);
        LIST_HEAD(cmds);
 
-       rc = cache_update(nft, CMD_INVALID, &msgs);
-       if (rc < 0)
-               return -1;
-
        if (!strcmp(filename, "-"))
                filename = "/dev/stdin";
 
index 579210e4736a4c6ee49389b8b1da19ca69bea069..c0df2c941d88128192e49c0507ec3b7f76ad78b8 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -394,15 +394,9 @@ int mnl_nft_rule_replace(struct netlink_ctx *ctx, const struct cmd *cmd)
        unsigned int flags = 0;
        struct nftnl_rule *nlr;
        struct nlmsghdr *nlh;
-       int err;
-
-       if (nft_output_echo(&ctx->nft->output)) {
-               err = cache_update(ctx->nft, CMD_INVALID, ctx->msgs);
-               if (err < 0)
-                       return err;
 
+       if (nft_output_echo(&ctx->nft->output))
                flags |= NLM_F_ECHO;
-       }
 
        nlr = nftnl_rule_alloc();
        if (!nlr)
index 326edb5dd459a229d7c2fb0dbc2548d54881d4bd..c87375d51cccd78d37d9379f438e65739acc3e7a 100644 (file)
@@ -1501,15 +1501,8 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
 {
        uint32_t flags = excl ? NLM_F_EXCL : 0;
 
-       if (nft_output_echo(&ctx->nft->output)) {
-               int ret;
-
-               ret = cache_update(ctx->nft, cmd->obj, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
+       if (nft_output_echo(&ctx->nft->output))
                flags |= NLM_F_ECHO;
-       }
 
        switch (cmd->obj) {
        case CMD_OBJ_TABLE:
@@ -1552,15 +1545,8 @@ static int do_command_insert(struct netlink_ctx *ctx, struct cmd *cmd)
 {
        uint32_t flags = 0;
 
-       if (nft_output_echo(&ctx->nft->output)) {
-               int ret;
-
-               ret = cache_update(ctx->nft, cmd->obj, ctx->msgs);
-               if (ret < 0)
-                       return ret;
-
+       if (nft_output_echo(&ctx->nft->output))
                flags |= NLM_F_ECHO;
-       }
 
        switch (cmd->obj) {
        case CMD_OBJ_RULE: