]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: add cache level flags
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 17 Jun 2019 10:03:08 +0000 (12:03 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 17 Jun 2019 17:54:57 +0000 (19:54 +0200)
The score approach based on command type is confusing.

This patch introduces cache level flags, each flag specifies what kind
of object type is needed. These flags are set on/off depending on the
list of commands coming in this batch.

cache_is_complete() now checks if the cache contains the objects that
are needed through these new flags.

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

index b1f4fcf2901586ec3e08752f954605a63f843722..2d77a768acb0bade1a0d3c5085837012a4e92e60 100644 (file)
@@ -2,6 +2,7 @@ SUBDIRS =               linux           \
                        nftables
 
 noinst_HEADERS =       cli.h           \
+                       cache.h         \
                        datatype.h      \
                        expression.h    \
                        fib.h           \
diff --git a/include/cache.h b/include/cache.h
new file mode 100644 (file)
index 0000000..d3502a8
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _NFT_CACHE_H_
+#define _NFT_CACHE_H_
+
+enum cache_level_bits {
+       NFT_CACHE_TABLE_BIT     = (1 << 0),
+       NFT_CACHE_CHAIN_BIT     = (1 << 1),
+       NFT_CACHE_SET_BIT       = (1 << 2),
+       NFT_CACHE_FLOWTABLE_BIT = (1 << 3),
+       NFT_CACHE_OBJECT_BIT    = (1 << 4),
+       NFT_CACHE_SETELEM_BIT   = (1 << 5),
+       NFT_CACHE_RULE_BIT      = (1 << 6),
+       __NFT_CACHE_MAX_BIT     = (1 << 7),
+};
+
+enum cache_level_flags {
+       NFT_CACHE_EMPTY         = 0,
+       NFT_CACHE_TABLE         = NFT_CACHE_TABLE_BIT,
+       NFT_CACHE_CHAIN         = NFT_CACHE_TABLE_BIT |
+                                 NFT_CACHE_CHAIN_BIT,
+       NFT_CACHE_SET           = NFT_CACHE_TABLE_BIT |
+                                 NFT_CACHE_SET_BIT,
+       NFT_CACHE_FLOWTABLE     = NFT_CACHE_TABLE_BIT |
+                                 NFT_CACHE_FLOWTABLE_BIT,
+       NFT_CACHE_OBJECT        = NFT_CACHE_TABLE_BIT |
+                                 NFT_CACHE_OBJECT_BIT,
+       NFT_CACHE_SETELEM       = NFT_CACHE_TABLE_BIT |
+                                 NFT_CACHE_SET_BIT |
+                                 NFT_CACHE_SETELEM_BIT,
+       NFT_CACHE_RULE          = NFT_CACHE_TABLE_BIT |
+                                 NFT_CACHE_CHAIN_BIT |
+                                 NFT_CACHE_RULE_BIT,
+       NFT_CACHE_FULL          = __NFT_CACHE_MAX_BIT - 1,
+};
+
+#endif /* _NFT_CACHE_H_ */
index b7c78572da77fa70bc5b1a9906c9fbf527a09233..ed446e2d16cf85709a79decaafdd1406e0111f1c 100644 (file)
@@ -81,7 +81,7 @@ struct nft_cache {
        uint32_t                genid;
        struct list_head        list;
        uint32_t                seqnum;
-       uint32_t                cmd;
+       uint32_t                flags;
 };
 
 struct mnl_socket;
index 299485ffeeaabced97d5289102a3a790139d7c05..aefb24d95163e91649505c00c28a3034d309c05c 100644 (file)
@@ -462,7 +462,6 @@ enum cmd_ops {
        CMD_EXPORT,
        CMD_MONITOR,
        CMD_DESCRIBE,
-       __CMD_FLUSH_RULESET,
 };
 
 /**
@@ -636,7 +635,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 unsigned 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, struct list_head *msgs);
index d7153f6f6b8f24c22fb574fa2d48cd8d8bc5d51d..d371c5488d1be7035e7f42fe9b88cbb76b67207a 100644 (file)
 #include <rule.h>
 #include <erec.h>
 #include <utils.h>
+#include <cache.h>
 
-static unsigned int evaluate_cache_add(struct cmd *cmd)
+static unsigned int evaluate_cache_add(struct cmd *cmd, unsigned int flags)
 {
-       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;
+               flags |= NFT_CACHE_SETELEM;
                break;
        case CMD_OBJ_RULE:
-               if (cmd->handle.index.id)
-                       completeness = CMD_LIST;
+               if (cmd->handle.index.id ||
+                   cmd->handle.position.id)
+                       flags |= NFT_CACHE_RULE;
                break;
        default:
                break;
        }
 
-       return completeness;
+       return flags;
 }
 
-static unsigned int evaluate_cache_del(struct cmd *cmd)
+static unsigned int evaluate_cache_del(struct cmd *cmd, unsigned int flags)
 {
-       unsigned int completeness = CMD_INVALID;
-
        switch (cmd->obj) {
        case CMD_OBJ_SETELEM:
-               completeness = cmd->op;
+               flags |= NFT_CACHE_SETELEM;
                break;
        default:
                break;
        }
 
-       return completeness;
+       return flags;
 }
 
-static unsigned int evaluate_cache_flush(struct cmd *cmd)
+static unsigned int evaluate_cache_flush(struct cmd *cmd, unsigned int flags)
 {
-       unsigned int completeness = CMD_INVALID;
-
        switch (cmd->obj) {
-       case CMD_OBJ_RULESET:
-               completeness = __CMD_FLUSH_RULESET;
-               break;
        case CMD_OBJ_SET:
        case CMD_OBJ_MAP:
        case CMD_OBJ_METER:
-               completeness = cmd->op;
+               flags |= NFT_CACHE_SET;
                break;
+       case CMD_OBJ_RULESET:
        default:
+               flags = NFT_CACHE_EMPTY;
                break;
        }
 
-       return completeness;
+       return flags;
 }
 
-static unsigned int evaluate_cache_rename(struct cmd *cmd)
+static unsigned int evaluate_cache_rename(struct cmd *cmd, unsigned int flags)
 {
-       unsigned int completeness = CMD_INVALID;
-
        switch (cmd->obj) {
        case CMD_OBJ_CHAIN:
-               completeness = cmd->op;
+               flags |= NFT_CACHE_CHAIN;
                break;
        default:
                break;
        }
 
-       return completeness;
+       return flags;
 }
 
-int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
+unsigned int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
 {
-       unsigned int echo_completeness = CMD_INVALID;
-       unsigned int completeness = CMD_INVALID;
+       unsigned int flags = NFT_CACHE_EMPTY;
        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;
-
+                       if (nft_output_echo(&nft->output)) {
+                               flags = NFT_CACHE_FULL;
+                               break;
+                       }
+
+                       flags |= NFT_CACHE_TABLE |
+                                NFT_CACHE_CHAIN |
+                                NFT_CACHE_SET |
+                                NFT_CACHE_FLOWTABLE |
+                                NFT_CACHE_OBJECT;
                        /* Fall through */
                case CMD_CREATE:
-                       completeness = evaluate_cache_add(cmd);
+                       flags = evaluate_cache_add(cmd, flags);
+                       break;
+               case CMD_REPLACE:
+                       flags = NFT_CACHE_FULL;
                        break;
                case CMD_DELETE:
-                       completeness = evaluate_cache_del(cmd);
+                       flags |= NFT_CACHE_TABLE |
+                                NFT_CACHE_CHAIN |
+                                NFT_CACHE_SET |
+                                NFT_CACHE_FLOWTABLE |
+                                NFT_CACHE_OBJECT;
+
+                       flags = evaluate_cache_del(cmd, flags);
                        break;
                case CMD_GET:
                case CMD_LIST:
                case CMD_RESET:
                case CMD_EXPORT:
                case CMD_MONITOR:
-                       completeness = cmd->op;
+                       flags |= NFT_CACHE_FULL;
                        break;
                case CMD_FLUSH:
-                       completeness = evaluate_cache_flush(cmd);
+                       flags = evaluate_cache_flush(cmd, flags);
                        break;
                case CMD_RENAME:
-                       completeness = evaluate_cache_rename(cmd);
+                       flags = evaluate_cache_rename(cmd, flags);
                        break;
                case CMD_DESCRIBE:
                case CMD_IMPORT:
@@ -126,5 +130,5 @@ int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
                }
        }
 
-       return max(completeness, echo_completeness);
+       return flags;
 }
index 73a4be339ce1fafa919e8cbdf92fd359cd14ac3a..511f9f14bedd75b0471c992b3679a5391742a8a9 100644 (file)
@@ -29,6 +29,7 @@
 #include <netlink.h>
 #include <time.h>
 #include <rule.h>
+#include <cache.h>
 #include <erec.h>
 #include <gmputil.h>
 #include <utils.h>
@@ -3294,7 +3295,7 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule,
        }
 
        /* add rules to cache only if it is complete enough to contain them */
-       if (!cache_is_complete(&ctx->nft->cache, CMD_LIST))
+       if (!cache_is_complete(&ctx->nft->cache, NFT_CACHE_RULE))
                return 0;
 
        return rule_cache_update(ctx, op);
index abd133bee1272bcb2b2aa0a4ac69c20be39f50b1..dccb8ab4da42ae60828e07c92b3d281ef320717e 100644 (file)
@@ -381,11 +381,11 @@ 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;
+       unsigned int flags;
        struct cmd *cmd;
 
-       completeness = cache_evaluate(nft, cmds);
-       if (cache_update(nft, completeness, msgs) < 0)
+       flags = cache_evaluate(nft, cmds);
+       if (cache_update(nft, flags, msgs) < 0)
                return -1;
 
        list_for_each_entry(cmd, cmds, list) {
index ed199889702f7855a75032fa8ea86edcb9f74c6d..f60374abcfbc8fd3707b59b42598b455ab762e3c 100644 (file)
@@ -24,6 +24,7 @@
 #include <mnl.h>
 #include <misspell.h>
 #include <json.h>
+#include <cache.h>
 
 #include <libnftnl/common.h>
 #include <libnftnl/ruleset.h>
@@ -147,97 +148,85 @@ static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
        return 0;
 }
 
-static int cache_init_objects(struct netlink_ctx *ctx, enum cmd_ops cmd)
+static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
 {
+       struct rule *rule, *nrule;
        struct table *table;
        struct chain *chain;
-       struct rule *rule, *nrule;
        struct set *set;
        int ret;
 
        list_for_each_entry(table, &ctx->nft->cache.list, list) {
-               ret = netlink_list_sets(ctx, &table->handle);
-               list_splice_tail_init(&ctx->list, &table->sets);
-
-               if (ret < 0)
-                       return -1;
-
-               list_for_each_entry(set, &table->sets, list) {
-                       ret = netlink_list_setelems(ctx, &set->handle, set);
+               if (flags & NFT_CACHE_SET_BIT) {
+                       ret = netlink_list_sets(ctx, &table->handle);
+                       list_splice_tail_init(&ctx->list, &table->sets);
                        if (ret < 0)
                                return -1;
                }
-
-               ret = netlink_list_chains(ctx, &table->handle);
-               if (ret < 0)
-                       return -1;
-               list_splice_tail_init(&ctx->list, &table->chains);
-
-               ret = netlink_list_flowtables(ctx, &table->handle);
-               if (ret < 0)
-                       return -1;
-               list_splice_tail_init(&ctx->list, &table->flowtables);
-
-               if (cmd != CMD_RESET) {
+               if (flags & NFT_CACHE_SETELEM_BIT) {
+                       list_for_each_entry(set, &table->sets, list) {
+                               ret = netlink_list_setelems(ctx, &set->handle,
+                                                           set);
+                               if (ret < 0)
+                                       return -1;
+                       }
+               }
+               if (flags & NFT_CACHE_CHAIN_BIT) {
+                       ret = netlink_list_chains(ctx, &table->handle);
+                       if (ret < 0)
+                               return -1;
+                       list_splice_tail_init(&ctx->list, &table->chains);
+               }
+               if (flags & NFT_CACHE_FLOWTABLE_BIT) {
+                       ret = netlink_list_flowtables(ctx, &table->handle);
+                       if (ret < 0)
+                               return -1;
+                       list_splice_tail_init(&ctx->list, &table->flowtables);
+               }
+               if (flags & NFT_CACHE_OBJECT_BIT) {
                        ret = netlink_list_objs(ctx, &table->handle);
                        if (ret < 0)
                                return -1;
                        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.
-                */
-               if (cmd != CMD_LIST)
-                       continue;
-
-               ret = netlink_list_rules(ctx, &table->handle);
-               list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
-                       chain = chain_lookup(table, &rule->handle);
-                       list_move_tail(&rule->list, &chain->rules);
+               if (flags & NFT_CACHE_RULE_BIT) {
+                       ret = netlink_list_rules(ctx, &table->handle);
+                       list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
+                               chain = chain_lookup(table, &rule->handle);
+                               list_move_tail(&rule->list, &chain->rules);
+                       }
+                       if (ret < 0)
+                               return -1;
                }
-
-               if (ret < 0)
-                       return -1;
        }
        return 0;
 }
 
-static int cache_init(struct netlink_ctx *ctx, enum cmd_ops cmd)
+static int cache_init(struct netlink_ctx *ctx, unsigned int flags)
 {
        struct handle handle = {
                .family = NFPROTO_UNSPEC,
        };
        int ret;
 
-       if (cmd == __CMD_FLUSH_RULESET)
+       if (flags == NFT_CACHE_EMPTY)
                return 0;
 
+       /* assume NFT_CACHE_TABLE is always set. */
        ret = cache_init_tables(ctx, &handle, &ctx->nft->cache);
        if (ret < 0)
                return ret;
-       ret = cache_init_objects(ctx, cmd);
+       ret = cache_init_objects(ctx, flags);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-/* Return a "score" of how complete local cache will be if
- * cache_init_objects() ran for given cmd. Higher value
- * means more complete. */
-static int cache_completeness(enum cmd_ops cmd)
+bool cache_is_complete(struct nft_cache *cache, unsigned int flags)
 {
-       if (cmd == CMD_LIST)
-               return 3;
-       if (cmd != CMD_RESET)
-               return 2;
-       return 1;
-}
-
-bool cache_is_complete(struct nft_cache *cache, enum cmd_ops cmd)
-{
-       return cache_completeness(cache->cmd) >= cache_completeness(cmd);
+       return (cache->flags & flags) == flags;
 }
 
 static bool cache_is_updated(struct nft_cache *cache, uint16_t genid)
@@ -245,7 +234,7 @@ static bool cache_is_updated(struct nft_cache *cache, uint16_t genid)
        return genid && genid == cache->genid;
 }
 
-int cache_update(struct nft_ctx *nft, enum cmd_ops cmd, struct list_head *msgs)
+int cache_update(struct nft_ctx *nft, unsigned int flags, struct list_head *msgs)
 {
        struct netlink_ctx ctx = {
                .list           = LIST_HEAD_INIT(ctx.list),
@@ -259,14 +248,14 @@ int cache_update(struct nft_ctx *nft, enum cmd_ops cmd, struct list_head *msgs)
 replay:
        ctx.seqnum = cache->seqnum++;
        genid = mnl_genid_get(&ctx);
-       if (cache_is_complete(cache, cmd) &&
+       if (cache_is_complete(cache, flags) &&
            cache_is_updated(cache, genid))
                return 0;
 
        if (cache->genid)
                cache_release(cache);
 
-       ret = cache_init(&ctx, cmd);
+       ret = cache_init(&ctx, flags);
        if (ret < 0) {
                cache_release(cache);
                if (errno == EINTR) {
@@ -283,7 +272,7 @@ replay:
        }
 
        cache->genid = genid;
-       cache->cmd = cmd;
+       cache->flags = flags;
        return 0;
 }
 
@@ -308,15 +297,14 @@ void cache_flush(struct nft_ctx *nft, struct list_head *msgs)
 
        __cache_flush(&cache->list);
        cache->genid = mnl_genid_get(&ctx);
-       cache->cmd = CMD_LIST;
+       cache->flags = NFT_CACHE_FULL;
 }
 
 void cache_release(struct nft_cache *cache)
 {
        __cache_flush(&cache->list);
        cache->genid = 0;
-       cache->cmd = CMD_INVALID;
-
+       cache->flags = NFT_CACHE_EMPTY;
 }
 
 /* internal ID to uniquely identify a set in the batch */