Blame SOURCES/0005-xtables-Introduce-per-table-chain-caches.patch

8cce6c
From 6fb4660bde886f1f1ad5cfc55553b0a6fd98c2ed Mon Sep 17 00:00:00 2001
8cce6c
From: Phil Sutter <phil@nwl.cc>
8cce6c
Date: Thu, 15 Nov 2018 14:53:02 +0100
8cce6c
Subject: [PATCH] xtables: Introduce per table chain caches
8cce6c
8cce6c
Being able to omit the previously obligatory table name check when
8cce6c
iterating over the chain cache might help restore performance with large
8cce6c
rulesets in xtables-save and -restore.
8cce6c
8cce6c
There is one subtle quirk in the code: flush_chain_cache() did free the
8cce6c
global chain cache if not called with a table name but didn't if a table
8cce6c
name was given even if it emptied the chain cache. In other places,
8cce6c
chain_cache being non-NULL prevented a cache update from happening, so
8cce6c
this patch establishes the same behaviour (for each individual chain
8cce6c
cache) since otherwise unexpected cache updates lead to weird problems.
8cce6c
8cce6c
Signed-off-by: Phil Sutter <phil@nwl.cc>
8cce6c
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
8cce6c
(cherry picked from commit c58ecf9f8bcb7619a27ef8ffaddf847a562475a5)
8cce6c
Signed-off-by: Phil Sutter <psutter@redhat.com>
8cce6c
---
8cce6c
 iptables/nft-shared.h      |   3 +-
8cce6c
 iptables/nft.c             | 160 +++++++++++++++++--------------------
8cce6c
 iptables/nft.h             |  10 ++-
8cce6c
 iptables/xtables-restore.c |  16 ++--
8cce6c
 iptables/xtables-save.c    |  12 +--
8cce6c
 5 files changed, 95 insertions(+), 106 deletions(-)
8cce6c
8cce6c
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
8cce6c
index e3ecdb4d23df3..9a61d8d2863e3 100644
8cce6c
--- a/iptables/nft-shared.h
8cce6c
+++ b/iptables/nft-shared.h
8cce6c
@@ -251,7 +251,8 @@ struct nftnl_chain_list;
8cce6c
 
8cce6c
 struct nft_xt_restore_cb {
8cce6c
 	void (*table_new)(struct nft_handle *h, const char *table);
8cce6c
-	struct nftnl_chain_list *(*chain_list)(struct nft_handle *h);
8cce6c
+	struct nftnl_chain_list *(*chain_list)(struct nft_handle *h,
8cce6c
+					       const char *table);
8cce6c
 	void (*chain_del)(struct nftnl_chain_list *clist, const char *curtable,
8cce6c
 			  const char *chain);
8cce6c
 	int (*chain_user_flush)(struct nft_handle *h,
8cce6c
diff --git a/iptables/nft.c b/iptables/nft.c
8cce6c
index 6863d851e44c2..36529048a0ca6 100644
8cce6c
--- a/iptables/nft.c
8cce6c
+++ b/iptables/nft.c
8cce6c
@@ -673,15 +673,17 @@ nft_chain_builtin_find(struct builtin_table *t, const char *chain)
8cce6c
 static void nft_chain_builtin_init(struct nft_handle *h,
8cce6c
 				   struct builtin_table *table)
8cce6c
 {
8cce6c
-	struct nftnl_chain_list *list = nft_chain_list_get(h);
8cce6c
+	struct nftnl_chain_list *list = nft_chain_list_get(h, table->name);
8cce6c
 	struct nftnl_chain *c;
8cce6c
 	int i;
8cce6c
 
8cce6c
+	if (!list)
8cce6c
+		return;
8cce6c
+
8cce6c
 	/* Initialize built-in chains if they don't exist yet */
8cce6c
 	for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) {
8cce6c
 
8cce6c
-		c = nft_chain_list_find(list, table->name,
8cce6c
-					table->chains[i].name);
8cce6c
+		c = nft_chain_list_find(list, table->chains[i].name);
8cce6c
 		if (c != NULL)
8cce6c
 			continue;
8cce6c
 
8cce6c
@@ -782,27 +784,33 @@ static void flush_rule_cache(struct nft_handle *h, const char *tablename)
8cce6c
 
8cce6c
 static int __flush_chain_cache(struct nftnl_chain *c, void *data)
8cce6c
 {
8cce6c
-	const char *tablename = data;
8cce6c
-
8cce6c
-	if (!strcmp(nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), tablename)) {
8cce6c
-		nftnl_chain_list_del(c);
8cce6c
-		nftnl_chain_free(c);
8cce6c
-	}
8cce6c
+	nftnl_chain_list_del(c);
8cce6c
+	nftnl_chain_free(c);
8cce6c
 
8cce6c
 	return 0;
8cce6c
 }
8cce6c
 
8cce6c
 static void flush_chain_cache(struct nft_handle *h, const char *tablename)
8cce6c
 {
8cce6c
-	if (!h->chain_cache)
8cce6c
-		return;
8cce6c
+	int i;
8cce6c
 
8cce6c
-	if (tablename) {
8cce6c
-		nftnl_chain_list_foreach(h->chain_cache, __flush_chain_cache,
8cce6c
-					 (void *)tablename);
8cce6c
-	} else {
8cce6c
-		nftnl_chain_list_free(h->chain_cache);
8cce6c
-		h->chain_cache = NULL;
8cce6c
+	for (i = 0; i < NFT_TABLE_MAX; i++) {
8cce6c
+		if (h->tables[i].name == NULL)
8cce6c
+			continue;
8cce6c
+
8cce6c
+		if (tablename && strcmp(h->tables[i].name, tablename))
8cce6c
+			continue;
8cce6c
+
8cce6c
+		if (h->tables[i].chain_cache) {
8cce6c
+			if (tablename) {
8cce6c
+				nftnl_chain_list_foreach(h->tables[i].chain_cache,
8cce6c
+							 __flush_chain_cache, NULL);
8cce6c
+				break;
8cce6c
+			} else {
8cce6c
+				nftnl_chain_list_free(h->tables[i].chain_cache);
8cce6c
+				h->tables[i].chain_cache = NULL;
8cce6c
+			}
8cce6c
+		}
8cce6c
 	}
8cce6c
 }
8cce6c
 
8cce6c
@@ -1244,8 +1252,9 @@ nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type,
8cce6c
 
8cce6c
 static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
8cce6c
 {
8cce6c
+	struct nft_handle *h = data;
8cce6c
+	struct builtin_table *t;
8cce6c
 	struct nftnl_chain *c;
8cce6c
-	struct nftnl_chain_list *list = data;
8cce6c
 
8cce6c
 	c = nftnl_chain_alloc();
8cce6c
 	if (c == NULL)
8cce6c
@@ -1254,7 +1263,18 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
8cce6c
 	if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
8cce6c
 		goto out;
8cce6c
 
8cce6c
-	nftnl_chain_list_add_tail(c, list);
8cce6c
+	t = nft_table_builtin_find(h,
8cce6c
+			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
8cce6c
+	if (!t)
8cce6c
+		goto out;
8cce6c
+
8cce6c
+	if (!t->chain_cache) {
8cce6c
+		t->chain_cache = nftnl_chain_list_alloc();
8cce6c
+		if (!t->chain_cache)
8cce6c
+			goto out;
8cce6c
+	}
8cce6c
+
8cce6c
+	nftnl_chain_list_add_tail(c, t->chain_cache);
8cce6c
 
8cce6c
 	return MNL_CB_OK;
8cce6c
 out:
8cce6c
@@ -1263,35 +1283,34 @@ err:
8cce6c
 	return MNL_CB_OK;
8cce6c
 }
8cce6c
 
8cce6c
-struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h)
8cce6c
+struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h,
8cce6c
+					    const char *table)
8cce6c
 {
8cce6c
 	char buf[16536];
8cce6c
 	struct nlmsghdr *nlh;
8cce6c
-	struct nftnl_chain_list *list;
8cce6c
+	struct builtin_table *t;
8cce6c
 	int ret;
8cce6c
 
8cce6c
-	if (h->chain_cache)
8cce6c
-		return h->chain_cache;
8cce6c
-retry:
8cce6c
-	list = nftnl_chain_list_alloc();
8cce6c
-	if (list == NULL) {
8cce6c
-		errno = ENOMEM;
8cce6c
+	t = nft_table_builtin_find(h, table);
8cce6c
+	if (!t)
8cce6c
 		return NULL;
8cce6c
-	}
8cce6c
 
8cce6c
+	if (t->chain_cache)
8cce6c
+		return t->chain_cache;
8cce6c
+retry:
8cce6c
 	nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
8cce6c
 					NLM_F_DUMP, h->seq);
8cce6c
 
8cce6c
-	ret = mnl_talk(h, nlh, nftnl_chain_list_cb, list);
8cce6c
+	ret = mnl_talk(h, nlh, nftnl_chain_list_cb, h);
8cce6c
 	if (ret < 0 && errno == EINTR) {
8cce6c
 		assert(nft_restart(h) >= 0);
8cce6c
-		nftnl_chain_list_free(list);
8cce6c
 		goto retry;
8cce6c
 	}
8cce6c
 
8cce6c
-	h->chain_cache = list;
8cce6c
+	if (!t->chain_cache)
8cce6c
+		t->chain_cache = nftnl_chain_list_alloc();
8cce6c
 
8cce6c
-	return list;
8cce6c
+	return t->chain_cache;
8cce6c
 }
8cce6c
 
8cce6c
 static const char *policy_name[NF_ACCEPT+1] = {
8cce6c
@@ -1299,8 +1318,7 @@ static const char *policy_name[NF_ACCEPT+1] = {
8cce6c
 	[NF_ACCEPT] = "ACCEPT",
8cce6c
 };
8cce6c
 
8cce6c
-int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list,
8cce6c
-		   const char *table)
8cce6c
+int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list)
8cce6c
 {
8cce6c
 	struct nftnl_chain_list_iter *iter;
8cce6c
 	struct nft_family_ops *ops;
8cce6c
@@ -1314,13 +1332,8 @@ int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list,
8cce6c
 
8cce6c
 	c = nftnl_chain_list_iter_next(iter);
8cce6c
 	while (c != NULL) {
8cce6c
-		const char *chain_table =
8cce6c
-			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
8cce6c
 		const char *policy = NULL;
8cce6c
 
8cce6c
-		if (strcmp(table, chain_table) != 0)
8cce6c
-			goto next;
8cce6c
-
8cce6c
 		if (nft_chain_builtin(c)) {
8cce6c
 			uint32_t pol = NF_ACCEPT;
8cce6c
 
8cce6c
@@ -1331,7 +1344,7 @@ int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list,
8cce6c
 
8cce6c
 		if (ops->save_chain)
8cce6c
 			ops->save_chain(c, policy);
8cce6c
-next:
8cce6c
+
8cce6c
 		c = nftnl_chain_list_iter_next(iter);
8cce6c
 	}
8cce6c
 
8cce6c
@@ -1502,7 +1515,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
8cce6c
 
8cce6c
 	nft_fn = nft_rule_flush;
8cce6c
 
8cce6c
-	list = nft_chain_list_get(h);
8cce6c
+	list = nft_chain_list_get(h, table);
8cce6c
 	if (list == NULL) {
8cce6c
 		ret = 1;
8cce6c
 		goto err;
8cce6c
@@ -1516,21 +1529,16 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
8cce6c
 
8cce6c
 	c = nftnl_chain_list_iter_next(iter);
8cce6c
 	while (c != NULL) {
8cce6c
-		const char *table_name =
8cce6c
-			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
8cce6c
 		const char *chain_name =
8cce6c
 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
8cce6c
 
8cce6c
-		if (strcmp(table, table_name) != 0)
8cce6c
-			goto next;
8cce6c
-
8cce6c
 		if (chain != NULL && strcmp(chain, chain_name) != 0)
8cce6c
 			goto next;
8cce6c
 
8cce6c
 		if (verbose)
8cce6c
 			fprintf(stdout, "Flushing chain `%s'\n", chain_name);
8cce6c
 
8cce6c
-		__nft_rule_flush(h, table_name, chain_name);
8cce6c
+		__nft_rule_flush(h, table, chain_name);
8cce6c
 
8cce6c
 		if (chain != NULL)
8cce6c
 			break;
8cce6c
@@ -1546,6 +1554,7 @@ err:
8cce6c
 
8cce6c
 int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table)
8cce6c
 {
8cce6c
+	struct nftnl_chain_list *list;
8cce6c
 	struct nftnl_chain *c;
8cce6c
 	int ret;
8cce6c
 
8cce6c
@@ -1564,9 +1573,9 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
8cce6c
 
8cce6c
 	ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
8cce6c
 
8cce6c
-	nft_chain_list_get(h);
8cce6c
-
8cce6c
-	nftnl_chain_list_add(c, h->chain_cache);
8cce6c
+	list = nft_chain_list_get(h, table);
8cce6c
+	if (list)
8cce6c
+		nftnl_chain_list_add(c, list);
8cce6c
 
8cce6c
 	/* the core expects 1 for success and 0 for error */
8cce6c
 	return ret == 0 ? 1 : 0;
8cce6c
@@ -1588,7 +1597,7 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
8cce6c
 
8cce6c
 	nft_fn = nft_chain_user_del;
8cce6c
 
8cce6c
-	list = nft_chain_list_get(h);
8cce6c
+	list = nft_chain_list_get(h, table);
8cce6c
 	if (list == NULL)
8cce6c
 		goto err;
8cce6c
 
8cce6c
@@ -1598,8 +1607,6 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
8cce6c
 
8cce6c
 	c = nftnl_chain_list_iter_next(iter);
8cce6c
 	while (c != NULL) {
8cce6c
-		const char *table_name =
8cce6c
-			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
8cce6c
 		const char *chain_name =
8cce6c
 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
8cce6c
 
8cce6c
@@ -1607,9 +1614,6 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
8cce6c
 		if (nft_chain_builtin(c))
8cce6c
 			goto next;
8cce6c
 
8cce6c
-		if (strcmp(table, table_name) != 0)
8cce6c
-			goto next;
8cce6c
-
8cce6c
 		if (chain != NULL && strcmp(chain, chain_name) != 0)
8cce6c
 			goto next;
8cce6c
 
8cce6c
@@ -1644,8 +1648,7 @@ err:
8cce6c
 }
8cce6c
 
8cce6c
 struct nftnl_chain *
8cce6c
-nft_chain_list_find(struct nftnl_chain_list *list,
8cce6c
-		    const char *table, const char *chain)
8cce6c
+nft_chain_list_find(struct nftnl_chain_list *list, const char *chain)
8cce6c
 {
8cce6c
 	struct nftnl_chain_list_iter *iter;
8cce6c
 	struct nftnl_chain *c;
8cce6c
@@ -1656,14 +1659,9 @@ nft_chain_list_find(struct nftnl_chain_list *list,
8cce6c
 
8cce6c
 	c = nftnl_chain_list_iter_next(iter);
8cce6c
 	while (c != NULL) {
8cce6c
-		const char *table_name =
8cce6c
-			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
8cce6c
 		const char *chain_name =
8cce6c
 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
8cce6c
 
8cce6c
-		if (strcmp(table, table_name) != 0)
8cce6c
-			goto next;
8cce6c
-
8cce6c
 		if (strcmp(chain, chain_name) != 0)
8cce6c
 			goto next;
8cce6c
 
8cce6c
@@ -1681,11 +1679,11 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
8cce6c
 {
8cce6c
 	struct nftnl_chain_list *list;
8cce6c
 
8cce6c
-	list = nft_chain_list_get(h);
8cce6c
+	list = nft_chain_list_get(h, table);
8cce6c
 	if (list == NULL)
8cce6c
 		return NULL;
8cce6c
 
8cce6c
-	return nft_chain_list_find(list, table, chain);
8cce6c
+	return nft_chain_list_find(list, chain);
8cce6c
 }
8cce6c
 
8cce6c
 bool nft_chain_exists(struct nft_handle *h,
8cce6c
@@ -2297,7 +2295,9 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
8cce6c
 		return 1;
8cce6c
 	}
8cce6c
 
8cce6c
-	list = nft_chain_list_get(h);
8cce6c
+	list = nft_chain_list_get(h, table);
8cce6c
+	if (!list)
8cce6c
+		goto err; /* XXX: return 0 instead? */
8cce6c
 
8cce6c
 	iter = nftnl_chain_list_iter_create(list);
8cce6c
 	if (iter == NULL)
8cce6c
@@ -2308,8 +2308,6 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
8cce6c
 
8cce6c
 	c = nftnl_chain_list_iter_next(iter);
8cce6c
 	while (c != NULL) {
8cce6c
-		const char *chain_table =
8cce6c
-			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
8cce6c
 		const char *chain_name =
8cce6c
 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
8cce6c
 		uint32_t policy =
8cce6c
@@ -2326,8 +2324,6 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
8cce6c
 		if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM))
8cce6c
 			basechain = true;
8cce6c
 
8cce6c
-		if (strcmp(table, chain_table) != 0)
8cce6c
-			goto next;
8cce6c
 		if (chain) {
8cce6c
 			if (strcmp(chain, chain_name) != 0)
8cce6c
 				goto next;
8cce6c
@@ -2442,7 +2438,9 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
8cce6c
 		return 0;
8cce6c
 	}
8cce6c
 
8cce6c
-	list = nft_chain_list_get(h);
8cce6c
+	list = nft_chain_list_get(h, table);
8cce6c
+	if (!list)
8cce6c
+		goto err; /* XXX: correct? */
8cce6c
 
8cce6c
 	/* Dump policies and custom chains first */
8cce6c
 	if (!rulenum)
8cce6c
@@ -2460,13 +2458,9 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
8cce6c
 
8cce6c
 	c = nftnl_chain_list_iter_next(iter);
8cce6c
 	while (c != NULL) {
8cce6c
-		const char *chain_table =
8cce6c
-			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
8cce6c
 		const char *chain_name =
8cce6c
 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
8cce6c
 
8cce6c
-		if (strcmp(table, chain_table) != 0)
8cce6c
-			goto next;
8cce6c
 		if (chain && strcmp(chain, chain_name) != 0)
8cce6c
 			goto next;
8cce6c
 
8cce6c
@@ -3045,7 +3039,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
8cce6c
 	struct nftnl_chain *c;
8cce6c
 	int ret = 0;
8cce6c
 
8cce6c
-	list = nft_chain_list_get(h);
8cce6c
+	list = nft_chain_list_get(h, table);
8cce6c
 	if (list == NULL)
8cce6c
 		goto err;
8cce6c
 
8cce6c
@@ -3057,11 +3051,6 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
8cce6c
 	while (c != NULL) {
8cce6c
 		const char *chain_name =
8cce6c
 			nftnl_chain_get(c, NFTNL_CHAIN_NAME);
8cce6c
-		const char *chain_table =
8cce6c
-			nftnl_chain_get(c, NFTNL_CHAIN_TABLE);
8cce6c
-
8cce6c
-		if (strcmp(table, chain_table) != 0)
8cce6c
-			goto next;
8cce6c
 
8cce6c
 		if (chain != NULL && strcmp(chain, chain_name) != 0)
8cce6c
 			goto next;
8cce6c
@@ -3202,7 +3191,7 @@ static int nft_are_chains_compatible(struct nft_handle *h, const char *tablename
8cce6c
 	struct nftnl_chain *chain;
8cce6c
 	int ret = 0;
8cce6c
 
8cce6c
-	list = nft_chain_list_get(h);
8cce6c
+	list = nft_chain_list_get(h, tablename);
8cce6c
 	if (list == NULL)
8cce6c
 		return -1;
8cce6c
 
8cce6c
@@ -3212,12 +3201,7 @@ static int nft_are_chains_compatible(struct nft_handle *h, const char *tablename
8cce6c
 
8cce6c
 	chain = nftnl_chain_list_iter_next(iter);
8cce6c
 	while (chain != NULL) {
8cce6c
-		const char *chain_table;
8cce6c
-
8cce6c
-		chain_table = nftnl_chain_get_str(chain, NFTNL_CHAIN_TABLE);
8cce6c
-
8cce6c
-		if (strcmp(chain_table, tablename) ||
8cce6c
-		    !nft_chain_builtin(chain))
8cce6c
+		if (!nft_chain_builtin(chain))
8cce6c
 			goto next;
8cce6c
 
8cce6c
 		ret = nft_is_chain_compatible(h, chain);
8cce6c
diff --git a/iptables/nft.h b/iptables/nft.h
8cce6c
index 052105fc6f3cd..6229221bd51f7 100644
8cce6c
--- a/iptables/nft.h
8cce6c
+++ b/iptables/nft.h
8cce6c
@@ -25,6 +25,7 @@ struct builtin_table {
8cce6c
 	const char *name;
8cce6c
 	struct builtin_chain chains[NF_INET_NUMHOOKS];
8cce6c
 	bool initialized;
8cce6c
+	struct nftnl_chain_list *chain_cache;
8cce6c
 };
8cce6c
 
8cce6c
 struct nft_handle {
8cce6c
@@ -38,7 +39,6 @@ struct nft_handle {
8cce6c
 	struct list_head	err_list;
8cce6c
 	struct nft_family_ops	*ops;
8cce6c
 	struct builtin_table	*tables;
8cce6c
-	struct nftnl_chain_list	*chain_cache;
8cce6c
 	struct nftnl_rule_list	*rule_cache;
8cce6c
 	bool			restore;
8cce6c
 	int8_t			config_done;
8cce6c
@@ -78,9 +78,11 @@ struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *t
8cce6c
 struct nftnl_chain;
8cce6c
 
8cce6c
 int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters);
8cce6c
-struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h);
8cce6c
-struct nftnl_chain *nft_chain_list_find(struct nftnl_chain_list *list, const char *table, const char *chain);
8cce6c
-int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list, const char *table);
8cce6c
+struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h,
8cce6c
+					    const char *table);
8cce6c
+struct nftnl_chain *nft_chain_list_find(struct nftnl_chain_list *list,
8cce6c
+					const char *chain);
8cce6c
+int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list);
8cce6c
 int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table);
8cce6c
 int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose);
8cce6c
 int nft_chain_user_flush(struct nft_handle *h, struct nftnl_chain_list *list,
8cce6c
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
8cce6c
index f529774054215..a46a92955a01a 100644
8cce6c
--- a/iptables/xtables-restore.c
8cce6c
+++ b/iptables/xtables-restore.c
8cce6c
@@ -56,11 +56,12 @@ static void print_usage(const char *name, const char *version)
8cce6c
 			"	   [ --ipv6 ]\n", name);
8cce6c
 }
8cce6c
 
8cce6c
-static struct nftnl_chain_list *get_chain_list(struct nft_handle *h)
8cce6c
+static struct nftnl_chain_list *get_chain_list(struct nft_handle *h,
8cce6c
+					       const char *table)
8cce6c
 {
8cce6c
 	struct nftnl_chain_list *chain_list;
8cce6c
 
8cce6c
-	chain_list = nft_chain_list_get(h);
8cce6c
+	chain_list = nft_chain_list_get(h, table);
8cce6c
 	if (chain_list == NULL)
8cce6c
 		xtables_error(OTHER_PROBLEM, "cannot retrieve chain list\n");
8cce6c
 
8cce6c
@@ -72,7 +73,7 @@ static void chain_delete(struct nftnl_chain_list *clist, const char *curtable,
8cce6c
 {
8cce6c
 	struct nftnl_chain *chain_obj;
8cce6c
 
8cce6c
-	chain_obj = nft_chain_list_find(clist, curtable, chain);
8cce6c
+	chain_obj = nft_chain_list_find(clist, chain);
8cce6c
 	/* This chain has been found, delete from list. Later
8cce6c
 	 * on, unvisited chains will be purged out.
8cce6c
 	 */
8cce6c
@@ -112,9 +113,6 @@ void xtables_restore_parse(struct nft_handle *h,
8cce6c
 
8cce6c
 	line = 0;
8cce6c
 
8cce6c
-	if (cb->chain_list)
8cce6c
-		chain_list = cb->chain_list(h);
8cce6c
-
8cce6c
 	/* Grab standard input. */
8cce6c
 	while (fgets(buffer, sizeof(buffer), p->in)) {
8cce6c
 		int ret = 0;
8cce6c
@@ -165,6 +163,9 @@ void xtables_restore_parse(struct nft_handle *h,
8cce6c
 			if (p->tablename && (strcmp(p->tablename, table) != 0))
8cce6c
 				continue;
8cce6c
 
8cce6c
+			if (cb->chain_list)
8cce6c
+				chain_list = cb->chain_list(h, table);
8cce6c
+
8cce6c
 			if (noflush == 0) {
8cce6c
 				DEBUGP("Cleaning all chains of table '%s'\n",
8cce6c
 					table);
8cce6c
@@ -197,8 +198,7 @@ void xtables_restore_parse(struct nft_handle *h,
8cce6c
 				if (cb->chain_del)
8cce6c
 					cb->chain_del(chain_list, curtable->name,
8cce6c
 						      chain);
8cce6c
-			} else if (nft_chain_list_find(chain_list,
8cce6c
-						       curtable->name, chain)) {
8cce6c
+			} else if (nft_chain_list_find(chain_list, chain)) {
8cce6c
 				chain_exists = true;
8cce6c
 				/* Apparently -n still flushes existing user
8cce6c
 				 * defined chains that are redefined. Otherwise,
8cce6c
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
8cce6c
index bed3ee0318995..d121d50e180ff 100644
8cce6c
--- a/iptables/xtables-save.c
8cce6c
+++ b/iptables/xtables-save.c
8cce6c
@@ -73,7 +73,9 @@ __do_output(struct nft_handle *h, const char *tablename, bool counters)
8cce6c
 		return 0;
8cce6c
 	}
8cce6c
 
8cce6c
-	chain_list = nft_chain_list_get(h);
8cce6c
+	chain_list = nft_chain_list_get(h, tablename);
8cce6c
+	if (!chain_list)
8cce6c
+		return 0;
8cce6c
 
8cce6c
 	time_t now = time(NULL);
8cce6c
 
8cce6c
@@ -83,7 +85,7 @@ __do_output(struct nft_handle *h, const char *tablename, bool counters)
8cce6c
 
8cce6c
 	/* Dump out chain names first,
8cce6c
 	 * thereby preventing dependency conflicts */
8cce6c
-	nft_chain_save(h, chain_list, tablename);
8cce6c
+	nft_chain_save(h, chain_list);
8cce6c
 	nft_rule_save(h, tablename, counters ? 0 : FMT_NOCOUNTS);
8cce6c
 
8cce6c
 	now = time(NULL);
8cce6c
@@ -257,7 +259,7 @@ static int __ebt_save(struct nft_handle *h, const char *tablename, bool counters
8cce6c
 		return 0;
8cce6c
 	}
8cce6c
 
8cce6c
-	chain_list = nft_chain_list_get(h);
8cce6c
+	chain_list = nft_chain_list_get(h, tablename);
8cce6c
 
8cce6c
 	if (first) {
8cce6c
 		now = time(NULL);
8cce6c
@@ -272,7 +274,7 @@ static int __ebt_save(struct nft_handle *h, const char *tablename, bool counters
8cce6c
 
8cce6c
 	/* Dump out chain names first,
8cce6c
 	 * thereby preventing dependency conflicts */
8cce6c
-	nft_chain_save(h, chain_list, tablename);
8cce6c
+	nft_chain_save(h, chain_list);
8cce6c
 	nft_rule_save(h, tablename, format);
8cce6c
 	printf("\n");
8cce6c
 	return 0;
8cce6c
@@ -399,7 +401,7 @@ int xtables_arp_save_main(int argc, char **argv)
8cce6c
 	}
8cce6c
 
8cce6c
 	printf("*filter\n");
8cce6c
-	nft_chain_save(&h, nft_chain_list_get(&h), "filter");
8cce6c
+	nft_chain_save(&h, nft_chain_list_get(&h, "filter"));
8cce6c
 	nft_rule_save(&h, "filter", show_counters ? 0 : FMT_NOCOUNTS);
8cce6c
 	printf("\n");
8cce6c
 	nft_fini(&h);
8cce6c
-- 
8cce6c
2.20.1
8cce6c