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

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