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; +} + static void __nft_flush_cache(struct nft_handle *h) { if (!h->cache_index) { diff --git a/iptables/nft.h b/iptables/nft.h index 43463d7f262e8..d9eb30a2a2413 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -74,6 +74,7 @@ int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh, int nft_init(struct nft_handle *h, const struct builtin_table *t); void nft_fini(struct nft_handle *h); void nft_build_cache(struct nft_handle *h); +void nft_fake_cache(struct nft_handle *h); /* * Operations with tables. diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index f930f5ba2d167..d1486afedc480 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -96,6 +96,11 @@ void xtables_restore_parse(struct nft_handle *h, line = 0; + if (h->noflush) + nft_build_cache(h); + else + nft_fake_cache(h); + /* Grab standard input. */ while (fgets(buffer, sizeof(buffer), p->in)) { int ret = 0; @@ -146,8 +151,6 @@ void xtables_restore_parse(struct nft_handle *h, if (p->tablename && (strcmp(p->tablename, table) != 0)) continue; - nft_build_cache(h); - if (h->noflush == 0) { DEBUGP("Cleaning all chains of table '%s'\n", table); -- 2.23.0