Blame SOURCES/0020-xtables-Implement-per-chain-rule-cache.patch

8cce6c
From 4c6357a568d3e079fa7246cc2aa1c46739a6a14c Mon Sep 17 00:00:00 2001
8cce6c
From: Phil Sutter <phil@nwl.cc>
8cce6c
Date: Thu, 20 Dec 2018 16:09:12 +0100
8cce6c
Subject: [PATCH] xtables: Implement per chain rule cache
8cce6c
8cce6c
Use recently introduced support for rules inside chains in libnftnl to
8cce6c
introduce a rule cache per chain instead of a global one.
8cce6c
8cce6c
A tricky bit is to decide if cache should be updated or not. Previously,
8cce6c
the global rule cache was populated just once and then reused unless
8cce6c
being flushed completely (via call to flush_rule_cache() with
8cce6c
NULL-pointer table argument). Resemble this behaviour by introducing a
8cce6c
boolean indicating cache status and fetch rules for all chains when
8cce6c
updating the chain cache in nft_chain_list_get().
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 947c51c95edbbf08d6b3c105177ac5cfa238aade)
8cce6c
Signed-off-by: Phil Sutter <psutter@redhat.com>
8cce6c
---
8cce6c
 iptables/nft.c | 386 +++++++++++++++++++++----------------------------
8cce6c
 iptables/nft.h |   2 +-
8cce6c
 2 files changed, 166 insertions(+), 222 deletions(-)
8cce6c
8cce6c
diff --git a/iptables/nft.c b/iptables/nft.c
8cce6c
index 1840561f2e531..842ed2b805bee 100644
8cce6c
--- a/iptables/nft.c
8cce6c
+++ b/iptables/nft.c
8cce6c
@@ -772,28 +772,15 @@ int nft_init(struct nft_handle *h, const struct builtin_table *t)
8cce6c
 
8cce6c
 static int __flush_rule_cache(struct nftnl_rule *r, void *data)
8cce6c
 {
8cce6c
-	const char *tablename = data;
8cce6c
-
8cce6c
-	if (!strcmp(nftnl_rule_get_str(r, NFTNL_RULE_TABLE), tablename)) {
8cce6c
-		nftnl_rule_list_del(r);
8cce6c
-		nftnl_rule_free(r);
8cce6c
-	}
8cce6c
+	nftnl_rule_list_del(r);
8cce6c
+	nftnl_rule_free(r);
8cce6c
 
8cce6c
 	return 0;
8cce6c
 }
8cce6c
 
8cce6c
-static void flush_rule_cache(struct nft_handle *h, const char *tablename)
8cce6c
+static void flush_rule_cache(struct nftnl_chain *c)
8cce6c
 {
8cce6c
-	if (!h->rule_cache)
8cce6c
-		return;
8cce6c
-
8cce6c
-	if (tablename) {
8cce6c
-		nftnl_rule_list_foreach(h->rule_cache, __flush_rule_cache,
8cce6c
-					(void *)tablename);
8cce6c
-	} else {
8cce6c
-		nftnl_rule_list_free(h->rule_cache);
8cce6c
-		h->rule_cache = NULL;
8cce6c
-	}
8cce6c
+	nftnl_rule_foreach(c, __flush_rule_cache, NULL);
8cce6c
 }
8cce6c
 
8cce6c
 static int __flush_chain_cache(struct nftnl_chain *c, void *data)
8cce6c
@@ -830,12 +817,12 @@ static void flush_chain_cache(struct nft_handle *h, const char *tablename)
8cce6c
 		nftnl_chain_list_free(h->table[i].chain_cache);
8cce6c
 		h->table[i].chain_cache = NULL;
8cce6c
 	}
8cce6c
+	h->have_cache = false;
8cce6c
 }
8cce6c
 
8cce6c
 void nft_fini(struct nft_handle *h)
8cce6c
 {
8cce6c
 	flush_chain_cache(h, NULL);
8cce6c
-	flush_rule_cache(h, NULL);
8cce6c
 	mnl_socket_close(h->nl);
8cce6c
 }
8cce6c
 
8cce6c
@@ -1195,12 +1182,14 @@ err:
8cce6c
 	return NULL;
8cce6c
 }
8cce6c
 
8cce6c
-static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h);
8cce6c
+static struct nftnl_chain *
8cce6c
+nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
8cce6c
 
8cce6c
 int
8cce6c
 nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
8cce6c
 		void *data, uint64_t handle, bool verbose)
8cce6c
 {
8cce6c
+	struct nftnl_chain *c;
8cce6c
 	struct nftnl_rule *r;
8cce6c
 	int type;
8cce6c
 
8cce6c
@@ -1228,10 +1217,9 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
8cce6c
 	if (verbose)
8cce6c
 		h->ops->print_rule(r, 0, FMT_PRINT_RULE);
8cce6c
 
8cce6c
-	if (!nft_rule_list_get(h))
8cce6c
-		return 0;
8cce6c
-
8cce6c
-	nftnl_rule_list_add_tail(r, h->rule_cache);
8cce6c
+	c = nft_chain_find(h, table, chain);
8cce6c
+	if (c)
8cce6c
+		nftnl_chain_rule_add_tail(r, c);
8cce6c
 
8cce6c
 	return 1;
8cce6c
 }
8cce6c
@@ -1328,58 +1316,75 @@ retry:
8cce6c
 
8cce6c
 static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
8cce6c
 {
8cce6c
+	struct nftnl_chain *c = data;
8cce6c
 	struct nftnl_rule *r;
8cce6c
-	struct nftnl_rule_list *list = data;
8cce6c
 
8cce6c
 	r = nftnl_rule_alloc();
8cce6c
 	if (r == NULL)
8cce6c
-		goto err;
8cce6c
-
8cce6c
-	if (nftnl_rule_nlmsg_parse(nlh, r) < 0)
8cce6c
-		goto out;
8cce6c
+		return MNL_CB_OK;
8cce6c
 
8cce6c
-	nftnl_rule_list_add_tail(r, list);
8cce6c
+	if (nftnl_rule_nlmsg_parse(nlh, r) < 0) {
8cce6c
+		nftnl_rule_free(r);
8cce6c
+		return MNL_CB_OK;
8cce6c
+	}
8cce6c
 
8cce6c
-	return MNL_CB_OK;
8cce6c
-out:
8cce6c
-	nftnl_rule_free(r);
8cce6c
-	nftnl_rule_list_free(list);
8cce6c
-err:
8cce6c
+	nftnl_chain_rule_add_tail(r, c);
8cce6c
 	return MNL_CB_OK;
8cce6c
 }
8cce6c
 
8cce6c
-static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h)
8cce6c
+static int nft_rule_list_update(struct nftnl_chain *c, void *data)
8cce6c
 {
8cce6c
+	struct nft_handle *h = data;
8cce6c
 	char buf[16536];
8cce6c
 	struct nlmsghdr *nlh;
8cce6c
-	struct nftnl_rule_list *list;
8cce6c
+	struct nftnl_rule *rule;
8cce6c
 	int ret;
8cce6c
 
8cce6c
-	if (h->rule_cache)
8cce6c
-		return h->rule_cache;
8cce6c
+	rule = nftnl_rule_alloc();
8cce6c
+	if (!rule)
8cce6c
+		return -1;
8cce6c
 
8cce6c
-retry:
8cce6c
-	list = nftnl_rule_list_alloc();
8cce6c
-	if (list == NULL)
8cce6c
-		return 0;
8cce6c
+	nftnl_rule_set_str(rule, NFTNL_RULE_TABLE,
8cce6c
+			   nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
8cce6c
+	nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN,
8cce6c
+			   nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
8cce6c
 
8cce6c
+retry:
8cce6c
 	nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
8cce6c
 					NLM_F_DUMP, h->seq);
8cce6c
+	nftnl_rule_nlmsg_build_payload(nlh, rule);
8cce6c
 
8cce6c
-	ret = mnl_talk(h, nlh, nftnl_rule_list_cb, list);
8cce6c
+	ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c);
8cce6c
 	if (ret < 0) {
8cce6c
+		flush_rule_cache(c);
8cce6c
+
8cce6c
 		if (errno == EINTR) {
8cce6c
 			assert(nft_restart(h) >= 0);
8cce6c
-			nftnl_rule_list_free(list);
8cce6c
 			goto retry;
8cce6c
 		}
8cce6c
-
8cce6c
-		nftnl_rule_list_free(list);
8cce6c
-		return NULL;
8cce6c
+		nftnl_rule_free(rule);
8cce6c
+		return -1;
8cce6c
 	}
8cce6c
 
8cce6c
-	h->rule_cache = list;
8cce6c
-	return list;
8cce6c
+	nftnl_rule_free(rule);
8cce6c
+	return 0;
8cce6c
+}
8cce6c
+
8cce6c
+static int fetch_rule_cache(struct nft_handle *h)
8cce6c
+{
8cce6c
+	int i;
8cce6c
+
8cce6c
+	for (i = 0; i < NFT_TABLE_MAX; i++) {
8cce6c
+		enum nft_table_type type = h->tables[i].type;
8cce6c
+
8cce6c
+		if (!h->tables[i].name)
8cce6c
+			continue;
8cce6c
+
8cce6c
+		if (nftnl_chain_list_foreach(h->table[type].chain_cache,
8cce6c
+					     nft_rule_list_update, h))
8cce6c
+			return -1;
8cce6c
+	}
8cce6c
+	return 0;
8cce6c
 }
8cce6c
 
8cce6c
 struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h,
8cce6c
@@ -1391,8 +1396,11 @@ struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h,
8cce6c
 	if (!t)
8cce6c
 		return NULL;
8cce6c
 
8cce6c
-	if (!h->table[t->type].chain_cache)
8cce6c
+	if (!h->have_cache) {
8cce6c
 		fetch_chain_cache(h);
8cce6c
+		fetch_rule_cache(h);
8cce6c
+		h->have_cache = true;
8cce6c
+	}
8cce6c
 
8cce6c
 	return h->table[t->type].chain_cache;
8cce6c
 }
8cce6c
@@ -1437,38 +1445,54 @@ int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list)
8cce6c
 	return 1;
8cce6c
 }
8cce6c
 
8cce6c
-int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
8cce6c
+static int nft_chain_save_rules(struct nft_handle *h,
8cce6c
+				struct nftnl_chain *c, unsigned int format)
8cce6c
 {
8cce6c
-	struct nftnl_rule_list *list;
8cce6c
-	struct nftnl_rule_list_iter *iter;
8cce6c
+	struct nftnl_rule_iter *iter;
8cce6c
 	struct nftnl_rule *r;
8cce6c
 
8cce6c
-	list = nft_rule_list_get(h);
8cce6c
-	if (list == NULL)
8cce6c
-		return 0;
8cce6c
-
8cce6c
-	iter = nftnl_rule_list_iter_create(list);
8cce6c
+	iter = nftnl_rule_iter_create(c);
8cce6c
 	if (iter == NULL)
8cce6c
-		return 0;
8cce6c
+		return 1;
8cce6c
 
8cce6c
-	r = nftnl_rule_list_iter_next(iter);
8cce6c
+	r = nftnl_rule_iter_next(iter);
8cce6c
 	while (r != NULL) {
8cce6c
-		const char *rule_table =
8cce6c
-			nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
8cce6c
+		nft_rule_print_save(r, NFT_RULE_APPEND, format);
8cce6c
+		r = nftnl_rule_iter_next(iter);
8cce6c
+	}
8cce6c
 
8cce6c
-		if (strcmp(table, rule_table) != 0)
8cce6c
-			goto next;
8cce6c
+	nftnl_rule_iter_destroy(iter);
8cce6c
+	return 0;
8cce6c
+}
8cce6c
 
8cce6c
-		nft_rule_print_save(r, NFT_RULE_APPEND, format);
8cce6c
+int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
8cce6c
+{
8cce6c
+	struct nftnl_chain_list_iter *iter;
8cce6c
+	struct nftnl_chain_list *list;
8cce6c
+	struct nftnl_chain *c;
8cce6c
+	int ret = 0;
8cce6c
 
8cce6c
-next:
8cce6c
-		r = nftnl_rule_list_iter_next(iter);
8cce6c
+	list = nft_chain_list_get(h, table);
8cce6c
+	if (!list)
8cce6c
+		return 0;
8cce6c
+
8cce6c
+	iter = nftnl_chain_list_iter_create(list);
8cce6c
+	if (!iter)
8cce6c
+		return 0;
8cce6c
+
8cce6c
+	c = nftnl_chain_list_iter_next(iter);
8cce6c
+	while (c) {
8cce6c
+		ret = nft_chain_save_rules(h, c, format);
8cce6c
+		if (ret != 0)
8cce6c
+			break;
8cce6c
+
8cce6c
+		c = nftnl_chain_list_iter_next(iter);
8cce6c
 	}
8cce6c
 
8cce6c
-	nftnl_rule_list_iter_destroy(iter);
8cce6c
+	nftnl_chain_list_iter_destroy(iter);
8cce6c
 
8cce6c
 	/* the core expects 1 for success and 0 for error */
8cce6c
-	return 1;
8cce6c
+	return ret == 0 ? 1 : 0;
8cce6c
 }
8cce6c
 
8cce6c
 static void
8cce6c
@@ -1567,6 +1591,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
8cce6c
 			fprintf(stdout, "Flushing chain `%s'\n", chain_name);
8cce6c
 
8cce6c
 		__nft_rule_flush(h, table, chain_name);
8cce6c
+		flush_rule_cache(c);
8cce6c
 
8cce6c
 		if (chain != NULL)
8cce6c
 			break;
8cce6c
@@ -1574,7 +1599,6 @@ next:
8cce6c
 		c = nftnl_chain_list_iter_next(iter);
8cce6c
 	}
8cce6c
 	nftnl_chain_list_iter_destroy(iter);
8cce6c
-	flush_rule_cache(h, table);
8cce6c
 err:
8cce6c
 	/* the core expects 1 for success and 0 for error */
8cce6c
 	return ret == 0 ? 1 : 0;
8cce6c
@@ -1898,7 +1922,6 @@ static int __nft_table_flush(struct nft_handle *h, const char *table)
8cce6c
 	h->table[_t->type].initialized = false;
8cce6c
 
8cce6c
 	flush_chain_cache(h, table);
8cce6c
-	flush_rule_cache(h, table);
8cce6c
 
8cce6c
 	return 0;
8cce6c
 }
8cce6c
@@ -1939,12 +1962,6 @@ next:
8cce6c
 		t = nftnl_table_list_iter_next(iter);
8cce6c
 	}
8cce6c
 
8cce6c
-	if (!h->rule_cache) {
8cce6c
-		h->rule_cache = nftnl_rule_list_alloc();
8cce6c
-		if (h->rule_cache == NULL)
8cce6c
-			return -1;
8cce6c
-	}
8cce6c
-
8cce6c
 err_table_iter:
8cce6c
 	nftnl_table_list_iter_destroy(iter);
8cce6c
 err_table_list:
8cce6c
@@ -1975,31 +1992,19 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
8cce6c
 }
8cce6c
 
8cce6c
 static struct nftnl_rule *
8cce6c
-nft_rule_find(struct nft_handle *h, struct nftnl_rule_list *list,
8cce6c
-	      const char *chain, const char *table, void *data, int rulenum)
8cce6c
+nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulenum)
8cce6c
 {
8cce6c
 	struct nftnl_rule *r;
8cce6c
-	struct nftnl_rule_list_iter *iter;
8cce6c
+	struct nftnl_rule_iter *iter;
8cce6c
 	int rule_ctr = 0;
8cce6c
 	bool found = false;
8cce6c
 
8cce6c
-	iter = nftnl_rule_list_iter_create(list);
8cce6c
+	iter = nftnl_rule_iter_create(c);
8cce6c
 	if (iter == NULL)
8cce6c
 		return 0;
8cce6c
 
8cce6c
-	r = nftnl_rule_list_iter_next(iter);
8cce6c
+	r = nftnl_rule_iter_next(iter);
8cce6c
 	while (r != NULL) {
8cce6c
-		const char *rule_table =
8cce6c
-			nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
8cce6c
-		const char *rule_chain =
8cce6c
-			nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
8cce6c
-
8cce6c
-		if (strcmp(table, rule_table) != 0 ||
8cce6c
-		    strcmp(chain, rule_chain) != 0) {
8cce6c
-			DEBUGP("different chain / table\n");
8cce6c
-			goto next;
8cce6c
-		}
8cce6c
-
8cce6c
 		if (rulenum >= 0) {
8cce6c
 			/* Delete by rule number case */
8cce6c
 			if (rule_ctr == rulenum) {
8cce6c
@@ -2012,11 +2017,10 @@ nft_rule_find(struct nft_handle *h, struct nftnl_rule_list *list,
8cce6c
 				break;
8cce6c
 		}
8cce6c
 		rule_ctr++;
8cce6c
-next:
8cce6c
-		r = nftnl_rule_list_iter_next(iter);
8cce6c
+		r = nftnl_rule_iter_next(iter);
8cce6c
 	}
8cce6c
 
8cce6c
-	nftnl_rule_list_iter_destroy(iter);
8cce6c
+	nftnl_rule_iter_destroy(iter);
8cce6c
 
8cce6c
 	return found ? r : NULL;
8cce6c
 }
8cce6c
@@ -2024,16 +2028,16 @@ next:
8cce6c
 int nft_rule_check(struct nft_handle *h, const char *chain,
8cce6c
 		   const char *table, void *data, bool verbose)
8cce6c
 {
8cce6c
-	struct nftnl_rule_list *list;
8cce6c
+	struct nftnl_chain *c;
8cce6c
 	struct nftnl_rule *r;
8cce6c
 
8cce6c
 	nft_fn = nft_rule_check;
8cce6c
 
8cce6c
-	list = nft_rule_list_get(h);
8cce6c
-	if (list == NULL)
8cce6c
+	c = nft_chain_find(h, table, chain);
8cce6c
+	if (!c)
8cce6c
 		return 0;
8cce6c
 
8cce6c
-	r = nft_rule_find(h, list, chain, table, data, -1);
8cce6c
+	r = nft_rule_find(h, c, data, -1);
8cce6c
 	if (r == NULL) {
8cce6c
 		errno = ENOENT;
8cce6c
 		return 0;
8cce6c
@@ -2048,16 +2052,18 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
8cce6c
 		    const char *table, void *data, bool verbose)
8cce6c
 {
8cce6c
 	int ret = 0;
8cce6c
+	struct nftnl_chain *c;
8cce6c
 	struct nftnl_rule *r;
8cce6c
-	struct nftnl_rule_list *list;
8cce6c
 
8cce6c
 	nft_fn = nft_rule_delete;
8cce6c
 
8cce6c
-	list = nft_rule_list_get(h);
8cce6c
-	if (list == NULL)
8cce6c
+	c = nft_chain_find(h, table, chain);
8cce6c
+	if (!c) {
8cce6c
+		errno = ENOENT;
8cce6c
 		return 0;
8cce6c
+	}
8cce6c
 
8cce6c
-	r = nft_rule_find(h, list, chain, table, data, -1);
8cce6c
+	r = nft_rule_find(h, c, data, -1);
8cce6c
 	if (r != NULL) {
8cce6c
 		ret =__nft_rule_del(h, r);
8cce6c
 		if (ret < 0)
8cce6c
@@ -2098,8 +2104,8 @@ nft_rule_add(struct nft_handle *h, const char *chain,
8cce6c
 int nft_rule_insert(struct nft_handle *h, const char *chain,
8cce6c
 		    const char *table, void *data, int rulenum, bool verbose)
8cce6c
 {
8cce6c
-	struct nftnl_rule_list *list = nft_rule_list_get(h);
8cce6c
 	struct nftnl_rule *r, *new_rule;
8cce6c
+	struct nftnl_chain *c;
8cce6c
 	uint64_t handle = 0;
8cce6c
 
8cce6c
 	/* If built-in chains don't exist for this table, create them */
8cce6c
@@ -2108,17 +2114,19 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
8cce6c
 
8cce6c
 	nft_fn = nft_rule_insert;
8cce6c
 
8cce6c
-	if (rulenum > 0) {
8cce6c
-		if (list == NULL)
8cce6c
-			goto err;
8cce6c
+	c = nft_chain_find(h, table, chain);
8cce6c
+	if (!c) {
8cce6c
+		errno = ENOENT;
8cce6c
+		goto err;
8cce6c
+	}
8cce6c
 
8cce6c
-		r = nft_rule_find(h, list, chain, table, data, rulenum);
8cce6c
+	if (rulenum > 0) {
8cce6c
+		r = nft_rule_find(h, c, data, rulenum);
8cce6c
 		if (r == NULL) {
8cce6c
 			/* special case: iptables allows to insert into
8cce6c
 			 * rule_count + 1 position.
8cce6c
 			 */
8cce6c
-			r = nft_rule_find(h, list, chain, table, data,
8cce6c
-					  rulenum - 1);
8cce6c
+			r = nft_rule_find(h, c, data, rulenum - 1);
8cce6c
 			if (r != NULL)
8cce6c
 				return nft_rule_append(h, chain, table, data,
8cce6c
 						       0, verbose);
8cce6c
@@ -2136,9 +2144,9 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
8cce6c
 		goto err;
8cce6c
 
8cce6c
 	if (handle)
8cce6c
-		nftnl_rule_list_insert_at(new_rule, r);
8cce6c
+		nftnl_chain_rule_insert_at(new_rule, r);
8cce6c
 	else
8cce6c
-		nftnl_rule_list_add(new_rule, h->rule_cache);
8cce6c
+		nftnl_chain_rule_add(new_rule, c);
8cce6c
 
8cce6c
 	return 1;
8cce6c
 err:
8cce6c
@@ -2149,16 +2157,18 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
8cce6c
 			const char *table, int rulenum, bool verbose)
8cce6c
 {
8cce6c
 	int ret = 0;
8cce6c
+	struct nftnl_chain *c;
8cce6c
 	struct nftnl_rule *r;
8cce6c
-	struct nftnl_rule_list *list;
8cce6c
 
8cce6c
 	nft_fn = nft_rule_delete_num;
8cce6c
 
8cce6c
-	list = nft_rule_list_get(h);
8cce6c
-	if (list == NULL)
8cce6c
+	c = nft_chain_find(h, table, chain);
8cce6c
+	if (!c) {
8cce6c
+		errno = ENOENT;
8cce6c
 		return 0;
8cce6c
+	}
8cce6c
 
8cce6c
-	r = nft_rule_find(h, list, chain, table, NULL, rulenum);
8cce6c
+	r = nft_rule_find(h, c, NULL, rulenum);
8cce6c
 	if (r != NULL) {
8cce6c
 		DEBUGP("deleting rule by number %d\n", rulenum);
8cce6c
 		ret = __nft_rule_del(h, r);
8cce6c
@@ -2174,16 +2184,18 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
8cce6c
 		     const char *table, void *data, int rulenum, bool verbose)
8cce6c
 {
8cce6c
 	int ret = 0;
8cce6c
+	struct nftnl_chain *c;
8cce6c
 	struct nftnl_rule *r;
8cce6c
-	struct nftnl_rule_list *list;
8cce6c
 
8cce6c
 	nft_fn = nft_rule_replace;
8cce6c
 
8cce6c
-	list = nft_rule_list_get(h);
8cce6c
-	if (list == NULL)
8cce6c
+	c = nft_chain_find(h, table, chain);
8cce6c
+	if (!c) {
8cce6c
+		errno = ENOENT;
8cce6c
 		return 0;
8cce6c
+	}
8cce6c
 
8cce6c
-	r = nft_rule_find(h, list, chain, table, data, rulenum);
8cce6c
+	r = nft_rule_find(h, c, data, rulenum);
8cce6c
 	if (r != NULL) {
8cce6c
 		DEBUGP("replacing rule with handle=%llu\n",
8cce6c
 			(unsigned long long)
8cce6c
@@ -2201,35 +2213,21 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
8cce6c
 }
8cce6c
 
8cce6c
 static int
8cce6c
-__nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
8cce6c
+__nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
8cce6c
 		int rulenum, unsigned int format,
8cce6c
 		void (*cb)(struct nftnl_rule *r, unsigned int num,
8cce6c
 			   unsigned int format))
8cce6c
 {
8cce6c
-	struct nftnl_rule_list *list;
8cce6c
-	struct nftnl_rule_list_iter *iter;
8cce6c
+	struct nftnl_rule_iter *iter;
8cce6c
 	struct nftnl_rule *r;
8cce6c
 	int rule_ctr = 0;
8cce6c
 
8cce6c
-	list = nft_rule_list_get(h);
8cce6c
-	if (list == NULL)
8cce6c
-		return 0;
8cce6c
-
8cce6c
-	iter = nftnl_rule_list_iter_create(list);
8cce6c
+	iter = nftnl_rule_iter_create(c);
8cce6c
 	if (iter == NULL)
8cce6c
 		return 0;
8cce6c
 
8cce6c
-	r = nftnl_rule_list_iter_next(iter);
8cce6c
+	r = nftnl_rule_iter_next(iter);
8cce6c
 	while (r != NULL) {
8cce6c
-		const char *rule_table =
8cce6c
-			nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
8cce6c
-		const char *rule_chain =
8cce6c
-			nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
8cce6c
-
8cce6c
-		if (strcmp(table, rule_table) != 0 ||
8cce6c
-		    strcmp(chain, rule_chain) != 0)
8cce6c
-			goto next;
8cce6c
-
8cce6c
 		rule_ctr++;
8cce6c
 
8cce6c
 		if (rulenum > 0 && rule_ctr != rulenum) {
8cce6c
@@ -2242,46 +2240,30 @@ __nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
8cce6c
 			break;
8cce6c
 
8cce6c
 next:
8cce6c
-		r = nftnl_rule_list_iter_next(iter);
8cce6c
+		r = nftnl_rule_iter_next(iter);
8cce6c
 	}
8cce6c
 
8cce6c
-	nftnl_rule_list_iter_destroy(iter);
8cce6c
+	nftnl_rule_iter_destroy(iter);
8cce6c
 	return 1;
8cce6c
 }
8cce6c
 
8cce6c
-static int nft_rule_count(struct nft_handle *h,
8cce6c
-			  const char *chain, const char *table)
8cce6c
+static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c)
8cce6c
 {
8cce6c
-	struct nftnl_rule_list_iter *iter;
8cce6c
-	struct nftnl_rule_list *list;
8cce6c
+	struct nftnl_rule_iter *iter;
8cce6c
 	struct nftnl_rule *r;
8cce6c
 	int rule_ctr = 0;
8cce6c
 
8cce6c
-	list = nft_rule_list_get(h);
8cce6c
-	if (list == NULL)
8cce6c
-		return 0;
8cce6c
-
8cce6c
-	iter = nftnl_rule_list_iter_create(list);
8cce6c
+	iter = nftnl_rule_iter_create(c);
8cce6c
 	if (iter == NULL)
8cce6c
 		return 0;
8cce6c
 
8cce6c
-	r = nftnl_rule_list_iter_next(iter);
8cce6c
+	r = nftnl_rule_iter_next(iter);
8cce6c
 	while (r != NULL) {
8cce6c
-		const char *rule_table =
8cce6c
-			nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
8cce6c
-		const char *rule_chain =
8cce6c
-			nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
8cce6c
-
8cce6c
-		if (strcmp(table, rule_table) != 0 ||
8cce6c
-		    strcmp(chain, rule_chain) != 0)
8cce6c
-			goto next;
8cce6c
-
8cce6c
 		rule_ctr++;
8cce6c
-next:
8cce6c
-		r = nftnl_rule_list_iter_next(iter);
8cce6c
+		r = nftnl_rule_iter_next(iter);
8cce6c
 	}
8cce6c
 
8cce6c
-	nftnl_rule_list_iter_destroy(iter);
8cce6c
+	nftnl_rule_iter_destroy(iter);
8cce6c
 	return rule_ctr;
8cce6c
 }
8cce6c
 
8cce6c
@@ -2314,8 +2296,11 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
8cce6c
 	}
8cce6c
 
8cce6c
 	if (chain && rulenum) {
8cce6c
-		__nft_rule_list(h, chain, table,
8cce6c
-				rulenum, format, ops->print_rule);
8cce6c
+		c = nft_chain_find(h, table, chain);
8cce6c
+		if (!c)
8cce6c
+			return 0;
8cce6c
+
8cce6c
+		__nft_rule_list(h, c, rulenum, format, ops->print_rule);
8cce6c
 		return 1;
8cce6c
 	}
8cce6c
 
8cce6c
@@ -2358,12 +2343,11 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
8cce6c
 		if (found)
8cce6c
 			printf("\n");
8cce6c
 
8cce6c
-		entries = nft_rule_count(h, chain_name, table);
8cce6c
+		entries = nft_rule_count(h, c);
8cce6c
 		ops->print_header(format, chain_name, policy_name[policy],
8cce6c
 				  &ctrs, basechain, refs - entries, entries);
8cce6c
 
8cce6c
-		__nft_rule_list(h, chain_name, table,
8cce6c
-				rulenum, format, ops->print_rule);
8cce6c
+		__nft_rule_list(h, c, rulenum, format, ops->print_rule);
8cce6c
 
8cce6c
 		found = true;
8cce6c
 
8cce6c
@@ -2484,8 +2468,7 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
8cce6c
 		if (chain && strcmp(chain, chain_name) != 0)
8cce6c
 			goto next;
8cce6c
 
8cce6c
-		ret = __nft_rule_list(h, chain_name, table, rulenum,
8cce6c
-				      format, list_save);
8cce6c
+		ret = __nft_rule_list(h, c, rulenum, format, list_save);
8cce6c
 
8cce6c
 		/* we printed the chain we wanted, stop processing. */
8cce6c
 		if (chain)
8cce6c
@@ -2503,17 +2486,17 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
8cce6c
 			   const char *table, int rulenum)
8cce6c
 {
8cce6c
 	struct iptables_command_state cs = {};
8cce6c
-	struct nftnl_rule_list *list;
8cce6c
+	struct nftnl_chain *c;
8cce6c
 	struct nftnl_rule *r;
8cce6c
 	int ret = 0;
8cce6c
 
8cce6c
 	nft_fn = nft_rule_delete;
8cce6c
 
8cce6c
-	list = nft_rule_list_get(h);
8cce6c
-	if (list == NULL)
8cce6c
+	c = nft_chain_find(h, table, chain);
8cce6c
+	if (!c)
8cce6c
 		return 0;
8cce6c
 
8cce6c
-	r = nft_rule_find(h, list, chain, table, NULL, rulenum);
8cce6c
+	r = nft_rule_find(h, c, NULL, rulenum);
8cce6c
 	if (r == NULL) {
8cce6c
 		errno = ENOENT;
8cce6c
 		ret = 1;
8cce6c
@@ -2982,38 +2965,19 @@ int nft_xtables_config_load(struct nft_handle *h, const char *filename,
8cce6c
 static void nft_chain_zero_rule_counters(struct nft_handle *h,
8cce6c
 					 struct nftnl_chain *c)
8cce6c
 {
8cce6c
-	struct nftnl_rule_list_iter *iter;
8cce6c
-	struct nftnl_rule_list *list;
8cce6c
-	const char *table_name;
8cce6c
-	const char *chain_name;
8cce6c
+	struct nftnl_rule_iter *iter;
8cce6c
 	struct nftnl_rule *r;
8cce6c
 
8cce6c
-	list = nft_rule_list_get(h);
8cce6c
-	if (list == NULL)
8cce6c
-		return;
8cce6c
-	iter = nftnl_rule_list_iter_create(list);
8cce6c
+	iter = nftnl_rule_iter_create(c);
8cce6c
 	if (iter == NULL)
8cce6c
 		return;
8cce6c
 
8cce6c
-	table_name = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
8cce6c
-	chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
8cce6c
-
8cce6c
-	r = nftnl_rule_list_iter_next(iter);
8cce6c
+	r = nftnl_rule_iter_next(iter);
8cce6c
 	while (r != NULL) {
8cce6c
 		struct nftnl_expr_iter *ei;
8cce6c
-		const char *table_chain;
8cce6c
-		const char *rule_chain;
8cce6c
 		struct nftnl_expr *e;
8cce6c
 		bool zero_needed;
8cce6c
 
8cce6c
-		table_chain = nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
8cce6c
-		if (strcmp(table_chain, table_name))
8cce6c
-			goto next;
8cce6c
-
8cce6c
-		rule_chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
8cce6c
-		if (strcmp(rule_chain, chain_name))
8cce6c
-			goto next;
8cce6c
-
8cce6c
 		ei = nftnl_expr_iter_create(r);
8cce6c
 		if (!ei)
8cce6c
 			break;
8cce6c
@@ -3044,11 +3008,10 @@ static void nft_chain_zero_rule_counters(struct nft_handle *h,
8cce6c
 			nftnl_rule_unset(r, NFTNL_RULE_POSITION);
8cce6c
 			batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r);
8cce6c
 		}
8cce6c
-next:
8cce6c
-		r = nftnl_rule_list_iter_next(iter);
8cce6c
+		r = nftnl_rule_iter_next(iter);
8cce6c
 	}
8cce6c
 
8cce6c
-	nftnl_rule_list_iter_destroy(iter);
8cce6c
+	nftnl_rule_iter_destroy(iter);
8cce6c
 }
8cce6c
 
8cce6c
 int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
8cce6c
@@ -3143,19 +3106,8 @@ static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data)
8cce6c
 	return -1;
8cce6c
 }
8cce6c
 
8cce6c
-struct nft_is_rule_compatible_data {
8cce6c
-	const char *tablename;
8cce6c
-};
8cce6c
-
8cce6c
 static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data)
8cce6c
 {
8cce6c
-	const char *table = nftnl_rule_get_str(rule, NFTNL_RULE_TABLE);
8cce6c
-	struct nft_is_rule_compatible_data *d = data;
8cce6c
-
8cce6c
-	/* ignore rules belonging to a different table */
8cce6c
-	if (strcmp(table, d->tablename))
8cce6c
-		return 0;
8cce6c
-
8cce6c
 	return nftnl_expr_foreach(rule, nft_is_expr_compatible, NULL);
8cce6c
 }
8cce6c
 
8cce6c
@@ -3167,6 +3119,9 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
8cce6c
 	enum nf_inet_hooks hook;
8cce6c
 	int i, prio;
8cce6c
 
8cce6c
+	if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL))
8cce6c
+		return -1;
8cce6c
+
8cce6c
 	if (!nft_chain_builtin(c))
8cce6c
 		return 0;
8cce6c
 
8cce6c
@@ -3210,11 +3165,7 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
8cce6c
 
8cce6c
 bool nft_is_table_compatible(struct nft_handle *h, const char *tablename)
8cce6c
 {
8cce6c
-	struct nft_is_rule_compatible_data rcd = {
8cce6c
-		.tablename = tablename
8cce6c
-	};
8cce6c
 	struct nftnl_chain_list *clist;
8cce6c
-	struct nftnl_rule_list *list;
8cce6c
 
8cce6c
 	clist = nft_chain_list_get(h, tablename);
8cce6c
 	if (clist == NULL)
8cce6c
@@ -3223,12 +3174,5 @@ bool nft_is_table_compatible(struct nft_handle *h, const char *tablename)
8cce6c
 	if (nftnl_chain_list_foreach(clist, nft_is_chain_compatible, h))
8cce6c
 		return false;
8cce6c
 
8cce6c
-	list = nft_rule_list_get(h);
8cce6c
-	if (list == NULL)
8cce6c
-		return true;
8cce6c
-
8cce6c
-	if (nftnl_rule_list_foreach(list, nft_is_rule_compatible, &rcd))
8cce6c
-		return false;
8cce6c
-
8cce6c
 	return true;
8cce6c
 }
8cce6c
diff --git a/iptables/nft.h b/iptables/nft.h
8cce6c
index bf60ab3943659..6568257feddc7 100644
8cce6c
--- a/iptables/nft.h
8cce6c
+++ b/iptables/nft.h
8cce6c
@@ -42,7 +42,7 @@ struct nft_handle {
8cce6c
 		struct nftnl_chain_list *chain_cache;
8cce6c
 		bool			initialized;
8cce6c
 	} table[NFT_TABLE_MAX];
8cce6c
-	struct nftnl_rule_list	*rule_cache;
8cce6c
+	bool			have_cache;
8cce6c
 	bool			restore;
8cce6c
 	int8_t			config_done;
8cce6c
 
8cce6c
-- 
8cce6c
2.20.1
8cce6c