Replace the simple have_cache boolean by a cache level indicator defining how complete the cache is. Since have_cache indicated full cache (including rules), make code depending on it check for cache level NFT_CL_RULES.
Core cache fetching routine __nft_build_cache() accepts a new level via parameter and raises cache completeness to that level. Signed-off-by: Phil Sutter <p...@nwl.cc> --- iptables/nft-cache.c | 51 +++++++++++++++++++++++++++++++------------- iptables/nft.h | 9 +++++++- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 5444419a5cc3b..22a87e94efd76 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -224,30 +224,49 @@ static int fetch_rule_cache(struct nft_handle *h) return 0; } -static void __nft_build_cache(struct nft_handle *h) +static void __nft_build_cache(struct nft_handle *h, enum nft_cache_level level) { uint32_t genid_start, genid_stop; + if (level <= h->cache_level) + return; retry: mnl_genid_get(h, &genid_start); - fetch_table_cache(h); - fetch_chain_cache(h); - fetch_rule_cache(h); - h->have_cache = true; - mnl_genid_get(h, &genid_stop); + switch (h->cache_level) { + case NFT_CL_NONE: + fetch_table_cache(h); + if (level == NFT_CL_TABLES) + break; + /* fall through */ + case NFT_CL_TABLES: + fetch_chain_cache(h); + if (level == NFT_CL_CHAINS) + break; + /* fall through */ + case NFT_CL_CHAINS: + fetch_rule_cache(h); + if (level == NFT_CL_RULES) + break; + /* fall through */ + case NFT_CL_RULES: + break; + } + + mnl_genid_get(h, &genid_stop); if (genid_start != genid_stop) { flush_chain_cache(h, NULL); goto retry; } + h->cache_level = level; h->nft_genid = genid_start; } void nft_build_cache(struct nft_handle *h) { - if (!h->have_cache) - __nft_build_cache(h); + if (h->cache_level < NFT_CL_RULES) + __nft_build_cache(h, NFT_CL_RULES); } void nft_fake_cache(struct nft_handle *h) @@ -263,7 +282,7 @@ void nft_fake_cache(struct nft_handle *h) h->cache->table[type].chains = nftnl_chain_list_alloc(); } - h->have_cache = true; + h->cache_level = NFT_CL_RULES; mnl_genid_get(h, &h->nft_genid); } @@ -331,19 +350,22 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c, void flush_chain_cache(struct nft_handle *h, const char *tablename) { - if (!h->have_cache) + if (!h->cache_level) return; if (flush_cache(h, h->cache, tablename)) - h->have_cache = false; + h->cache_level = NFT_CL_NONE; } void nft_rebuild_cache(struct nft_handle *h) { - if (h->have_cache) + enum nft_cache_level level = h->cache_level; + + if (h->cache_level) __nft_flush_cache(h); - __nft_build_cache(h); + h->cache_level = NFT_CL_NONE; + __nft_build_cache(h, level); } void nft_release_cache(struct nft_handle *h) @@ -354,8 +376,7 @@ void nft_release_cache(struct nft_handle *h) struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h) { - if (!h->cache->tables) - fetch_table_cache(h); + __nft_build_cache(h, NFT_CL_TABLES); return h->cache->tables; } diff --git a/iptables/nft.h b/iptables/nft.h index 451c266016d8d..9ae3122a1c515 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -27,6 +27,13 @@ struct builtin_table { struct builtin_chain chains[NF_INET_NUMHOOKS]; }; +enum nft_cache_level { + NFT_CL_NONE, + NFT_CL_TABLES, + NFT_CL_CHAINS, + NFT_CL_RULES +}; + struct nft_cache { struct nftnl_table_list *tables; struct { @@ -53,7 +60,7 @@ struct nft_handle { unsigned int cache_index; struct nft_cache __cache[2]; struct nft_cache *cache; - bool have_cache; + enum nft_cache_level cache_level; bool restore; bool noflush; int8_t config_done; -- 2.23.0