]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
nft-cache: Fetch cache per table
authorPhil Sutter <phil@nwl.cc>
Wed, 18 Mar 2020 16:08:31 +0000 (17:08 +0100)
committerPhil Sutter <phil@nwl.cc>
Mon, 11 May 2020 12:28:28 +0000 (14:28 +0200)
Restore per-table operation of cache routines as initially implemented
in commit e2883c5531e6e ("nft-cache: Support partial cache per table").

As before, this doesn't limit fetching of tables (their number is
supposed to be low) but instead limits fetching of sets, chains and
rules to the specified table.

For this to behave correctly when restoring without flushing over
multiple tables, cache must be freed fully after each commit - otherwise
the previous table's cache level is reused for the current one. The
exception being fake cache, used for flushing restore: NFT_CL_FAKE is
set just once at program startup, so it must stay set otherwise
consecutive tables cause pointless cache fetching.

The sole use-case requiring a multi-table cache, iptables-save, is
indicated by req->table being NULL. Therefore, req->table assignment is
a bit sloppy: All calls to nft_cache_level_set() are assumed to set the
same table value, collision detection exists merely to catch programming
mistakes.

Make nft_fini() call nft_release_cache() instead of flush_chain_cache(),
the former does a full cache deinit including cache_req contents.

Signed-off-by: Phil Sutter <phil@nwl.cc>
iptables/nft-cache.c
iptables/nft-cache.h
iptables/nft-cmd.c
iptables/nft.c
iptables/nft.h
iptables/xtables-restore.c
iptables/xtables-save.c

index 305f2c12307f7a22984e3517ba5201feecf3c45d..611846534a0984b810b5cd4cb8fdb9b603b41ccd 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <stdlib.h>
 #include <string.h>
 #include <xtables.h>
 
 #include "nft.h"
 #include "nft-cache.h"
 
-void nft_cache_level_set(struct nft_handle *h, int level)
+void nft_cache_level_set(struct nft_handle *h, int level,
+                        const struct nft_cmd *cmd)
 {
        struct nft_cache_req *req = &h->cache_req;
 
-       if (level <= req->level)
+       if (level > req->level)
+               req->level = level;
+
+       if (!cmd)
                return;
 
-       req->level = level;
+       if (!req->table)
+               req->table = strdup(cmd->table);
+       else
+               assert(!strcmp(req->table, cmd->table));
 }
 
 static int genid_cb(const struct nlmsghdr *nlh, void *data)
@@ -435,10 +443,14 @@ static void
 __nft_build_cache(struct nft_handle *h)
 {
        struct nft_cache_req *req = &h->cache_req;
+       const struct builtin_table *t = NULL;
 
        if (h->cache_init)
                return;
 
+       if (req->table)
+               t = nft_table_builtin_find(h, req->table);
+
        h->cache_init = true;
        mnl_genid_get(h, &h->nft_genid);
 
@@ -447,11 +459,11 @@ __nft_build_cache(struct nft_handle *h)
        if (req->level == NFT_CL_FAKE)
                return;
        if (req->level >= NFT_CL_CHAINS)
-               fetch_chain_cache(h, NULL, NULL);
+               fetch_chain_cache(h, t, NULL);
        if (req->level >= NFT_CL_SETS)
-               fetch_set_cache(h, NULL, NULL);
+               fetch_set_cache(h, t, NULL);
        if (req->level >= NFT_CL_RULES)
-               fetch_rule_cache(h, NULL);
+               fetch_rule_cache(h, t);
 }
 
 static void __nft_flush_cache(struct nft_handle *h)
@@ -575,14 +587,20 @@ void nft_cache_build(struct nft_handle *h)
 
 void nft_release_cache(struct nft_handle *h)
 {
-       if (!h->cache_index)
-               return;
+       struct nft_cache_req *req = &h->cache_req;
 
+       while (h->cache_index)
+               flush_cache(h, &h->__cache[h->cache_index--], NULL);
        flush_cache(h, &h->__cache[0], NULL);
-       memcpy(&h->__cache[0], &h->__cache[1], sizeof(h->__cache[0]));
-       memset(&h->__cache[1], 0, sizeof(h->__cache[1]));
-       h->cache_index = 0;
        h->cache = &h->__cache[0];
+       h->cache_init = false;
+
+       if (req->level != NFT_CL_FAKE)
+               req->level = NFT_CL_TABLES;
+       if (req->table) {
+               free(req->table);
+               req->table = NULL;
+       }
 }
 
 struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
index 01dd15e145fd444ba5f7d075ee9e0a3f555a5fea..f429118041be42d06556f0a04942576e3b1c39de 100644 (file)
@@ -2,8 +2,10 @@
 #define _NFT_CACHE_H_
 
 struct nft_handle;
+struct nft_cmd;
 
-void nft_cache_level_set(struct nft_handle *h, int level);
+void nft_cache_level_set(struct nft_handle *h, int level,
+                        const struct nft_cmd *cmd);
 void nft_rebuild_cache(struct nft_handle *h);
 void nft_release_cache(struct nft_handle *h);
 void flush_chain_cache(struct nft_handle *h, const char *tablename);
index 8bf361a6ba33541dfff86cf5c3d38777e038d332..23f2761f2bf3f72d88146df30bc557d047225b7d 100644 (file)
@@ -71,12 +71,11 @@ void nft_cmd_free(struct nft_cmd *cmd)
        free(cmd);
 }
 
-static void nft_cmd_rule_bridge(struct nft_handle *h, const char *chain,
-                               const char *table)
+static void nft_cmd_rule_bridge(struct nft_handle *h, const struct nft_cmd *cmd)
 {
        const struct builtin_table *t;
 
-       t = nft_table_builtin_find(h, table);
+       t = nft_table_builtin_find(h, cmd->table);
        if (!t)
                return;
 
@@ -84,10 +83,10 @@ static void nft_cmd_rule_bridge(struct nft_handle *h, const char *chain,
         * rule in nftables, rule cache is required here to treat them right.
         */
        if (h->family == NFPROTO_BRIDGE &&
-           !nft_chain_builtin_find(t, chain))
-               nft_cache_level_set(h, NFT_CL_RULES);
+           !nft_chain_builtin_find(t, cmd->chain))
+               nft_cache_level_set(h, NFT_CL_RULES, cmd);
        else
-               nft_cache_level_set(h, NFT_CL_CHAINS);
+               nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
 }
 
 int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
@@ -96,13 +95,13 @@ int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
 {
        struct nft_cmd *cmd;
 
-       nft_cmd_rule_bridge(h, chain, table);
-
        cmd = nft_cmd_new(h, NFT_COMPAT_RULE_APPEND, table, chain, state, -1,
                          verbose);
        if (!cmd)
                return 0;
 
+       nft_cmd_rule_bridge(h, cmd);
+
        return 1;
 }
 
@@ -112,17 +111,17 @@ int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
 {
        struct nft_cmd *cmd;
 
-       nft_cmd_rule_bridge(h, chain, table);
-
        cmd = nft_cmd_new(h, NFT_COMPAT_RULE_INSERT, table, chain, state,
                          rulenum, verbose);
        if (!cmd)
                return 0;
 
+       nft_cmd_rule_bridge(h, cmd);
+
        if (cmd->rulenum > 0)
-               nft_cache_level_set(h, NFT_CL_RULES);
+               nft_cache_level_set(h, NFT_CL_RULES, cmd);
        else
-               nft_cache_level_set(h, NFT_CL_CHAINS);
+               nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
 
        return 1;
 }
@@ -138,7 +137,7 @@ int nft_cmd_rule_delete(struct nft_handle *h, const char *chain,
        if (!cmd)
                return 0;
 
-       nft_cache_level_set(h, NFT_CL_RULES);
+       nft_cache_level_set(h, NFT_CL_RULES, cmd);
 
        return 1;
 }
@@ -153,7 +152,7 @@ int nft_cmd_rule_delete_num(struct nft_handle *h, const char *chain,
        if (!cmd)
                return 0;
 
-       nft_cache_level_set(h, NFT_CL_RULES);
+       nft_cache_level_set(h, NFT_CL_RULES, cmd);
 
        return 1;
 }
@@ -168,7 +167,7 @@ int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
        if (!cmd)
                return 0;
 
-       nft_cache_level_set(h, NFT_CL_CHAINS);
+       nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
 
        return 1;
 }
@@ -183,7 +182,7 @@ int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
        if (!cmd)
                return 0;
 
-       nft_cache_level_set(h, NFT_CL_CHAINS);
+       nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
 
        return 1;
 }
@@ -198,7 +197,7 @@ int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
        if (!cmd)
                return 0;
 
-       nft_cache_level_set(h, NFT_CL_CHAINS);
+       nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
 
        return 1;
 }
@@ -217,9 +216,9 @@ int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
         * rule cache.
         */
        if (h->family == NFPROTO_BRIDGE)
-               nft_cache_level_set(h, NFT_CL_RULES);
+               nft_cache_level_set(h, NFT_CL_RULES, cmd);
        else
-               nft_cache_level_set(h, NFT_CL_CHAINS);
+               nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
 
        return 1;
 }
@@ -236,7 +235,7 @@ int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
 
        cmd->rename = strdup(newname);
 
-       nft_cache_level_set(h, NFT_CL_CHAINS);
+       nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
 
        return 1;
 }
@@ -253,7 +252,7 @@ int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
 
        cmd->format = format;
 
-       nft_cache_level_set(h, NFT_CL_RULES);
+       nft_cache_level_set(h, NFT_CL_RULES, cmd);
 
        return 1;
 }
@@ -269,7 +268,7 @@ int nft_cmd_rule_replace(struct nft_handle *h, const char *chain,
        if (!cmd)
                return 0;
 
-       nft_cache_level_set(h, NFT_CL_RULES);
+       nft_cache_level_set(h, NFT_CL_RULES, cmd);
 
        return 1;
 }
@@ -284,7 +283,7 @@ int nft_cmd_rule_check(struct nft_handle *h, const char *chain,
        if (!cmd)
                return 0;
 
-       nft_cache_level_set(h, NFT_CL_RULES);
+       nft_cache_level_set(h, NFT_CL_RULES, cmd);
 
        return 1;
 }
@@ -304,7 +303,7 @@ int nft_cmd_chain_set(struct nft_handle *h, const char *table,
        if (counters)
                cmd->counters = *counters;
 
-       nft_cache_level_set(h, NFT_CL_CHAINS);
+       nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
 
        return 1;
 }
@@ -318,7 +317,7 @@ int nft_cmd_table_flush(struct nft_handle *h, const char *table)
        if (!cmd)
                return 0;
 
-       nft_cache_level_set(h, NFT_CL_TABLES);
+       nft_cache_level_set(h, NFT_CL_TABLES, cmd);
 
        return 1;
 }
@@ -333,7 +332,7 @@ int nft_cmd_chain_restore(struct nft_handle *h, const char *chain,
        if (!cmd)
                return 0;
 
-       nft_cache_level_set(h, NFT_CL_CHAINS);
+       nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
 
        return 1;
 }
@@ -348,7 +347,7 @@ int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain,
        if (!cmd)
                return 0;
 
-       nft_cache_level_set(h, NFT_CL_RULES);
+       nft_cache_level_set(h, NFT_CL_RULES, cmd);
 
        return 1;
 }
@@ -365,7 +364,7 @@ int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
 
        cmd->counters_save = counters;
 
-       nft_cache_level_set(h, NFT_CL_RULES);
+       nft_cache_level_set(h, NFT_CL_RULES, cmd);
 
        return 1;
 }
@@ -382,7 +381,7 @@ int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
 
        cmd->policy = strdup(policy);
 
-       nft_cache_level_set(h, NFT_CL_RULES);
+       nft_cache_level_set(h, NFT_CL_RULES, cmd);
 
        return 1;
 }
index f9e53316ab7cf6d815ac634492a70ec30e6f3b0e..daf0860401ba5dfa2df8bca801fa46a12c7abb34 100644 (file)
@@ -816,7 +816,7 @@ void nft_fini(struct nft_handle *h)
        list_for_each_entry_safe(cmd, next, &h->cmd_list, head)
                nft_cmd_free(cmd);
 
-       flush_chain_cache(h, NULL);
+       nft_release_cache(h);
        mnl_socket_close(h->nl);
 }
 
index c6aece7d1dac8de3fb074defdb63bc71054364f1..4eaaa77f962f4ebbd029ec46fe1066726335f284 100644 (file)
@@ -73,6 +73,7 @@ enum obj_update_type {
 
 struct nft_cache_req {
        enum nft_cache_level    level;
+       char                    *table;
 };
 
 struct nft_handle {
index 28ef366c302af14af4e80f008a8d18833789d0c9..418a7400c8ce00c06fadada632e85c9217e26ca8 100644 (file)
@@ -261,7 +261,7 @@ void xtables_restore_parse(struct nft_handle *h,
        char buffer[10240] = {};
 
        if (!h->noflush)
-               nft_cache_level_set(h, NFT_CL_FAKE);
+               nft_cache_level_set(h, NFT_CL_FAKE, NULL);
 
        line = 0;
        while (fgets(buffer, sizeof(buffer), p->in)) {
index f927aa6e9e4041eb141e57c5fc6176ff3753ac4a..0ce66e5d15cee1a9c4cfed8022a11b11fc068f23 100644 (file)
@@ -239,7 +239,7 @@ xtables_save_main(int family, int argc, char *argv[],
                exit(EXIT_FAILURE);
        }
 
-       nft_cache_level_set(&h, NFT_CL_RULES);
+       nft_cache_level_set(&h, NFT_CL_RULES, NULL);
        nft_cache_build(&h);
 
        ret = do_output(&h, tablename, &d);