From 13b351c9ba01751c693df68f657d19e8c3d267ce Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 18 Mar 2020 17:08:31 +0100 Subject: nft-cache: Fetch cache per table 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 --- iptables/nft-cache.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) (limited to 'iptables/nft-cache.c') diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 305f2c12..61184653 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -24,14 +25,21 @@ #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) -- cgit v1.2.3