diff mbox series

[xtables,2/4] xtables: add chain cache

Message ID 20180528192739.10414-2-pablo@netfilter.org
State Changes Requested
Delegated to: Pablo Neira
Headers show
Series [xtables,1/4] xtables: always initialize basechains on ruleset restore | expand

Commit Message

Pablo Neira Ayuso May 28, 2018, 7:27 p.m. UTC
So we don't have to dump the chain cache content over and over again.
Moreover, perform incremental updates on the chain cache to add and to
delete non-base chains.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 iptables/nft.c             | 82 ++++++++++++++++++++++++++++------------------
 iptables/nft.h             |  3 +-
 iptables/xtables-restore.c |  5 +--
 iptables/xtables-save.c    |  2 +-
 4 files changed, 54 insertions(+), 38 deletions(-)
diff mbox series

Patch

diff --git a/iptables/nft.c b/iptables/nft.c
index a04aa350a074..07801f973176 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -604,7 +604,7 @@  static void nft_chain_builtin_init(struct nft_handle *h,
 				   struct builtin_table *table)
 {
 	int i;
-	struct nftnl_chain_list *list = nft_chain_dump(h, NULL);
+	struct nftnl_chain_list *list = nft_chain_dump(h);
 	struct nftnl_chain *c;
 
 	/* Initialize built-in chains if they don't exist yet */
@@ -617,8 +617,6 @@  static void nft_chain_builtin_init(struct nft_handle *h,
 
 		nft_chain_builtin_add(h, table, &table->chains[i]);
 	}
-
-	nftnl_chain_list_free(list);
 }
 
 static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
@@ -694,8 +692,35 @@  static void flush_rule_cache(struct nft_handle *h)
 	h->rule_cache = NULL;
 }
 
+static int __flush_chain_cache(struct nftnl_chain *c, void *data)
+{
+	const char *tablename = data;
+
+	if (!strcmp(nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), tablename)) {
+		nftnl_chain_list_del(c);
+		nftnl_chain_free(c);
+	}
+
+	return 0;
+}
+
+static void flush_chain_cache(struct nft_handle *h, const char *tablename)
+{
+	if (!h->chain_cache)
+		return;
+
+	if (tablename) {
+		nftnl_chain_list_foreach(h->chain_cache, __flush_chain_cache,
+					 (void *)tablename);
+	} else {
+		nftnl_chain_list_free(h->chain_cache);
+		h->chain_cache = NULL;
+	}
+}
+
 void nft_fini(struct nft_handle *h)
 {
+	flush_chain_cache(h, NULL);
 	flush_rule_cache(h);
 	mnl_socket_close(h->nl);
 }
@@ -1093,14 +1118,15 @@  err:
 	return MNL_CB_OK;
 }
 
-static struct nftnl_chain_list *nftnl_chain_list_get(struct nft_handle *h,
-						     const char *tablename)
+static struct nftnl_chain_list *nftnl_chain_list_get(struct nft_handle *h)
 {
 	char buf[16536];
 	struct nlmsghdr *nlh;
 	struct nftnl_chain_list *list;
 	int ret;
 
+	if (h->chain_cache)
+		return h->chain_cache;
 retry:
 	list = nftnl_chain_list_alloc();
 	if (list == NULL) {
@@ -1110,15 +1136,6 @@  retry:
 
 	nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
 					NLM_F_DUMP, h->seq);
-	if (tablename) {
-		struct nftnl_chain *t = nftnl_chain_alloc();
-
-		if (t) {
-			nftnl_chain_set(t, NFTNL_CHAIN_TABLE, tablename);
-			nftnl_chain_nlmsg_build_payload(nlh, t);
-			nftnl_chain_free(t);
-		}
-	}
 
 	ret = mnl_talk(h, nlh, nftnl_chain_list_cb, list);
 	if (ret < 0 && errno == EINTR) {
@@ -1127,12 +1144,14 @@  retry:
 		goto retry;
 	}
 
+	h->chain_cache = list;
+
 	return list;
 }
 
-struct nftnl_chain_list *nft_chain_dump(struct nft_handle *h, const char *tablename)
+struct nftnl_chain_list *nft_chain_dump(struct nft_handle *h)
 {
-	return nftnl_chain_list_get(h, tablename);
+	return nftnl_chain_list_get(h);
 }
 
 static const char *policy_name[NF_ACCEPT+1] = {
@@ -1186,7 +1205,6 @@  next:
 	}
 
 	nftnl_chain_list_iter_destroy(iter);
-	nftnl_chain_list_free(list);
 
 	return 1;
 }
@@ -1359,7 +1377,7 @@  int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table)
 
 	nft_fn = nft_rule_flush;
 
-	list = nftnl_chain_list_get(h, table);
+	list = nftnl_chain_list_get(h);
 	if (list == NULL) {
 		ret = 0;
 		goto err;
@@ -1393,8 +1411,6 @@  next:
 	nftnl_chain_list_iter_destroy(iter);
 	flush_rule_cache(h);
 err:
-	nftnl_chain_list_free(list);
-
 	/* the core expects 1 for success and 0 for error */
 	return ret == 0 ? 1 : 0;
 }
@@ -1419,6 +1435,10 @@  int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
 
 	ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
 
+	nft_chain_dump(h);
+
+	nftnl_chain_list_add(c, h->chain_cache);
+
 	/* the core expects 1 for success and 0 for error */
 	return ret == 0 ? 1 : 0;
 }
@@ -1438,7 +1458,7 @@  int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *tabl
 
 	nft_fn = nft_chain_user_del;
 
-	list = nftnl_chain_list_get(h, table);
+	list = nftnl_chain_list_get(h);
 	if (list == NULL)
 		goto err;
 
@@ -1469,6 +1489,7 @@  int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *tabl
 			break;
 
 		deleted_ctr++;
+		nftnl_chain_list_del(c);
 
 		if (chain != NULL)
 			break;
@@ -1527,7 +1548,7 @@  nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
 {
 	struct nftnl_chain_list *list;
 
-	list = nftnl_chain_list_get(h, table);
+	list = nftnl_chain_list_get(h);
 	if (list == NULL)
 		return NULL;
 
@@ -1693,6 +1714,8 @@  static int __nft_table_flush(struct nft_handle *h, const char *table)
 
 	batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t);
 
+	flush_chain_cache(h, table);
+
 	return 0;
 }
 
@@ -2064,7 +2087,7 @@  int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
 		return 1;
 	}
 
-	list = nft_chain_dump(h, table);
+	list = nft_chain_dump(h);
 
 	iter = nftnl_chain_list_iter_create(list);
 	if (iter == NULL)
@@ -2118,8 +2141,6 @@  next:
 
 	nftnl_chain_list_iter_destroy(iter);
 err:
-	nftnl_chain_list_free(list);
-
 	return 1;
 }
 
@@ -2188,7 +2209,7 @@  int nft_rule_list_save(struct nft_handle *h, const char *chain,
 	struct nftnl_chain *c;
 	int ret = 1;
 
-	list = nft_chain_dump(h, table);
+	list = nft_chain_dump(h);
 
 	/* Dump policies and custom chains first */
 	if (!rulenum)
@@ -2223,8 +2244,6 @@  next:
 
 	nftnl_chain_list_iter_destroy(iter);
 err:
-	nftnl_chain_list_free(list);
-
 	return ret;
 }
 
@@ -2285,7 +2304,6 @@  static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
 					type, h->family, flags, seq);
 	nftnl_chain_nlmsg_build_payload(nlh, chain);
 	nft_chain_print_debug(chain, nlh);
-	nftnl_chain_free(chain);
 }
 
 static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
@@ -2654,7 +2672,7 @@  int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
 	struct nftnl_chain *c;
 	int ret = 0;
 
-	list = nftnl_chain_list_get(h, table);
+	list = nftnl_chain_list_get(h);
 	if (list == NULL)
 		goto err;
 
@@ -2799,7 +2817,7 @@  static int nft_are_chains_compatible(struct nft_handle *h, const char *tablename
 	struct nftnl_chain *chain;
 	int ret = 0;
 
-	list = nftnl_chain_list_get(h, tablename);
+	list = nftnl_chain_list_get(h);
 	if (list == NULL)
 		return -1;
 
@@ -2820,7 +2838,7 @@  next:
 	}
 
 	nftnl_chain_list_iter_destroy(iter);
-	nftnl_chain_list_free(list);
+
 	return ret;
 }
 
diff --git a/iptables/nft.h b/iptables/nft.h
index 515832d7e37b..7a775a8db7a2 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -36,6 +36,7 @@  struct nft_handle {
 	struct list_head	err_list;
 	struct nft_family_ops	*ops;
 	struct builtin_table	*tables;
+	struct nftnl_chain_list	*chain_cache;
 	struct nftnl_rule_list	*rule_cache;
 	bool			restore;
 };
@@ -67,7 +68,7 @@  int nft_table_flush(struct nft_handle *h, const char *table);
 struct nftnl_chain;
 
 int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters);
-struct nftnl_chain_list *nft_chain_dump(struct nft_handle *h, const char *table);
+struct nftnl_chain_list *nft_chain_dump(struct nft_handle *h);
 struct nftnl_chain *nft_chain_list_find(struct nftnl_chain_list *list, const char *table, const char *chain);
 int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list, const char *table);
 int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table);
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index d977dabfae50..db199218027b 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -169,7 +169,7 @@  static struct nftnl_chain_list *get_chain_list(struct nft_handle *h)
 {
 	struct nftnl_chain_list *chain_list;
 
-	chain_list = nft_chain_dump(h, NULL);
+	chain_list = nft_chain_dump(h);
 	if (chain_list == NULL)
 		xtables_error(OTHER_PROBLEM, "cannot retrieve chain list\n");
 
@@ -447,9 +447,6 @@  void xtables_restore_parse(struct nft_handle *h,
 				xt_params->program_name, line + 1);
 		exit(1);
 	}
-
-	if (chain_list)
-		nftnl_chain_list_free(chain_list);
 }
 
 static int
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index be98b8350aaa..8bcc31fd9d48 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -57,7 +57,7 @@  do_output(struct nft_handle *h, const char *tablename, bool counters)
 		return 0;
 	}
 
-	chain_list = nft_chain_dump(h, tablename);
+	chain_list = nft_chain_dump(h);
 
 	time_t now = time(NULL);