Hi Phil, On Mon, Sep 16, 2019 at 06:49:54PM +0200, Phil Sutter wrote: > When called without --noflush, don't fetch full ruleset from kernel but > merely list of tables and the current genid. Locally, initialize chain > lists and set have_cache to simulate an empty ruleset. > > Doing so reduces execution time significantly if a large ruleset exists > in kernel space. A simple test case consisting of a dump with 100,000 > rules can be restored within 15s on my testing VM. Restoring it a second > time took 21s before this patch and only 17s after it. > > Signed-off-by: Phil Sutter <phil@xxxxxx> > --- > iptables/nft.c | 27 ++++++++++++++++++++++++++- > iptables/nft.h | 1 + > iptables/xtables-restore.c | 7 +++++-- > 3 files changed, 32 insertions(+), 3 deletions(-) > > diff --git a/iptables/nft.c b/iptables/nft.c > index 7f0f9e1234ae4..820f3392dd495 100644 > --- a/iptables/nft.c > +++ b/iptables/nft.c > @@ -882,7 +882,8 @@ static int flush_cache(struct nft_cache *c, const struct builtin_table *tables, > nftnl_chain_list_free(c->table[i].chains); > c->table[i].chains = NULL; > } > - nftnl_table_list_free(c->tables); > + if (c->tables) > + nftnl_table_list_free(c->tables); > c->tables = NULL; > > return 1; > @@ -1617,6 +1618,30 @@ void nft_build_cache(struct nft_handle *h) > __nft_build_cache(h); > } > > +void nft_fake_cache(struct nft_handle *h) > +{ > + int i; > + > + if (h->have_cache) > + return; > + > + /* fetch tables so conditional table delete logic works */ > + if (!h->cache->tables) > + fetch_table_cache(h); > + > + for (i = 0; i < NFT_TABLE_MAX; i++) { > + enum nft_table_type type = h->tables[i].type; > + > + if (!h->tables[i].name || > + h->cache->table[type].chains) > + continue; > + > + h->cache->table[type].chains = nftnl_chain_list_alloc(); > + } > + mnl_genid_get(h, &h->nft_genid); > + h->have_cache = true; > +} Looking at patches from 8/24 onwards, I think it's time to introduce cache flags logic to iptables. In patch 9/14 there is a new field have_chain_cache. In patch 10/14 there is have_rule_cache. Then moving on, the logic is based on checking for this booleans and then checking if the caches are initialized or not. I think if we move towards cache flags logic (the flags tell us what if we need no cache, partial cache (only tables, tables + chains) or full cache. This would make this logic easier to understand and more maintainable.