diff mbox series

[xtables,3/4] xtables: rework rule cache logic

Message ID 20180528192739.10414-3-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
Perform incremental tracking on rule cache updates, instead of flushing
and resynchronizing with the kernel over and over again.

Note that there is no need to call flush_rule_cache() from
nft_rule_delete() and nft_rule_delete_num(), since __nft_rule_del()
already deletes the rule from the list.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 iptables/nft.c | 81 ++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 53 insertions(+), 28 deletions(-)
diff mbox series

Patch

diff --git a/iptables/nft.c b/iptables/nft.c
index 07801f973176..3cfd23c7cdab 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -683,13 +683,30 @@  int nft_init(struct nft_handle *h, struct builtin_table *t)
 	return 0;
 }
 
-static void flush_rule_cache(struct nft_handle *h)
+static int __flush_rule_cache(struct nftnl_rule *r, void *data)
+{
+	const char *tablename = data;
+
+	if (!strcmp(nftnl_rule_get_str(r, NFTNL_RULE_TABLE), tablename)) {
+		nftnl_rule_list_del(r);
+		nftnl_rule_free(r);
+	}
+
+	return 0;
+}
+
+static void flush_rule_cache(struct nft_handle *h, const char *tablename)
 {
 	if (!h->rule_cache)
 		return;
 
-	nftnl_rule_list_free(h->rule_cache);
-	h->rule_cache = NULL;
+	if (tablename) {
+		nftnl_rule_list_foreach(h->rule_cache, __flush_rule_cache,
+					(void *)tablename);
+	} else {
+		nftnl_rule_list_free(h->rule_cache);
+		h->rule_cache = NULL;
+	}
 }
 
 static int __flush_chain_cache(struct nftnl_chain *c, void *data)
@@ -721,7 +738,7 @@  static void flush_chain_cache(struct nft_handle *h, const char *tablename)
 void nft_fini(struct nft_handle *h)
 {
 	flush_chain_cache(h, NULL);
-	flush_rule_cache(h);
+	flush_rule_cache(h, NULL);
 	mnl_socket_close(h->nl);
 }
 
@@ -1038,6 +1055,8 @@  err:
 	return NULL;
 }
 
+static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h);
+
 int
 nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
 		void *data, uint64_t handle, bool verbose)
@@ -1064,7 +1083,10 @@  nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
 	if (batch_rule_add(h, type, r) < 0)
 		nftnl_rule_free(r);
 
-	flush_rule_cache(h);
+	nft_rule_list_get(h);
+
+	nftnl_rule_list_add_tail(r, h->rule_cache);
+
 	return 1;
 }
 
@@ -1407,9 +1429,9 @@  int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table)
 next:
 		c = nftnl_chain_list_iter_next(iter);
 	}
+	flush_rule_cache(h, table);
 
 	nftnl_chain_list_iter_destroy(iter);
-	flush_rule_cache(h);
 err:
 	/* the core expects 1 for success and 0 for error */
 	return ret == 0 ? 1 : 0;
@@ -1715,6 +1737,7 @@  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);
+	flush_rule_cache(h, table);
 
 	return 0;
 }
@@ -1755,6 +1778,10 @@  next:
 		t = nftnl_table_list_iter_next(iter);
 	}
 
+	h->rule_cache = nftnl_rule_list_alloc();
+	if (h->rule_cache == NULL)
+		return -1;
+
 err_table_iter:
 	nftnl_table_list_iter_destroy(iter);
 err_table_list:
@@ -1866,12 +1893,10 @@  int nft_rule_delete(struct nft_handle *h, const char *chain,
 	} else
 		errno = ENOENT;
 
-	flush_rule_cache(h);
-
 	return ret;
 }
 
-static int
+static struct nftnl_rule *
 nft_rule_add(struct nft_handle *h, const char *chain,
 	     const char *table, struct iptables_command_state *cs,
 	     uint64_t handle, bool verbose)
@@ -1880,25 +1905,24 @@  nft_rule_add(struct nft_handle *h, const char *chain,
 
 	r = nft_rule_new(h, chain, table, cs);
 	if (r == NULL)
-		return 0;
+		return NULL;
 
 	if (handle > 0)
 		nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle);
 
 	if (batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r) < 0) {
 		nftnl_rule_free(r);
-		return 0;
+		return NULL;
 	}
 
-	flush_rule_cache(h);
-	return 1;
+	return r;
 }
 
 int nft_rule_insert(struct nft_handle *h, const char *chain,
 		    const char *table, void *data, int rulenum, bool verbose)
 {
+	struct nftnl_rule *r, *new_rule;
 	struct nftnl_rule_list *list;
-	struct nftnl_rule *r;
 	uint64_t handle = 0;
 
 	/* If built-in chains don't exist for this table, create them */
@@ -1919,11 +1943,9 @@  int nft_rule_insert(struct nft_handle *h, const char *chain,
 			 */
 			r = nft_rule_find(h, list, chain, table, data,
 					  rulenum - 1);
-			if (r != NULL) {
-				flush_rule_cache(h);
+			if (r != NULL)
 				return nft_rule_append(h, chain, table, data,
 						       0, verbose);
-			}
 
 			errno = ENOENT;
 			goto err;
@@ -1931,13 +1953,21 @@  int nft_rule_insert(struct nft_handle *h, const char *chain,
 
 		handle = nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE);
 		DEBUGP("adding after rule handle %"PRIu64"\n", handle);
-
-		flush_rule_cache(h);
+	} else {
+		nft_rule_list_get(h);
 	}
 
-	return nft_rule_add(h, chain, table, data, handle, verbose);
+	new_rule = nft_rule_add(h, chain, table, data, handle, verbose);
+	if (!new_rule)
+		goto err;
+
+	if (handle)
+		nftnl_rule_list_insert_at(new_rule, r);
+	else
+		nftnl_rule_list_add(new_rule, h->rule_cache);
+
+	return 1;
 err:
-	flush_rule_cache(h);
 	return 0;
 }
 
@@ -1965,8 +1995,6 @@  int nft_rule_delete_num(struct nft_handle *h, const char *chain,
 	} else
 		errno = ENOENT;
 
-	flush_rule_cache(h);
-
 	return ret;
 }
 
@@ -1989,14 +2017,14 @@  int nft_rule_replace(struct nft_handle *h, const char *chain,
 			(unsigned long long)
 			nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
 
+		nftnl_rule_list_del(r);
+
 		ret = nft_rule_append(h, chain, table, data,
 				      nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE),
 				      verbose);
 	} else
 		errno = ENOENT;
 
-	flush_rule_cache(h);
-
 	return ret;
 }
 
@@ -2277,8 +2305,6 @@  int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
 			       false);
 
 error:
-	flush_rule_cache(h);
-
 	return ret;
 }
 
@@ -2316,7 +2342,6 @@  static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
 				       type, h->family, flags, seq);
 	nftnl_rule_nlmsg_build_payload(nlh, rule);
 	nft_rule_print_debug(rule, nlh);
-	nftnl_rule_free(rule);
 }
 
 static int nft_action(struct nft_handle *h, int action)