All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nft 00/18] cache updates,v2
@ 2021-04-29 23:42 Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 01/18] tests: shell: remove missing modules Pablo Neira Ayuso
                   ` (17 more replies)
  0 siblings, 18 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Hi,

This is another round of patches to update the cache infrastructure
in nftables:

1) Remove all nftables modules after running tests/shell.

2) Restore removal by 64-bit unique handle.

3) Consolidate cache infrastructure.

4) Add hashtable cache for remaining objects.

5) Track deletions on the cache.

Pablo Neira Ayuso (18):
  tests: shell: remove missing modules
  src: unbreak deletion by table handle
  rule: skip fuzzy lookup for unexisting 64-bit handle
  src: pass chain name to chain_cache_find()
  src: consolidate nft_cache infrastructure
  src: consolidate object cache infrastructure
  cache: add hashtable cache for object
  cache: add hashtable cache for flowtable
  cache: add set_cache_del() and use it
  evaluate: add set to the cache
  evaluate: add flowtable to the cache
  cache: missing table cache for several policy objects
  evaluate: add object to the cache
  cache: add hashtable cache for table
  evaluate: remove chain from cache on delete chain command
  evaluate: remove set from cache on delete set command
  evaluate: remove flowtable from cache on delete flowtable command
  evaluate: remove object from cache on delete object command

 include/cache.h                               |  60 ++-
 include/netlink.h                             |   2 +
 include/nftables.h                            |   8 +-
 include/rule.h                                |  31 +-
 src/cache.c                                   | 341 +++++++++++++++---
 src/cmd.c                                     |  17 +-
 src/evaluate.c                                | 275 +++++++++++---
 src/json.c                                    |  38 +-
 src/libnftables.c                             |  13 +-
 src/mnl.c                                     |   2 +-
 src/monitor.c                                 |  26 +-
 src/netlink.c                                 |  25 +-
 src/netlink_delinearize.c                     |   7 +-
 src/rule.c                                    | 170 ++++-----
 tests/shell/run-tests.sh                      |   5 +-
 .../testcases/cache/0008_delete_by_handle_0   |  20 +
 .../cache/0009_delete_by_handle_incorrect_0   |   8 +
 17 files changed, 738 insertions(+), 310 deletions(-)
 create mode 100755 tests/shell/testcases/cache/0008_delete_by_handle_0
 create mode 100755 tests/shell/testcases/cache/0009_delete_by_handle_incorrect_0

-- 
2.20.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH nft 01/18] tests: shell: remove missing modules
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 02/18] src: unbreak deletion by table handle Pablo Neira Ayuso
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Update run-tests.sh to remove the following modules:

- nft_reject_netdev
- nft_xfrm
- nft_synproxy

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 tests/shell/run-tests.sh | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/tests/shell/run-tests.sh b/tests/shell/run-tests.sh
index 943f88776fda..349ec6cb1b16 100755
--- a/tests/shell/run-tests.sh
+++ b/tests/shell/run-tests.sh
@@ -90,10 +90,11 @@ kernel_cleanup() {
 	nft_chain_nat \
 	nft_chain_route_ipv4 nft_chain_route_ipv6 \
 	nft_dup_netdev nft_fwd_netdev \
-	nft_reject nft_reject_inet \
+	nft_reject nft_reject_inet nft_reject_netdev \
 	nf_tables_set nf_tables \
 	nf_flow_table nf_flow_table_ipv4 nf_flow_tables_ipv6 \
-	nf_flow_table_inet nft_flow_offload
+	nf_flow_table_inet nft_flow_offload \
+	nft_xfrm
 }
 
 find_tests() {
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 02/18] src: unbreak deletion by table handle
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 01/18] tests: shell: remove missing modules Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 03/18] rule: skip fuzzy lookup for unexisting 64-bit handle Pablo Neira Ayuso
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Use NFTA_TABLE_HANDLE instead of NFTA_TABLE_NAME to refer to the
table 64-bit unique handle.

Fixes: 7840b9224d5b ("evaluate: remove table from cache on delete table")
Fixes: f8aec603aa7e ("src: initial extended netlink error reporting")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/evaluate.c                                |  3 +++
 src/mnl.c                                     |  2 +-
 .../testcases/cache/0008_delete_by_handle_0   | 20 +++++++++++++++++++
 3 files changed, 24 insertions(+), 1 deletion(-)
 create mode 100755 tests/shell/testcases/cache/0008_delete_by_handle_0

diff --git a/src/evaluate.c b/src/evaluate.c
index a6bb1792c58a..c52309f46f59 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4335,6 +4335,9 @@ static void table_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
 {
 	struct table *table;
 
+	if (!cmd->handle.table.name)
+		return;
+
 	table = table_lookup(&cmd->handle, &ctx->nft->cache);
 	if (!table)
 		return;
diff --git a/src/mnl.c b/src/mnl.c
index d5ea87d8d609..1a8e8105707b 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -960,7 +960,7 @@ int mnl_nft_table_del(struct netlink_ctx *ctx, struct cmd *cmd)
 		mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, cmd->handle.table.name);
 	} else if (cmd->handle.handle.id) {
 		cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
-		mnl_attr_put_u64(nlh, NFTA_TABLE_NAME,
+		mnl_attr_put_u64(nlh, NFTA_TABLE_HANDLE,
 				 htobe64(cmd->handle.handle.id));
 	}
 	nftnl_table_nlmsg_build_payload(nlh, nlt);
diff --git a/tests/shell/testcases/cache/0008_delete_by_handle_0 b/tests/shell/testcases/cache/0008_delete_by_handle_0
new file mode 100755
index 000000000000..24b2607b236f
--- /dev/null
+++ b/tests/shell/testcases/cache/0008_delete_by_handle_0
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT delete table handle 1
+
+$NFT add table t
+
+$NFT add chain t c
+$NFT delete chain t handle 1
+
+$NFT add set t s { type ipv4_addr\; }
+$NFT delete set t handle 2
+
+$NFT add flowtable t f { hook ingress priority 0\; }
+$NFT delete flowtable t handle 4
+
+$NFT add counter t x
+$NFT delete counter t handle 5
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 03/18] rule: skip fuzzy lookup for unexisting 64-bit handle
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 01/18] tests: shell: remove missing modules Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 02/18] src: unbreak deletion by table handle Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 04/18] src: pass chain name to chain_cache_find() Pablo Neira Ayuso
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Deletion by handle, if incorrect, should not exercise the misspell
lookup functions.

Fixes: 3a0e07106f66 ("src: combine extended netlink error reporting with mispelling support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/cmd.c                                         | 15 +++++++++++++++
 .../cache/0009_delete_by_handle_incorrect_0       |  8 ++++++++
 2 files changed, 23 insertions(+)
 create mode 100755 tests/shell/testcases/cache/0009_delete_by_handle_incorrect_0

diff --git a/src/cmd.c b/src/cmd.c
index 9cb5b6a3f33d..c04efce3801a 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -14,6 +14,9 @@ static int nft_cmd_enoent_table(struct netlink_ctx *ctx, const struct cmd *cmd,
 {
 	struct table *table;
 
+	if (!cmd->handle.table.name)
+		return 0;
+
 	table = table_lookup_fuzzy(&cmd->handle, &ctx->nft->cache);
 	if (!table)
 		return 0;
@@ -30,6 +33,9 @@ static int nft_cmd_enoent_chain(struct netlink_ctx *ctx, const struct cmd *cmd,
 	const struct table *table;
 	struct chain *chain;
 
+	if (!cmd->handle.chain.name)
+		return 0;
+
 	chain = chain_lookup_fuzzy(&cmd->handle, &ctx->nft->cache, &table);
 	if (!chain)
 		return 0;
@@ -81,6 +87,9 @@ static int nft_cmd_enoent_set(struct netlink_ctx *ctx, const struct cmd *cmd,
 	const struct table *table;
 	struct set *set;
 
+	if (!cmd->handle.set.name)
+		return 0;
+
 	set = set_lookup_fuzzy(cmd->handle.set.name, &ctx->nft->cache, &table);
 	if (!set)
 		return 0;
@@ -100,6 +109,9 @@ static int nft_cmd_enoent_obj(struct netlink_ctx *ctx, const struct cmd *cmd,
 	const struct table *table;
 	struct obj *obj;
 
+	if (!cmd->handle.obj.name)
+		return 0;
+
 	obj = obj_lookup_fuzzy(cmd->handle.obj.name, &ctx->nft->cache, &table);
 	if (!obj)
 		return 0;
@@ -118,6 +130,9 @@ static int nft_cmd_enoent_flowtable(struct netlink_ctx *ctx,
 	const struct table *table;
 	struct flowtable *ft;
 
+	if (!cmd->handle.flowtable.name)
+		return 0;
+
 	ft = flowtable_lookup_fuzzy(cmd->handle.flowtable.name,
 				    &ctx->nft->cache, &table);
 	if (!ft)
diff --git a/tests/shell/testcases/cache/0009_delete_by_handle_incorrect_0 b/tests/shell/testcases/cache/0009_delete_by_handle_incorrect_0
new file mode 100755
index 000000000000..f0bb02a636ee
--- /dev/null
+++ b/tests/shell/testcases/cache/0009_delete_by_handle_incorrect_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+$NFT delete table handle 4000 && exit 1
+$NFT delete chain t handle 4000 && exit 1
+$NFT delete set t handle 4000 && exit 1
+$NFT delete flowtable t handle 4000 && exit 1
+$NFT delete counter t handle 4000 && exit 1
+exit 0
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 04/18] src: pass chain name to chain_cache_find()
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (2 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 03/18] rule: skip fuzzy lookup for unexisting 64-bit handle Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 05/18] src: consolidate nft_cache infrastructure Pablo Neira Ayuso
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

You can identify chains through the unique handle in deletions, update
this interface to take a string instead of the handle to prepare for
the introduction of 64-bit handle chain lookups.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/cache.h |  3 +--
 src/cache.c     |  9 ++++-----
 src/evaluate.c  | 10 +++++-----
 src/netlink.c   |  2 +-
 src/rule.c      |  2 +-
 5 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/include/cache.h b/include/cache.h
index f500e1b19e45..0009276701a3 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -57,8 +57,7 @@ int cache_update(struct nft_ctx *nft, unsigned int flags, struct list_head *msgs
 void cache_release(struct nft_cache *cache);
 
 void chain_cache_add(struct chain *chain, struct table *table);
-struct chain *chain_cache_find(const struct table *table,
-			       const struct handle *handle);
+struct chain *chain_cache_find(const struct table *table, const char *name);
 void set_cache_add(struct set *set, struct table *table);
 struct set *set_cache_find(const struct table *table, const char *name);
 
diff --git a/src/cache.c b/src/cache.c
index f032171a95ff..b38f3b84eda6 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -244,15 +244,14 @@ void chain_cache_add(struct chain *chain, struct table *table)
 	list_add_tail(&chain->cache_list, &table->cache_chain);
 }
 
-struct chain *chain_cache_find(const struct table *table,
-			       const struct handle *handle)
+struct chain *chain_cache_find(const struct table *table, const char *name)
 {
 	struct chain *chain;
 	uint32_t hash;
 
-	hash = djb_hash(handle->chain.name) % NFT_CACHE_HSIZE;
+	hash = djb_hash(name) % NFT_CACHE_HSIZE;
 	list_for_each_entry(chain, &table->cache_chain_ht[hash], cache_hlist) {
-		if (!strcmp(chain->handle.chain.name, handle->chain.name))
+		if (!strcmp(chain->handle.chain.name, name))
 			return chain;
 	}
 
@@ -421,7 +420,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
 		if (flags & NFT_CACHE_RULE_BIT) {
 			ret = netlink_list_rules(ctx, &table->handle);
 			list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
-				chain = chain_cache_find(table, &rule->handle);
+				chain = chain_cache_find(table, rule->handle.chain.name);
 				if (!chain)
 					chain = chain_binding_lookup(table,
 							rule->handle.chain.name);
diff --git a/src/evaluate.c b/src/evaluate.c
index c52309f46f59..2c8a649f5392 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4002,7 +4002,7 @@ static int rule_cache_update(struct eval_ctx *ctx, enum cmd_ops op)
 	if (!table)
 		return table_not_found(ctx);
 
-	chain = chain_cache_find(table, &rule->handle);
+	chain = chain_cache_find(table, rule->handle.chain.name);
 	if (!chain)
 		return chain_not_found(ctx);
 
@@ -4145,14 +4145,14 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
 		return table_not_found(ctx);
 
 	if (chain == NULL) {
-		if (chain_cache_find(table, &ctx->cmd->handle) == NULL) {
+		if (!chain_cache_find(table, ctx->cmd->handle.chain.name)) {
 			chain = chain_alloc(NULL);
 			handle_merge(&chain->handle, &ctx->cmd->handle);
 			chain_cache_add(chain, table);
 		}
 		return 0;
 	} else if (!(chain->flags & CHAIN_F_BINDING)) {
-		if (chain_cache_find(table, &chain->handle) == NULL)
+		if (!chain_cache_find(table, chain->handle.chain.name))
 			chain_cache_add(chain_get(chain), table);
 	}
 
@@ -4482,7 +4482,7 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
 		if (table == NULL)
 			return table_not_found(ctx);
 
-		if (chain_cache_find(table, &cmd->handle) == NULL)
+		if (!chain_cache_find(table, cmd->handle.chain.name))
 			return chain_not_found(ctx);
 
 		return 0;
@@ -4642,7 +4642,7 @@ static int cmd_evaluate_rename(struct eval_ctx *ctx, struct cmd *cmd)
 		if (table == NULL)
 			return table_not_found(ctx);
 
-		if (chain_cache_find(table, &ctx->cmd->handle) == NULL)
+		if (!chain_cache_find(table, ctx->cmd->handle.chain.name))
 			return chain_not_found(ctx);
 
 		break;
diff --git a/src/netlink.c b/src/netlink.c
index e8b016096b67..123525570c39 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1718,7 +1718,7 @@ static struct rule *trace_lookup_rule(const struct nftnl_trace *nlt,
 	if (!table)
 		return NULL;
 
-	chain = chain_cache_find(table, &h);
+	chain = chain_cache_find(table, h.chain.name);
 	if (!chain)
 		return NULL;
 
diff --git a/src/rule.c b/src/rule.c
index 2c6292c4e173..fac8d22a85ee 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -2608,7 +2608,7 @@ static int do_command_rename(struct netlink_ctx *ctx, struct cmd *cmd)
 
 	switch (cmd->obj) {
 	case CMD_OBJ_CHAIN:
-		chain = chain_cache_find(table, &cmd->handle);
+		chain = chain_cache_find(table, cmd->handle.chain.name);
 
 		return mnl_nft_chain_rename(ctx, cmd, chain);
 	default:
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 05/18] src: consolidate nft_cache infrastructure
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (3 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 04/18] src: pass chain name to chain_cache_find() Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 06/18] src: consolidate object cache infrastructure Pablo Neira Ayuso
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

- prepend nft_ prefix to nft_cache API and internal functions
- move declarations to cache.h (and remove redundant declarations)
- move struct nft_cache definition to cache.h

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/cache.h    | 23 +++++++++++++++++------
 include/nftables.h |  8 +-------
 include/rule.h     |  6 ------
 src/cache.c        | 35 ++++++++++++++++++-----------------
 src/cmd.c          |  2 +-
 src/evaluate.c     |  2 +-
 src/libnftables.c  | 10 +++++-----
 7 files changed, 43 insertions(+), 43 deletions(-)

diff --git a/include/cache.h b/include/cache.h
index 0009276701a3..987b122bc4fb 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -1,6 +1,8 @@
 #ifndef _NFT_CACHE_H_
 #define _NFT_CACHE_H_
 
+#include <string.h>
+
 enum cache_level_bits {
 	NFT_CACHE_TABLE_BIT	= (1 << 0),
 	NFT_CACHE_CHAIN_BIT	= (1 << 1),
@@ -35,6 +37,21 @@ enum cache_level_flags {
 	NFT_CACHE_FLUSHED	= (1 << 31),
 };
 
+struct nft_cache {
+	uint32_t		genid;
+	struct list_head	list;
+	uint32_t		seqnum;
+	uint32_t		flags;
+};
+
+enum cmd_ops;
+
+unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds);
+int nft_cache_update(struct nft_ctx *ctx, enum cmd_ops cmd,
+		     struct list_head *msgs);
+bool nft_cache_needs_update(struct nft_cache *cache);
+void nft_cache_release(struct nft_cache *cache);
+
 static inline uint32_t djb_hash(const char *key)
 {
 	uint32_t i, hash = 5381;
@@ -47,14 +64,8 @@ static inline uint32_t djb_hash(const char *key)
 
 #define NFT_CACHE_HSIZE 8192
 
-struct netlink_ctx;
 struct table;
 struct chain;
-struct handle;
-
-int cache_init(struct netlink_ctx *ctx, unsigned int flags);
-int cache_update(struct nft_ctx *nft, unsigned int flags, struct list_head *msgs);
-void cache_release(struct nft_cache *cache);
 
 void chain_cache_add(struct chain *chain, struct table *table);
 struct chain *chain_cache_find(const struct table *table, const char *name);
diff --git a/include/nftables.h b/include/nftables.h
index 9095ff3d0b79..f239fcf0e1f4 100644
--- a/include/nftables.h
+++ b/include/nftables.h
@@ -5,6 +5,7 @@
 #include <stdarg.h>
 #include <limits.h>
 #include <utils.h>
+#include <cache.h>
 #include <nftables/libnftables.h>
 
 struct cookie {
@@ -95,13 +96,6 @@ static inline bool nft_output_terse(const struct output_ctx *octx)
 	return octx->flags & NFT_CTX_OUTPUT_TERSE;
 }
 
-struct nft_cache {
-	uint32_t		genid;
-	struct list_head	list;
-	uint32_t		seqnum;
-	uint32_t		flags;
-};
-
 struct mnl_socket;
 struct parser_state;
 struct scope;
diff --git a/include/rule.h b/include/rule.h
index 90c01e9014c8..7896eafec137 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -771,12 +771,6 @@ extern struct error_record *rule_postprocess(struct rule *rule);
 struct netlink_ctx;
 extern int do_command(struct netlink_ctx *ctx, struct cmd *cmd);
 
-extern unsigned int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds);
-extern int cache_update(struct nft_ctx *ctx, enum cmd_ops cmd,
-			struct list_head *msgs);
-extern bool cache_needs_update(struct nft_cache *cache);
-extern void cache_release(struct nft_cache *cache);
-
 struct timeout_protocol {
 	uint32_t array_size;
 	const char *const *state_to_name;
diff --git a/src/cache.c b/src/cache.c
index b38f3b84eda6..53dbaaba8e20 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -113,7 +113,7 @@ static unsigned int evaluate_cache_rename(struct cmd *cmd, unsigned int flags)
 	return flags;
 }
 
-unsigned int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
+unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
 {
 	unsigned int flags = NFT_CACHE_EMPTY;
 	struct cmd *cmd;
@@ -445,7 +445,7 @@ cache_fails:
 	return ret;
 }
 
-int cache_init(struct netlink_ctx *ctx, unsigned int flags)
+static int nft_cache_init(struct netlink_ctx *ctx, unsigned int flags)
 {
 	struct handle handle = {
 		.family = NFPROTO_UNSPEC,
@@ -466,27 +466,28 @@ int cache_init(struct netlink_ctx *ctx, unsigned int flags)
 	return 0;
 }
 
-static bool cache_is_complete(struct nft_cache *cache, unsigned int flags)
+static bool nft_cache_is_complete(struct nft_cache *cache, unsigned int flags)
 {
 	return (cache->flags & flags) == flags;
 }
 
-static bool cache_needs_refresh(struct nft_cache *cache)
+static bool nft_cache_needs_refresh(struct nft_cache *cache)
 {
 	return cache->flags & NFT_CACHE_REFRESH;
 }
 
-static bool cache_is_updated(struct nft_cache *cache, uint16_t genid)
+static bool nft_cache_is_updated(struct nft_cache *cache, uint16_t genid)
 {
 	return genid && genid == cache->genid;
 }
 
-bool cache_needs_update(struct nft_cache *cache)
+bool nft_cache_needs_update(struct nft_cache *cache)
 {
 	return cache->flags & NFT_CACHE_UPDATE;
 }
 
-int cache_update(struct nft_ctx *nft, unsigned int flags, struct list_head *msgs)
+int nft_cache_update(struct nft_ctx *nft, unsigned int flags,
+		     struct list_head *msgs)
 {
 	struct netlink_ctx ctx = {
 		.list		= LIST_HEAD_INIT(ctx.list),
@@ -499,13 +500,13 @@ int cache_update(struct nft_ctx *nft, unsigned int flags, struct list_head *msgs
 replay:
 	ctx.seqnum = cache->seqnum++;
 	genid = mnl_genid_get(&ctx);
-	if (!cache_needs_refresh(cache) &&
-	    cache_is_complete(cache, flags) &&
-	    cache_is_updated(cache, genid))
+	if (!nft_cache_needs_refresh(cache) &&
+	    nft_cache_is_complete(cache, flags) &&
+	    nft_cache_is_updated(cache, genid))
 		return 0;
 
 	if (cache->genid)
-		cache_release(cache);
+		nft_cache_release(cache);
 
 	if (flags & NFT_CACHE_FLUSHED) {
 		oldflags = flags;
@@ -515,9 +516,9 @@ replay:
 		goto skip;
 	}
 
-	ret = cache_init(&ctx, flags);
+	ret = nft_cache_init(&ctx, flags);
 	if (ret < 0) {
-		cache_release(cache);
+		nft_cache_release(cache);
 		if (errno == EINTR)
 			goto replay;
 
@@ -526,7 +527,7 @@ replay:
 
 	genid_stop = mnl_genid_get(&ctx);
 	if (genid != genid_stop) {
-		cache_release(cache);
+		nft_cache_release(cache);
 		goto replay;
 	}
 skip:
@@ -535,7 +536,7 @@ skip:
 	return 0;
 }
 
-static void __cache_flush(struct list_head *table_list)
+static void nft_cache_flush(struct list_head *table_list)
 {
 	struct table *table, *next;
 
@@ -545,9 +546,9 @@ static void __cache_flush(struct list_head *table_list)
 	}
 }
 
-void cache_release(struct nft_cache *cache)
+void nft_cache_release(struct nft_cache *cache)
 {
-	__cache_flush(&cache->list);
+	nft_cache_flush(&cache->list);
 	cache->genid = 0;
 	cache->flags = NFT_CACHE_EMPTY;
 }
diff --git a/src/cmd.c b/src/cmd.c
index c04efce3801a..f9716fccd513 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -55,7 +55,7 @@ static int nft_cmd_enoent_rule(struct netlink_ctx *ctx, const struct cmd *cmd,
 	const struct table *table;
 	struct chain *chain;
 
-	if (cache_update(ctx->nft, flags, ctx->msgs) < 0)
+	if (nft_cache_update(ctx->nft, flags, ctx->msgs) < 0)
 		return 0;
 
 	table = table_lookup_fuzzy(&cmd->handle, &ctx->nft->cache);
diff --git a/src/evaluate.c b/src/evaluate.c
index 2c8a649f5392..a3f468aab104 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4086,7 +4086,7 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule,
 		return -1;
 	}
 
-	if (cache_needs_update(&ctx->nft->cache))
+	if (nft_cache_needs_update(&ctx->nft->cache))
 		return rule_cache_update(ctx, op);
 
 	return 0;
diff --git a/src/libnftables.c b/src/libnftables.c
index 044365914747..56c51a6104ac 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -303,7 +303,7 @@ void nft_ctx_free(struct nft_ctx *ctx)
 	exit_cookie(&ctx->output.output_cookie);
 	exit_cookie(&ctx->output.error_cookie);
 	iface_cache_release();
-	cache_release(&ctx->cache);
+	nft_cache_release(&ctx->cache);
 	nft_ctx_clear_include_paths(ctx);
 	scope_free(ctx->top_scope);
 	xfree(ctx->state);
@@ -416,8 +416,8 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
 	unsigned int flags;
 	struct cmd *cmd;
 
-	flags = cache_evaluate(nft, cmds);
-	if (cache_update(nft, flags, msgs) < 0)
+	flags = nft_cache_evaluate(nft, cmds);
+	if (nft_cache_update(nft, flags, msgs) < 0)
 		return -1;
 
 	list_for_each_entry(cmd, cmds, list) {
@@ -496,7 +496,7 @@ err:
 	    nft_output_echo(&nft->output))
 		json_print_echo(nft);
 	if (rc)
-		cache_release(&nft->cache);
+		nft_cache_release(&nft->cache);
 	return rc;
 }
 
@@ -547,6 +547,6 @@ err:
 	    nft_output_echo(&nft->output))
 		json_print_echo(nft);
 	if (rc)
-		cache_release(&nft->cache);
+		nft_cache_release(&nft->cache);
 	return rc;
 }
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 06/18] src: consolidate object cache infrastructure
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (4 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 05/18] src: consolidate nft_cache infrastructure Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 07/18] cache: add hashtable cache for object Pablo Neira Ayuso
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

This patch consolidates the object cache infrastructure. Update set and
chains to use it.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/cache.h | 15 +++++++++++++++
 include/rule.h  | 12 ++++--------
 src/cache.c     | 48 ++++++++++++++++++++++++++++++++++++------------
 src/json.c      | 10 +++++-----
 src/rule.c      | 40 +++++++++++++++-------------------------
 5 files changed, 75 insertions(+), 50 deletions(-)

diff --git a/include/cache.h b/include/cache.h
index 987b122bc4fb..4d91a73624c8 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -72,4 +72,19 @@ struct chain *chain_cache_find(const struct table *table, const char *name);
 void set_cache_add(struct set *set, struct table *table);
 struct set *set_cache_find(const struct table *table, const char *name);
 
+struct cache {
+	struct list_head	*ht;
+	struct list_head	list;
+};
+
+struct cache_item {
+	struct list_head	hlist;
+	struct list_head	list;
+};
+
+void cache_init(struct cache *cache);
+void cache_free(struct cache *cache);
+void cache_add(struct cache_item *item, struct cache *cache, uint32_t hash);
+void cache_del(struct cache_item *item);
+
 #endif /* _NFT_CACHE_H_ */
diff --git a/include/rule.h b/include/rule.h
index 7896eafec137..b238c85bcba9 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -155,11 +155,9 @@ struct table {
 	struct handle		handle;
 	struct location		location;
 	struct scope		scope;
-	struct list_head	*cache_chain_ht;
-	struct list_head	cache_chain;
+	struct cache		chain_cache;
+	struct cache		set_cache;
 	struct list_head	chains;
-	struct list_head	*cache_set_ht;
-	struct list_head	cache_set;
 	struct list_head	sets;
 	struct list_head	objs;
 	struct list_head	flowtables;
@@ -233,8 +231,7 @@ struct hook_spec {
  */
 struct chain {
 	struct list_head	list;
-	struct list_head	cache_hlist;
-	struct list_head	cache_list;
+	struct cache_item	cache;
 	struct handle		handle;
 	struct location		location;
 	unsigned int		refcnt;
@@ -333,8 +330,7 @@ void rule_stmt_insert_at(struct rule *rule, struct stmt *nstmt,
  */
 struct set {
 	struct list_head	list;
-	struct list_head	cache_hlist;
-	struct list_head	cache_list;
+	struct cache_item	cache;
 	struct handle		handle;
 	struct location		location;
 	unsigned int		refcnt;
diff --git a/src/cache.c b/src/cache.c
index 53dbaaba8e20..70e47064848e 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -193,10 +193,9 @@ static int chain_cache_cb(struct nftnl_chain *nlc, void *arg)
 	chain = netlink_delinearize_chain(ctx->nlctx, nlc);
 
 	if (chain->flags & CHAIN_F_BINDING) {
-		list_add_tail(&chain->cache_list, &ctx->table->chain_bindings);
+		list_add_tail(&chain->cache.list, &ctx->table->chain_bindings);
 	} else {
-		list_add_tail(&chain->cache_hlist, &ctx->table->cache_chain_ht[hash]);
-		list_add_tail(&chain->cache_list, &ctx->table->cache_chain);
+		cache_add(&chain->cache, &ctx->table->chain_cache, hash);
 	}
 
 	nftnl_chain_list_del(nlc);
@@ -240,8 +239,7 @@ void chain_cache_add(struct chain *chain, struct table *table)
 	uint32_t hash;
 
 	hash = djb_hash(chain->handle.chain.name) % NFT_CACHE_HSIZE;
-	list_add_tail(&chain->cache_hlist, &table->cache_chain_ht[hash]);
-	list_add_tail(&chain->cache_list, &table->cache_chain);
+	cache_add(&chain->cache, &table->chain_cache, hash);
 }
 
 struct chain *chain_cache_find(const struct table *table, const char *name)
@@ -250,7 +248,7 @@ struct chain *chain_cache_find(const struct table *table, const char *name)
 	uint32_t hash;
 
 	hash = djb_hash(name) % NFT_CACHE_HSIZE;
-	list_for_each_entry(chain, &table->cache_chain_ht[hash], cache_hlist) {
+	list_for_each_entry(chain, &table->chain_cache.ht[hash], cache.hlist) {
 		if (!strcmp(chain->handle.chain.name, name))
 			return chain;
 	}
@@ -276,8 +274,7 @@ static int set_cache_cb(struct nftnl_set *nls, void *arg)
 
 	set_name = nftnl_set_get_str(nls, NFTNL_SET_NAME);
 	hash = djb_hash(set_name) % NFT_CACHE_HSIZE;
-	list_add_tail(&set->cache_hlist, &ctx->table->cache_set_ht[hash]);
-	list_add_tail(&set->cache_list, &ctx->table->cache_set);
+	cache_add(&set->cache, &ctx->table->set_cache, hash);
 
 	return 0;
 }
@@ -319,8 +316,7 @@ void set_cache_add(struct set *set, struct table *table)
 	uint32_t hash;
 
 	hash = djb_hash(set->handle.set.name) % NFT_CACHE_HSIZE;
-	list_add_tail(&set->cache_hlist, &table->cache_set_ht[hash]);
-	list_add_tail(&set->cache_list, &table->cache_set);
+	cache_add(&set->cache, &table->set_cache, hash);
 }
 
 struct set *set_cache_find(const struct table *table, const char *name)
@@ -329,7 +325,7 @@ struct set *set_cache_find(const struct table *table, const char *name)
 	uint32_t hash;
 
 	hash = djb_hash(name) % NFT_CACHE_HSIZE;
-	list_for_each_entry(set, &table->cache_set_ht[hash], cache_hlist) {
+	list_for_each_entry(set, &table->set_cache.ht[hash], cache.hlist) {
 		if (!strcmp(set->handle.set.name, name))
 			return set;
 	}
@@ -384,7 +380,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
 			}
 		}
 		if (flags & NFT_CACHE_SETELEM_BIT) {
-			list_for_each_entry(set, &table->cache_set, cache_list) {
+			list_for_each_entry(set, &table->set_cache.list, cache.list) {
 				ret = netlink_list_setelems(ctx, &set->handle,
 							    set);
 				if (ret < 0) {
@@ -552,3 +548,31 @@ void nft_cache_release(struct nft_cache *cache)
 	cache->genid = 0;
 	cache->flags = NFT_CACHE_EMPTY;
 }
+
+void cache_init(struct cache *cache)
+{
+	int i;
+
+	cache->ht = xmalloc(sizeof(struct list_head) * NFT_CACHE_HSIZE);
+	for (i = 0; i < NFT_CACHE_HSIZE; i++)
+		init_list_head(&cache->ht[i]);
+
+	init_list_head(&cache->list);
+}
+
+void cache_free(struct cache *cache)
+{
+	xfree(cache->ht);
+}
+
+void cache_add(struct cache_item *item, struct cache *cache, uint32_t hash)
+{
+	list_add_tail(&item->hlist, &cache->ht[hash]);
+	list_add_tail(&item->list, &cache->list);
+}
+
+void cache_del(struct cache_item *item)
+{
+	list_del(&item->hlist);
+	list_del(&item->list);
+}
diff --git a/src/json.c b/src/json.c
index 52603a57de50..a375093eb785 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1574,7 +1574,7 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx,
 		tmp = obj_print_json(obj);
 		json_array_append_new(root, tmp);
 	}
-	list_for_each_entry(set, &table->cache_set, cache_list) {
+	list_for_each_entry(set, &table->set_cache.list, cache.list) {
 		if (set_is_anonymous(set->flags))
 			continue;
 		tmp = set_print_json(&ctx->nft->output, set);
@@ -1584,7 +1584,7 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx,
 		tmp = flowtable_print_json(flowtable);
 		json_array_append_new(root, tmp);
 	}
-	list_for_each_entry(chain, &table->cache_chain, cache_list) {
+	list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
 		tmp = chain_print_json(chain);
 		json_array_append_new(root, tmp);
 
@@ -1646,7 +1646,7 @@ static json_t *do_list_chain_json(struct netlink_ctx *ctx,
 	struct chain *chain;
 	struct rule *rule;
 
-	list_for_each_entry(chain, &table->cache_chain, cache_list) {
+	list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
 		if (chain->handle.family != cmd->handle.family ||
 		    strcmp(cmd->handle.chain.name, chain->handle.chain.name))
 			continue;
@@ -1674,7 +1674,7 @@ static json_t *do_list_chains_json(struct netlink_ctx *ctx, struct cmd *cmd)
 		    cmd->handle.family != table->handle.family)
 			continue;
 
-		list_for_each_entry(chain, &table->cache_chain, cache_list) {
+		list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
 			json_t *tmp = chain_print_json(chain);
 
 			json_array_append_new(root, tmp);
@@ -1707,7 +1707,7 @@ static json_t *do_list_sets_json(struct netlink_ctx *ctx, struct cmd *cmd)
 		    cmd->handle.family != table->handle.family)
 			continue;
 
-		list_for_each_entry(set, &table->cache_set, cache_list) {
+		list_for_each_entry(set, &table->set_cache.list, cache.list) {
 			if (cmd->obj == CMD_OBJ_SETS &&
 			    !set_is_literal(set->flags))
 				continue;
diff --git a/src/rule.c b/src/rule.c
index fac8d22a85ee..7dbb02f5b04f 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -212,7 +212,7 @@ struct set *set_lookup_fuzzy(const char *set_name,
 	string_misspell_init(&st);
 
 	list_for_each_entry(table, &cache->list, list) {
-		list_for_each_entry(set, &table->cache_set, cache_list) {
+		list_for_each_entry(set, &table->set_cache.list, cache.list) {
 			if (set_is_anonymous(set->flags))
 				continue;
 			if (!strcmp(set->handle.set.name, set_name)) {
@@ -750,7 +750,7 @@ struct chain *chain_binding_lookup(const struct table *table,
 {
 	struct chain *chain;
 
-	list_for_each_entry(chain, &table->chain_bindings, cache_list) {
+	list_for_each_entry(chain, &table->chain_bindings, cache.list) {
 		if (!strcmp(chain->handle.chain.name, chain_name))
 			return chain;
 	}
@@ -768,7 +768,7 @@ struct chain *chain_lookup_fuzzy(const struct handle *h,
 	string_misspell_init(&st);
 
 	list_for_each_entry(table, &cache->list, list) {
-		list_for_each_entry(chain, &table->cache_chain, cache_list) {
+		list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
 			if (!strcmp(chain->handle.chain.name, h->chain.name)) {
 				*t = table;
 				return chain;
@@ -1102,28 +1102,18 @@ void chain_print_plain(const struct chain *chain, struct output_ctx *octx)
 struct table *table_alloc(void)
 {
 	struct table *table;
-	int i;
 
 	table = xzalloc(sizeof(*table));
 	init_list_head(&table->chains);
-	init_list_head(&table->cache_chain);
 	init_list_head(&table->sets);
-	init_list_head(&table->cache_set);
 	init_list_head(&table->objs);
 	init_list_head(&table->flowtables);
 	init_list_head(&table->chain_bindings);
 	init_list_head(&table->scope.symbols);
 	table->refcnt = 1;
 
-	table->cache_chain_ht =
-		xmalloc(sizeof(struct list_head) * NFT_CACHE_HSIZE);
-	for (i = 0; i < NFT_CACHE_HSIZE; i++)
-		init_list_head(&table->cache_chain_ht[i]);
-
-	table->cache_set_ht =
-		xmalloc(sizeof(struct list_head) * NFT_CACHE_HSIZE);
-	for (i = 0; i < NFT_CACHE_HSIZE; i++)
-		init_list_head(&table->cache_set_ht[i]);
+	cache_init(&table->chain_cache);
+	cache_init(&table->set_cache);
 
 	return table;
 }
@@ -1141,15 +1131,15 @@ void table_free(struct table *table)
 		xfree(table->comment);
 	list_for_each_entry_safe(chain, next, &table->chains, list)
 		chain_free(chain);
-	list_for_each_entry_safe(chain, next, &table->chain_bindings, cache_list)
+	list_for_each_entry_safe(chain, next, &table->chain_bindings, cache.list)
 		chain_free(chain);
 	/* this is implicitly releasing chains in the hashtable cache */
-	list_for_each_entry_safe(chain, next, &table->cache_chain, cache_list)
+	list_for_each_entry_safe(chain, next, &table->chain_cache.list, cache.list)
 		chain_free(chain);
 	list_for_each_entry_safe(set, nset, &table->sets, list)
 		set_free(set);
 	/* this is implicitly releasing sets in the hashtable cache */
-	list_for_each_entry_safe(set, nset, &table->cache_set, cache_list)
+	list_for_each_entry_safe(set, nset, &table->set_cache.list, cache.list)
 		set_free(set);
 	list_for_each_entry_safe(ft, nft, &table->flowtables, list)
 		flowtable_free(ft);
@@ -1157,8 +1147,8 @@ void table_free(struct table *table)
 		obj_free(obj);
 	handle_free(&table->handle);
 	scope_release(&table->scope);
-	xfree(table->cache_chain_ht);
-	xfree(table->cache_set_ht);
+	cache_free(&table->chain_cache);
+	cache_free(&table->set_cache);
 	xfree(table);
 }
 
@@ -1269,7 +1259,7 @@ static void table_print(const struct table *table, struct output_ctx *octx)
 		obj_print(obj, octx);
 		delim = "\n";
 	}
-	list_for_each_entry(set, &table->cache_set, cache_list) {
+	list_for_each_entry(set, &table->set_cache.list, cache.list) {
 		if (set_is_anonymous(set->flags))
 			continue;
 		nft_print(octx, "%s", delim);
@@ -1281,7 +1271,7 @@ static void table_print(const struct table *table, struct output_ctx *octx)
 		flowtable_print(flowtable, octx);
 		delim = "\n";
 	}
-	list_for_each_entry(chain, &table->cache_chain, cache_list) {
+	list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
 		nft_print(octx, "%s", delim);
 		chain_print(chain, octx);
 		delim = "\n";
@@ -1691,7 +1681,7 @@ static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
 			  family2str(table->handle.family),
 			  table->handle.table.name);
 
-		list_for_each_entry(set, &table->cache_set, cache_list) {
+		list_for_each_entry(set, &table->set_cache.list, cache.list) {
 			if (cmd->obj == CMD_OBJ_SETS &&
 			    !set_is_literal(set->flags))
 				continue;
@@ -2375,7 +2365,7 @@ static int do_list_chain(struct netlink_ctx *ctx, struct cmd *cmd,
 
 	table_print_declaration(table, &ctx->nft->output);
 
-	list_for_each_entry(chain, &table->cache_chain, cache_list) {
+	list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
 		if (chain->handle.family != cmd->handle.family ||
 		    strcmp(cmd->handle.chain.name, chain->handle.chain.name) != 0)
 			continue;
@@ -2400,7 +2390,7 @@ static int do_list_chains(struct netlink_ctx *ctx, struct cmd *cmd)
 
 		table_print_declaration(table, &ctx->nft->output);
 
-		list_for_each_entry(chain, &table->cache_chain, cache_list) {
+		list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
 			chain_print_declaration(chain, &ctx->nft->output);
 			nft_print(&ctx->nft->output, "\t}\n");
 		}
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 07/18] cache: add hashtable cache for object
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (5 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 06/18] src: consolidate object cache infrastructure Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 08/18] cache: add hashtable cache for flowtable Pablo Neira Ayuso
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

This patch adds a hashtable for object lookups.

This patch also splits table->objs in two:

- Sets that reside in the cache are stored in the new
  tables->cache_obj and tables->cache_obj_ht.

- Set that defined via command line / ruleset file reside in
  tables->obj.

Sets in the cache (already in the kernel) are not placed in the
table->objs list.

By keeping separated lists, objs defined via command line / ruleset file
can be added to cache.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/cache.h |  5 +++
 include/rule.h  |  5 +--
 src/cache.c     | 98 ++++++++++++++++++++++++++++++++++++++++++++++++-
 src/evaluate.c  |  2 +-
 src/json.c      |  4 +-
 src/monitor.c   |  8 ++--
 src/netlink.c   | 19 ----------
 src/rule.c      | 38 +++++++------------
 8 files changed, 124 insertions(+), 55 deletions(-)

diff --git a/include/cache.h b/include/cache.h
index 4d91a73624c8..9605ef96c853 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -87,4 +87,9 @@ void cache_free(struct cache *cache);
 void cache_add(struct cache_item *item, struct cache *cache, uint32_t hash);
 void cache_del(struct cache_item *item);
 
+void obj_cache_add(struct obj *obj, struct table *table);
+void obj_cache_del(struct obj *obj);
+struct obj *obj_cache_find(const struct table *table, const char *name,
+			   uint32_t obj_type);
+
 #endif /* _NFT_CACHE_H_ */
diff --git a/include/rule.h b/include/rule.h
index b238c85bcba9..f264bc8a1a01 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -157,6 +157,7 @@ struct table {
 	struct scope		scope;
 	struct cache		chain_cache;
 	struct cache		set_cache;
+	struct cache		obj_cache;
 	struct list_head	chains;
 	struct list_head	sets;
 	struct list_head	objs;
@@ -484,6 +485,7 @@ struct secmark {
  */
 struct obj {
 	struct list_head		list;
+	struct cache_item		cache;
 	struct location			location;
 	struct handle			handle;
 	uint32_t			type;
@@ -504,9 +506,6 @@ struct obj {
 struct obj *obj_alloc(const struct location *loc);
 extern struct obj *obj_get(struct obj *obj);
 void obj_free(struct obj *obj);
-void obj_add_hash(struct obj *obj, struct table *table);
-struct obj *obj_lookup(const struct table *table, const char *name,
-		       uint32_t type);
 struct obj *obj_lookup_fuzzy(const char *obj_name,
 			     const struct nft_cache *cache,
 			     const struct table **t);
diff --git a/src/cache.c b/src/cache.c
index 70e47064848e..b2f796ec9975 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -333,6 +333,92 @@ struct set *set_cache_find(const struct table *table, const char *name)
 	return NULL;
 }
 
+struct obj_cache_dump_ctx {
+	struct netlink_ctx	*nlctx;
+	struct table		*table;
+};
+
+static int obj_cache_cb(struct nftnl_obj *nlo, void *arg)
+{
+	struct obj_cache_dump_ctx *ctx = arg;
+	const char *obj_name;
+	struct obj *obj;
+	uint32_t hash;
+
+	obj = netlink_delinearize_obj(ctx->nlctx, nlo);
+	if (!obj)
+		return -1;
+
+	obj_name = nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME);
+	hash = djb_hash(obj_name) % NFT_CACHE_HSIZE;
+	cache_add(&obj->cache, &ctx->table->obj_cache, hash);
+
+	return 0;
+}
+
+static int obj_cache_init(struct netlink_ctx *ctx, struct table *table,
+			  struct nftnl_obj_list *obj_list)
+{
+	struct obj_cache_dump_ctx dump_ctx = {
+		.nlctx	= ctx,
+		.table	= table,
+	};
+	nftnl_obj_list_foreach(obj_list, obj_cache_cb, &dump_ctx);
+
+	return 0;
+}
+
+static struct nftnl_obj_list *obj_cache_dump(struct netlink_ctx *ctx,
+					     const struct table *table,
+					     int *err)
+{
+	struct nftnl_obj_list *obj_list;
+
+	obj_list = mnl_nft_obj_dump(ctx, table->handle.family,
+				    table->handle.table.name, NULL,
+				    0, true, false);
+	if (!obj_list) {
+                if (errno == EINTR) {
+			*err = -1;
+			return NULL;
+		}
+		*err = 0;
+		return NULL;
+	}
+
+	return obj_list;
+}
+
+void obj_cache_add(struct obj *obj, struct table *table)
+{
+	uint32_t hash;
+
+	hash = djb_hash(obj->handle.obj.name) % NFT_CACHE_HSIZE;
+	cache_add(&obj->cache, &table->obj_cache, hash);
+}
+
+void obj_cache_del(struct obj *obj)
+{
+	cache_del(&obj->cache);
+}
+
+struct obj *obj_cache_find(const struct table *table, const char *name,
+			   uint32_t obj_type)
+{
+	struct obj *obj;
+	uint32_t hash;
+
+	hash = djb_hash(name) % NFT_CACHE_HSIZE;
+	list_for_each_entry(obj, &table->obj_cache.ht[hash], cache.hlist) {
+		if (!strcmp(obj->handle.obj.name, name) &&
+		    obj->type == obj_type)
+			return obj;
+	}
+
+	return NULL;
+}
+
+
 static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
 			     struct nft_cache *cache)
 {
@@ -351,6 +437,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
 {
 	struct nftnl_chain_list *chain_list = NULL;
 	struct nftnl_set_list *set_list = NULL;
+	struct nftnl_obj_list *obj_list;
 	struct rule *rule, *nrule;
 	struct table *table;
 	struct chain *chain;
@@ -405,12 +492,19 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
 			list_splice_tail_init(&ctx->list, &table->flowtables);
 		}
 		if (flags & NFT_CACHE_OBJECT_BIT) {
-			ret = netlink_list_objs(ctx, &table->handle);
+			obj_list = obj_cache_dump(ctx, table, &ret);
+			if (!obj_list) {
+				ret = -1;
+				goto cache_fails;
+			}
+			ret = obj_cache_init(ctx, table, obj_list);
+
+			nftnl_obj_list_free(obj_list);
+
 			if (ret < 0) {
 				ret = -1;
 				goto cache_fails;
 			}
-			list_splice_tail_init(&ctx->list, &table->objs);
 		}
 
 		if (flags & NFT_CACHE_RULE_BIT) {
diff --git a/src/evaluate.c b/src/evaluate.c
index a3f468aab104..91cedf4ca021 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4412,7 +4412,7 @@ static int cmd_evaluate_list_obj(struct eval_ctx *ctx, const struct cmd *cmd,
 	if (table == NULL)
 		return table_not_found(ctx);
 
-	if (obj_lookup(table, cmd->handle.obj.name, obj_type) == NULL)
+	if (!obj_cache_find(table, cmd->handle.obj.name, obj_type))
 		return obj_not_found(ctx, &cmd->handle.obj.location,
 				     cmd->handle.obj.name);
 
diff --git a/src/json.c b/src/json.c
index a375093eb785..0b7699a625b5 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1570,7 +1570,7 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx,
 	tmp = table_print_json(table);
 	json_array_append_new(root, tmp);
 
-	list_for_each_entry(obj, &table->objs, list) {
+	list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
 		tmp = obj_print_json(obj);
 		json_array_append_new(root, tmp);
 	}
@@ -1740,7 +1740,7 @@ static json_t *do_list_obj_json(struct netlink_ctx *ctx,
 		    strcmp(cmd->handle.table.name, table->handle.table.name))
 			continue;
 
-		list_for_each_entry(obj, &table->objs, list) {
+		list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
 			if (obj->type != type ||
 			    (cmd->handle.obj.name &&
 			     strcmp(cmd->handle.obj.name, obj->handle.obj.name)))
diff --git a/src/monitor.c b/src/monitor.c
index dc3f0848ba66..ae288f6cb212 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -477,7 +477,7 @@ static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
 	nlo = netlink_obj_alloc(nlh);
 
 	obj = netlink_delinearize_obj(monh->ctx, nlo);
-	if (obj == NULL) {
+	if (!obj) {
 		nftnl_obj_free(nlo);
 		return MNL_CB_ERROR;
 	}
@@ -727,7 +727,7 @@ static void netlink_events_cache_addobj(struct netlink_mon_handler *monh,
 		goto out;
 	}
 
-	obj_add_hash(obj, t);
+	obj_cache_add(obj, t);
 out:
 	nftnl_obj_free(nlo);
 }
@@ -756,13 +756,13 @@ static void netlink_events_cache_delobj(struct netlink_mon_handler *monh,
 		goto out;
 	}
 
-	obj = obj_lookup(t, name, type);
+	obj = obj_cache_find(t, name, type);
 	if (obj == NULL) {
 		fprintf(stderr, "W: Unable to find object in cache\n");
 		goto out;
 	}
 
-	list_del(&obj->list);
+	obj_cache_del(obj);
 	obj_free(obj);
 out:
 	nftnl_obj_free(nlo);
diff --git a/src/netlink.c b/src/netlink.c
index 123525570c39..6323fe4e810f 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1517,25 +1517,6 @@ static int list_obj_cb(struct nftnl_obj *nls, void *arg)
 	return 0;
 }
 
-int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h)
-{
-	struct nftnl_obj_list *obj_cache;
-	int err;
-
-	obj_cache = mnl_nft_obj_dump(ctx, h->family,
-				     h->table.name, NULL, 0, true, false);
-	if (obj_cache == NULL) {
-		if (errno == EINTR)
-			return -1;
-
-		return 0;
-	}
-
-	err = nftnl_obj_list_foreach(obj_cache, list_obj_cb, ctx);
-	nftnl_obj_list_free(obj_cache);
-	return err;
-}
-
 int netlink_reset_objs(struct netlink_ctx *ctx, const struct cmd *cmd,
 		       uint32_t type, bool dump)
 {
diff --git a/src/rule.c b/src/rule.c
index 7dbb02f5b04f..56fb19c77e7d 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1114,6 +1114,7 @@ struct table *table_alloc(void)
 
 	cache_init(&table->chain_cache);
 	cache_init(&table->set_cache);
+	cache_init(&table->obj_cache);
 
 	return table;
 }
@@ -1145,10 +1146,15 @@ void table_free(struct table *table)
 		flowtable_free(ft);
 	list_for_each_entry_safe(obj, nobj, &table->objs, list)
 		obj_free(obj);
+	/* this is implicitly releasing objs in the hashtable cache */
+	list_for_each_entry_safe(obj, nobj, &table->obj_cache.list, cache.list)
+		obj_free(obj);
+
 	handle_free(&table->handle);
 	scope_release(&table->scope);
 	cache_free(&table->chain_cache);
 	cache_free(&table->set_cache);
+	cache_free(&table->obj_cache);
 	xfree(table);
 }
 
@@ -1254,7 +1260,7 @@ static void table_print(const struct table *table, struct output_ctx *octx)
 	if (table->comment)
 		nft_print(octx, "\tcomment \"%s\"\n", table->comment);
 
-	list_for_each_entry(obj, &table->objs, list) {
+	list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
 		nft_print(octx, "%s", delim);
 		obj_print(obj, octx);
 		delim = "\n";
@@ -1727,24 +1733,6 @@ void obj_free(struct obj *obj)
 	xfree(obj);
 }
 
-void obj_add_hash(struct obj *obj, struct table *table)
-{
-	list_add_tail(&obj->list, &table->objs);
-}
-
-struct obj *obj_lookup(const struct table *table, const char *name,
-		       uint32_t type)
-{
-	struct obj *obj;
-
-	list_for_each_entry(obj, &table->objs, list) {
-		if (!strcmp(obj->handle.obj.name, name) &&
-		    obj->type == type)
-			return obj;
-	}
-	return NULL;
-}
-
 struct obj *obj_lookup_fuzzy(const char *obj_name,
 			     const struct nft_cache *cache,
 			     const struct table **t)
@@ -1756,7 +1744,7 @@ struct obj *obj_lookup_fuzzy(const char *obj_name,
 	string_misspell_init(&st);
 
 	list_for_each_entry(table, &cache->list, list) {
-		list_for_each_entry(obj, &table->objs, list) {
+		list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
 			if (!strcmp(obj->handle.obj.name, obj_name)) {
 				*t = table;
 				return obj;
@@ -2101,14 +2089,14 @@ static int do_list_obj(struct netlink_ctx *ctx, struct cmd *cmd, uint32_t type)
 		    strcmp(cmd->handle.table.name, table->handle.table.name))
 			continue;
 
-		if (list_empty(&table->objs))
+		if (list_empty(&table->obj_cache.list))
 			continue;
 
 		nft_print(&ctx->nft->output, "table %s %s {\n",
 			  family2str(table->handle.family),
 			  table->handle.table.name);
 
-		list_for_each_entry(obj, &table->objs, list) {
+		list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
 			if (obj->type != type ||
 			    (cmd->handle.obj.name != NULL &&
 			     strcmp(cmd->handle.obj.name, obj->handle.obj.name)))
@@ -2564,8 +2552,10 @@ static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd)
 	ret = netlink_reset_objs(ctx, cmd, type, dump);
 	list_for_each_entry_safe(obj, next, &ctx->list, list) {
 		table = table_lookup(&obj->handle, &ctx->nft->cache);
-		if (!obj_lookup(table, obj->handle.obj.name, obj->type))
-			list_move(&obj->list, &table->objs);
+		if (!obj_cache_find(table, obj->handle.obj.name, obj->type)) {
+			list_del(&obj->list);
+			obj_cache_add(obj, table);
+		}
 	}
 	if (ret < 0)
 		return ret;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 08/18] cache: add hashtable cache for flowtable
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (6 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 07/18] cache: add hashtable cache for object Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 09/18] cache: add set_cache_del() and use it Pablo Neira Ayuso
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Add flowtable hashtable cache.

Actually I am not expecting that many flowtables to benefit from the
hashtable to be created by streamline this code with tables, chains,
sets and policy objects.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/cache.h   |  4 +++
 include/netlink.h |  2 ++
 include/rule.h    |  4 +--
 src/cache.c       | 88 +++++++++++++++++++++++++++++++++++++++++++++--
 src/evaluate.c    |  6 ++--
 src/json.c        |  8 ++---
 src/netlink.c     |  2 +-
 src/rule.c        | 31 ++++++-----------
 8 files changed, 112 insertions(+), 33 deletions(-)

diff --git a/include/cache.h b/include/cache.h
index 9605ef96c853..992f993c0667 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -92,4 +92,8 @@ void obj_cache_del(struct obj *obj);
 struct obj *obj_cache_find(const struct table *table, const char *name,
 			   uint32_t obj_type);
 
+struct flowtable;
+void ft_cache_add(struct flowtable *ft, struct table *table);
+struct flowtable *ft_cache_find(const struct table *table, const char *name);
+
 #endif /* _NFT_CACHE_H_ */
diff --git a/include/netlink.h b/include/netlink.h
index f93c5322100f..a7c524ca9674 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -163,6 +163,8 @@ extern struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
 
 extern int netlink_list_flowtables(struct netlink_ctx *ctx,
 				   const struct handle *h);
+extern struct flowtable *netlink_delinearize_flowtable(struct netlink_ctx *ctx,
+						       struct nftnl_flowtable *nlo);
 
 extern void netlink_dump_chain(const struct nftnl_chain *nlc,
 			       struct netlink_ctx *ctx);
diff --git a/include/rule.h b/include/rule.h
index f264bc8a1a01..c6fd4c4c067b 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -158,6 +158,7 @@ struct table {
 	struct cache		chain_cache;
 	struct cache		set_cache;
 	struct cache		obj_cache;
+	struct cache		ft_cache;
 	struct list_head	chains;
 	struct list_head	sets;
 	struct list_head	objs;
@@ -516,6 +517,7 @@ uint32_t obj_type_to_cmd(uint32_t type);
 
 struct flowtable {
 	struct list_head	list;
+	struct cache_item	cache;
 	struct handle		handle;
 	struct scope		scope;
 	struct location		location;
@@ -531,8 +533,6 @@ struct flowtable {
 extern struct flowtable *flowtable_alloc(const struct location *loc);
 extern struct flowtable *flowtable_get(struct flowtable *flowtable);
 extern void flowtable_free(struct flowtable *flowtable);
-extern void flowtable_add_hash(struct flowtable *flowtable, struct table *table);
-extern struct flowtable *flowtable_lookup(const struct table *table, const char *name);
 extern struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
 						const struct nft_cache *cache,
 						const struct table **table);
diff --git a/src/cache.c b/src/cache.c
index b2f796ec9975..1aec12666d52 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -418,6 +418,82 @@ struct obj *obj_cache_find(const struct table *table, const char *name,
 	return NULL;
 }
 
+struct ft_cache_dump_ctx {
+	struct netlink_ctx	*nlctx;
+	struct table		*table;
+};
+
+static int ft_cache_cb(struct nftnl_flowtable *nlf, void *arg)
+{
+	struct ft_cache_dump_ctx *ctx = arg;
+	const char *ft_name;
+	struct flowtable *ft;
+	uint32_t hash;
+
+	ft = netlink_delinearize_flowtable(ctx->nlctx, nlf);
+	if (!ft)
+		return -1;
+
+	ft_name = nftnl_flowtable_get_str(nlf, NFTNL_FLOWTABLE_NAME);
+	hash = djb_hash(ft_name) % NFT_CACHE_HSIZE;
+	cache_add(&ft->cache, &ctx->table->ft_cache, hash);
+
+	return 0;
+}
+
+static int ft_cache_init(struct netlink_ctx *ctx, struct table *table,
+			 struct nftnl_flowtable_list *ft_list)
+{
+	struct ft_cache_dump_ctx dump_ctx = {
+		.nlctx	= ctx,
+		.table	= table,
+	};
+	nftnl_flowtable_list_foreach(ft_list, ft_cache_cb, &dump_ctx);
+
+	return 0;
+}
+
+static struct nftnl_flowtable_list *ft_cache_dump(struct netlink_ctx *ctx,
+						  const struct table *table,
+						  int *err)
+{
+	struct nftnl_flowtable_list *ft_list;
+
+	ft_list = mnl_nft_flowtable_dump(ctx, table->handle.family,
+					 table->handle.table.name);
+	if (!ft_list) {
+                if (errno == EINTR) {
+			*err = -1;
+			return NULL;
+		}
+		*err = 0;
+		return NULL;
+	}
+
+	return ft_list;
+}
+
+void ft_cache_add(struct flowtable *ft, struct table *table)
+{
+	uint32_t hash;
+
+	hash = djb_hash(ft->handle.flowtable.name) % NFT_CACHE_HSIZE;
+	cache_add(&ft->cache, &table->ft_cache, hash);
+}
+
+struct flowtable *ft_cache_find(const struct table *table, const char *name)
+{
+	struct flowtable *ft;
+	uint32_t hash;
+
+	hash = djb_hash(name) % NFT_CACHE_HSIZE;
+	list_for_each_entry(ft, &table->ft_cache.ht[hash], cache.hlist) {
+		if (!strcmp(ft->handle.flowtable.name, name))
+			return ft;
+	}
+
+	return NULL;
+}
 
 static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
 			     struct nft_cache *cache)
@@ -435,6 +511,7 @@ static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
 
 static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
 {
+	struct nftnl_flowtable_list *ft_list = NULL;
 	struct nftnl_chain_list *chain_list = NULL;
 	struct nftnl_set_list *set_list = NULL;
 	struct nftnl_obj_list *obj_list;
@@ -484,12 +561,19 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
 			}
 		}
 		if (flags & NFT_CACHE_FLOWTABLE_BIT) {
-			ret = netlink_list_flowtables(ctx, &table->handle);
+			ft_list = ft_cache_dump(ctx, table, &ret);
+			if (!ft_list) {
+				ret = -1;
+				goto cache_fails;
+			}
+			ret = ft_cache_init(ctx, table, ft_list);
+
+			nftnl_flowtable_list_free(ft_list);
+
 			if (ret < 0) {
 				ret = -1;
 				goto cache_fails;
 			}
-			list_splice_tail_init(&ctx->list, &table->flowtables);
 		}
 		if (flags & NFT_CACHE_OBJECT_BIT) {
 			obj_list = obj_cache_dump(ctx, table, &ret);
diff --git a/src/evaluate.c b/src/evaluate.c
index 91cedf4ca021..8f35ca5935bc 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -238,7 +238,7 @@ static int flowtable_not_found(struct eval_ctx *ctx, const struct location *loc,
 	struct flowtable *ft;
 
 	ft = flowtable_lookup_fuzzy(ft_name, &ctx->nft->cache, &table);
-	if (ft == NULL)
+	if (!ft)
 		return cmd_error(ctx, loc, "%s", strerror(ENOENT));
 
 	return cmd_error(ctx, loc,
@@ -4491,8 +4491,8 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
 		if (table == NULL)
 			return table_not_found(ctx);
 
-		ft = flowtable_lookup(table, cmd->handle.flowtable.name);
-		if (ft == NULL)
+		ft = ft_cache_find(table, cmd->handle.flowtable.name);
+		if (!ft)
 			return flowtable_not_found(ctx, &ctx->cmd->handle.flowtable.location,
 						   ctx->cmd->handle.flowtable.name);
 
diff --git a/src/json.c b/src/json.c
index 0b7699a625b5..9358cbc3da8d 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1580,7 +1580,7 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx,
 		tmp = set_print_json(&ctx->nft->output, set);
 		json_array_append_new(root, tmp);
 	}
-	list_for_each_entry(flowtable, &table->flowtables, list) {
+	list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
 		tmp = flowtable_print_json(flowtable);
 		json_array_append_new(root, tmp);
 	}
@@ -1759,8 +1759,8 @@ static json_t *do_list_flowtable_json(struct netlink_ctx *ctx,
 	json_t *root = json_array();
 	struct flowtable *ft;
 
-	ft = flowtable_lookup(table, cmd->handle.flowtable.name);
-	if (ft == NULL)
+	ft = ft_cache_find(table, cmd->handle.flowtable.name);
+	if (!ft)
 		return json_null();
 
 	json_array_append_new(root, flowtable_print_json(ft));
@@ -1779,7 +1779,7 @@ static json_t *do_list_flowtables_json(struct netlink_ctx *ctx, struct cmd *cmd)
 		    cmd->handle.family != table->handle.family)
 			continue;
 
-		list_for_each_entry(flowtable, &table->flowtables, list) {
+		list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
 			tmp = flowtable_print_json(flowtable);
 			json_array_append_new(root, tmp);
 		}
diff --git a/src/netlink.c b/src/netlink.c
index 6323fe4e810f..5ed6d32fb292 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1534,7 +1534,7 @@ int netlink_reset_objs(struct netlink_ctx *ctx, const struct cmd *cmd,
 	return err;
 }
 
-static struct flowtable *
+struct flowtable *
 netlink_delinearize_flowtable(struct netlink_ctx *ctx,
 			      struct nftnl_flowtable *nlo)
 {
diff --git a/src/rule.c b/src/rule.c
index 56fb19c77e7d..95016320dfd3 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1115,6 +1115,7 @@ struct table *table_alloc(void)
 	cache_init(&table->chain_cache);
 	cache_init(&table->set_cache);
 	cache_init(&table->obj_cache);
+	cache_init(&table->ft_cache);
 
 	return table;
 }
@@ -1144,6 +1145,9 @@ void table_free(struct table *table)
 		set_free(set);
 	list_for_each_entry_safe(ft, nft, &table->flowtables, list)
 		flowtable_free(ft);
+	/* this is implicitly releasing flowtables in the hashtable cache */
+	list_for_each_entry_safe(ft, nft, &table->ft_cache.list, cache.list)
+		flowtable_free(ft);
 	list_for_each_entry_safe(obj, nobj, &table->objs, list)
 		obj_free(obj);
 	/* this is implicitly releasing objs in the hashtable cache */
@@ -1155,6 +1159,7 @@ void table_free(struct table *table)
 	cache_free(&table->chain_cache);
 	cache_free(&table->set_cache);
 	cache_free(&table->obj_cache);
+	cache_free(&table->ft_cache);
 	xfree(table);
 }
 
@@ -1272,7 +1277,7 @@ static void table_print(const struct table *table, struct output_ctx *octx)
 		set_print(set, octx);
 		delim = "\n";
 	}
-	list_for_each_entry(flowtable, &table->flowtables, list) {
+	list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
 		nft_print(octx, "%s", delim);
 		flowtable_print(flowtable, octx);
 		delim = "\n";
@@ -2146,11 +2151,6 @@ void flowtable_free(struct flowtable *flowtable)
 	xfree(flowtable);
 }
 
-void flowtable_add_hash(struct flowtable *flowtable, struct table *table)
-{
-	list_add_tail(&flowtable->list, &table->flowtables);
-}
-
 static void flowtable_print_declaration(const struct flowtable *flowtable,
 					struct print_fmt_options *opts,
 					struct output_ctx *octx)
@@ -2216,17 +2216,6 @@ void flowtable_print(const struct flowtable *s, struct output_ctx *octx)
 	do_flowtable_print(s, &opts, octx);
 }
 
-struct flowtable *flowtable_lookup(const struct table *table, const char *name)
-{
-	struct flowtable *ft;
-
-	list_for_each_entry(ft, &table->flowtables, list) {
-		if (!strcmp(ft->handle.flowtable.name, name))
-			return ft;
-	}
-	return NULL;
-}
-
 struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
 					 const struct nft_cache *cache,
 					 const struct table **t)
@@ -2238,7 +2227,7 @@ struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
 	string_misspell_init(&st);
 
 	list_for_each_entry(table, &cache->list, list) {
-		list_for_each_entry(ft, &table->flowtables, list) {
+		list_for_each_entry(ft, &table->ft_cache.list, cache.list) {
 			if (!strcmp(ft->handle.flowtable.name, ft_name)) {
 				*t = table;
 				return ft;
@@ -2256,8 +2245,8 @@ static int do_list_flowtable(struct netlink_ctx *ctx, struct cmd *cmd,
 {
 	struct flowtable *ft;
 
-	ft = flowtable_lookup(table, cmd->handle.flowtable.name);
-	if (ft == NULL)
+	ft = ft_cache_find(table, cmd->handle.flowtable.name);
+	if (!ft)
 		return -1;
 
 	nft_print(&ctx->nft->output, "table %s %s {\n",
@@ -2289,7 +2278,7 @@ static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd)
 			  family2str(table->handle.family),
 			  table->handle.table.name);
 
-		list_for_each_entry(flowtable, &table->flowtables, list) {
+		list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
 			flowtable_print_declaration(flowtable, &opts, &ctx->nft->output);
 			nft_print(&ctx->nft->output, "%s}%s", opts.tab, opts.nl);
 		}
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 09/18] cache: add set_cache_del() and use it
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (7 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 08/18] cache: add hashtable cache for flowtable Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 10/18] evaluate: add set to the cache Pablo Neira Ayuso
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Update set_cache_del() from the monitor path to remove sets
in the cache.

Fixes: df48e56e987f ("cache: add hashtable cache for sets")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/cache.h | 1 +
 src/cache.c     | 5 +++++
 src/monitor.c   | 2 +-
 3 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/include/cache.h b/include/cache.h
index 992f993c0667..f5b4876a4d40 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -70,6 +70,7 @@ struct chain;
 void chain_cache_add(struct chain *chain, struct table *table);
 struct chain *chain_cache_find(const struct table *table, const char *name);
 void set_cache_add(struct set *set, struct table *table);
+void set_cache_del(struct set *set);
 struct set *set_cache_find(const struct table *table, const char *name);
 
 struct cache {
diff --git a/src/cache.c b/src/cache.c
index 1aec12666d52..03b781bb4834 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -319,6 +319,11 @@ void set_cache_add(struct set *set, struct table *table)
 	cache_add(&set->cache, &table->set_cache, hash);
 }
 
+void set_cache_del(struct set *set)
+{
+	cache_del(&set->cache);
+}
+
 struct set *set_cache_find(const struct table *table, const char *name)
 {
 	struct set *set;
diff --git a/src/monitor.c b/src/monitor.c
index ae288f6cb212..00cf7d135034 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -687,7 +687,7 @@ out:
 static void netlink_events_cache_delset_cb(struct set *s,
 					   void *data)
 {
-	list_del(&s->list);
+	set_cache_del(s);
 	set_free(s);
 }
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 10/18] evaluate: add set to the cache
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (8 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 09/18] cache: add set_cache_del() and use it Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 11/18] evaluate: add flowtable " Pablo Neira Ayuso
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

If the cache does not contain the set that is defined in this batch, add
it to the cache. This allows for references to this new set in the same
batch.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/evaluate.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/evaluate.c b/src/evaluate.c
index 8f35ca5935bc..02115101fec3 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -3754,6 +3754,10 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
 	if (table == NULL)
 		return table_not_found(ctx);
 
+	if (!(set->flags & NFT_SET_ANONYMOUS) &&
+	    !set_cache_find(table, set->handle.set.name))
+		set_cache_add(set_get(set), table);
+
 	if (!(set->flags & NFT_SET_INTERVAL) && set->automerge)
 		return set_error(ctx, set, "auto-merge only works with interval sets");
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 11/18] evaluate: add flowtable to the cache
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (9 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 10/18] evaluate: add set to the cache Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 12/18] cache: missing table cache for several policy objects Pablo Neira Ayuso
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

If the cache does not contain this flowtable that is defined in this
batch, then add it to the cache. This allows for references to this new
flowtable in the same batch.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/evaluate.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/evaluate.c b/src/evaluate.c
index 02115101fec3..f4c1acef0b16 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -3961,6 +3961,9 @@ static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
 	if (table == NULL)
 		return table_not_found(ctx);
 
+	if (!ft_cache_find(table, ft->handle.flowtable.name))
+		ft_cache_add(flowtable_get(ft), table);
+
 	if (ft->hook.name) {
 		ft->hook.num = str2hooknum(NFPROTO_NETDEV, ft->hook.name);
 		if (ft->hook.num == NF_INET_NUMHOOKS)
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 12/18] cache: missing table cache for several policy objects
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (10 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 11/18] evaluate: add flowtable " Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 13/18] evaluate: add object to the cache Pablo Neira Ayuso
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Populate the cache with tables for several policy objects types.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/cache.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/cache.c b/src/cache.c
index 03b781bb4834..d1f8e8392b58 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -26,6 +26,10 @@ static unsigned int evaluate_cache_add(struct cmd *cmd, unsigned int flags)
 	case CMD_OBJ_QUOTA:
 	case CMD_OBJ_LIMIT:
 	case CMD_OBJ_SECMARK:
+	case CMD_OBJ_CT_HELPER:
+	case CMD_OBJ_CT_TIMEOUT:
+	case CMD_OBJ_CT_EXPECT:
+	case CMD_OBJ_SYNPROXY:
 	case CMD_OBJ_FLOWTABLE:
 		flags |= NFT_CACHE_TABLE;
 		break;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 13/18] evaluate: add object to the cache
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (11 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 12/18] cache: missing table cache for several policy objects Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 14/18] cache: add hashtable cache for table Pablo Neira Ayuso
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

If the cache does not contain this object that is defined in this batch,
add it to the cache. This allows for references to this new object in
the same batch.

This patch also adds missing handle_merge() to set the object name,
otherwise object name is NULL and obj_cache_find() crashes.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/evaluate.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/evaluate.c b/src/evaluate.c
index f4c1acef0b16..c5adf2cab7b5 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4246,6 +4246,15 @@ static int ct_timeout_evaluate(struct eval_ctx *ctx, struct obj *obj)
 
 static int obj_evaluate(struct eval_ctx *ctx, struct obj *obj)
 {
+	struct table *table;
+
+	table = table_lookup_global(ctx);
+	if (!table)
+		return table_not_found(ctx);
+
+	if (!obj_cache_find(table, obj->handle.obj.name, obj->type))
+		obj_cache_add(obj_get(obj), table);
+
 	switch (obj->type) {
 	case NFT_OBJECT_CT_TIMEOUT:
 		return ct_timeout_evaluate(ctx, obj);
@@ -4332,6 +4341,7 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
 	case CMD_OBJ_SECMARK:
 	case CMD_OBJ_CT_EXPECT:
 	case CMD_OBJ_SYNPROXY:
+		handle_merge(&cmd->object->handle, &cmd->handle);
 		return obj_evaluate(ctx, cmd->object);
 	default:
 		BUG("invalid command object type %u\n", cmd->obj);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 14/18] cache: add hashtable cache for table
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (12 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 13/18] evaluate: add object to the cache Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 15/18] evaluate: remove chain from cache on delete chain command Pablo Neira Ayuso
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Add a hashtable for fast table lookups.

Tables that reside in the cache use the table->cache_hlist and
table->cache_list heads.

Table that are created from command line / ruleset are also added
to the cache.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/cache.h           |  20 +++---
 include/rule.h            |   4 +-
 src/cache.c               |  48 ++++++++++++--
 src/evaluate.c            | 128 +++++++++++++++++++++++---------------
 src/json.c                |  16 ++---
 src/libnftables.c         |   3 +-
 src/monitor.c             |  16 +++--
 src/netlink.c             |   2 +-
 src/netlink_delinearize.c |   7 ++-
 src/rule.c                |  59 +++++++-----------
 10 files changed, 182 insertions(+), 121 deletions(-)

diff --git a/include/cache.h b/include/cache.h
index f5b4876a4d40..fddb843b510e 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -37,13 +37,7 @@ enum cache_level_flags {
 	NFT_CACHE_FLUSHED	= (1 << 31),
 };
 
-struct nft_cache {
-	uint32_t		genid;
-	struct list_head	list;
-	uint32_t		seqnum;
-	uint32_t		flags;
-};
-
+struct nft_cache;
 enum cmd_ops;
 
 unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds);
@@ -88,6 +82,11 @@ void cache_free(struct cache *cache);
 void cache_add(struct cache_item *item, struct cache *cache, uint32_t hash);
 void cache_del(struct cache_item *item);
 
+void table_cache_add(struct table *table, struct nft_cache *cache);
+void table_cache_del(struct table *table);
+struct table *table_cache_find(const struct cache *cache, const char *name,
+			       uint32_t family);
+
 void obj_cache_add(struct obj *obj, struct table *table);
 void obj_cache_del(struct obj *obj);
 struct obj *obj_cache_find(const struct table *table, const char *name,
@@ -97,4 +96,11 @@ struct flowtable;
 void ft_cache_add(struct flowtable *ft, struct table *table);
 struct flowtable *ft_cache_find(const struct table *table, const char *name);
 
+struct nft_cache {
+	uint32_t		genid;
+	struct cache		table_cache;
+	uint32_t		seqnum;
+	uint32_t		flags;
+};
+
 #endif /* _NFT_CACHE_H_ */
diff --git a/include/rule.h b/include/rule.h
index c6fd4c4c067b..fbd2c9a79b47 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -152,6 +152,7 @@ const char *table_flag_name(uint32_t flag);
  */
 struct table {
 	struct list_head	list;
+	struct cache_item	cache;
 	struct handle		handle;
 	struct location		location;
 	struct scope		scope;
@@ -173,9 +174,6 @@ struct table {
 extern struct table *table_alloc(void);
 extern struct table *table_get(struct table *table);
 extern void table_free(struct table *table);
-extern void table_add_hash(struct table *table, struct nft_cache *cache);
-extern struct table *table_lookup(const struct handle *h,
-				  const struct nft_cache *cache);
 extern struct table *table_lookup_fuzzy(const struct handle *h,
 					const struct nft_cache *cache);
 
diff --git a/src/cache.c b/src/cache.c
index d1f8e8392b58..3c139f1a5dbb 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -173,6 +173,38 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
 	return flags;
 }
 
+void table_cache_add(struct table *table, struct nft_cache *cache)
+{
+	uint32_t hash;
+
+	hash = djb_hash(table->handle.table.name) % NFT_CACHE_HSIZE;
+	cache_add(&table->cache, &cache->table_cache, hash);
+}
+
+void table_cache_del(struct table *table)
+{
+	cache_del(&table->cache);
+}
+
+struct table *table_cache_find(const struct cache *cache,
+			       const char *name, uint32_t family)
+{
+	struct table *table;
+	uint32_t hash;
+
+	if (!name)
+		return NULL;
+
+	hash = djb_hash(name) % NFT_CACHE_HSIZE;
+	list_for_each_entry(table, &cache->ht[hash], cache.hlist) {
+		if (table->handle.family == family &&
+		    !strcmp(table->handle.table.name, name))
+			return table;
+	}
+
+	return NULL;
+}
+
 struct chain_cache_dump_ctx {
 	struct netlink_ctx	*nlctx;
 	struct table		*table;
@@ -507,13 +539,17 @@ struct flowtable *ft_cache_find(const struct table *table, const char *name)
 static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
 			     struct nft_cache *cache)
 {
+	struct table *table, *next;
 	int ret;
 
 	ret = netlink_list_tables(ctx, h);
 	if (ret < 0)
 		return -1;
 
-	list_splice_tail_init(&ctx->list, &cache->list);
+	list_for_each_entry_safe(table, next, &ctx->list, list) {
+		list_del(&table->list);
+		table_cache_add(table, cache);
+	}
 
 	return 0;
 }
@@ -536,7 +572,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
 			return -1;
 	}
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (flags & NFT_CACHE_SET_BIT) {
 			set_list = set_cache_dump(ctx, table, &ret);
 			if (!set_list) {
@@ -719,19 +755,19 @@ skip:
 	return 0;
 }
 
-static void nft_cache_flush(struct list_head *table_list)
+static void nft_cache_flush(struct cache *table_cache)
 {
 	struct table *table, *next;
 
-	list_for_each_entry_safe(table, next, table_list, list) {
-		list_del(&table->list);
+	list_for_each_entry_safe(table, next, &table_cache->list, cache.list) {
+		table_cache_del(table);
 		table_free(table);
 	}
 }
 
 void nft_cache_release(struct nft_cache *cache)
 {
-	nft_cache_flush(&cache->list);
+	nft_cache_flush(&cache->table_cache);
 	cache->genid = 0;
 	cache->flags = NFT_CACHE_EMPTY;
 }
diff --git a/src/evaluate.c b/src/evaluate.c
index c5adf2cab7b5..e770cffa6d99 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -166,20 +166,6 @@ static int byteorder_conversion(struct eval_ctx *ctx, struct expr **expr,
 	return 0;
 }
 
-static struct table *table_lookup_global(struct eval_ctx *ctx)
-{
-	struct table *table;
-
-	if (ctx->table != NULL)
-		return ctx->table;
-
-	table = table_lookup(&ctx->cmd->handle, &ctx->nft->cache);
-	if (table == NULL)
-		return NULL;
-
-	return table;
-}
-
 static int table_not_found(struct eval_ctx *ctx)
 {
 	struct table *table;
@@ -269,7 +255,9 @@ static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
 		}
 		break;
 	case SYMBOL_SET:
-		table = table_lookup_global(ctx);
+		table = table_cache_find(&ctx->nft->cache.table_cache,
+					 ctx->cmd->handle.table.name,
+					 ctx->cmd->handle.family);
 		if (table == NULL)
 			return table_not_found(ctx);
 
@@ -3709,7 +3697,9 @@ static int setelem_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
 	struct table *table;
 	struct set *set;
 
-	table = table_lookup_global(ctx);
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 ctx->cmd->handle.table.name,
+				 ctx->cmd->handle.family);
 	if (table == NULL)
 		return table_not_found(ctx);
 
@@ -3750,7 +3740,9 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
 	struct stmt *stmt;
 	const char *type;
 
-	table = table_lookup_global(ctx);
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 ctx->cmd->handle.table.name,
+				 ctx->cmd->handle.family);
 	if (table == NULL)
 		return table_not_found(ctx);
 
@@ -3957,7 +3949,9 @@ static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
 {
 	struct table *table;
 
-	table = table_lookup_global(ctx);
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 ctx->cmd->handle.table.name,
+				 ctx->cmd->handle.family);
 	if (table == NULL)
 		return table_not_found(ctx);
 
@@ -4005,7 +3999,9 @@ static int rule_cache_update(struct eval_ctx *ctx, enum cmd_ops op)
 	struct table *table;
 	struct chain *chain;
 
-	table = table_lookup(&rule->handle, &ctx->nft->cache);
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 rule->handle.table.name,
+				 rule->handle.family);
 	if (!table)
 		return table_not_found(ctx);
 
@@ -4147,7 +4143,9 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
 	struct table *table;
 	struct rule *rule;
 
-	table = table_lookup_global(ctx);
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 ctx->cmd->handle.table.name,
+				 ctx->cmd->handle.family);
 	if (table == NULL)
 		return table_not_found(ctx);
 
@@ -4248,7 +4246,9 @@ static int obj_evaluate(struct eval_ctx *ctx, struct obj *obj)
 {
 	struct table *table;
 
-	table = table_lookup_global(ctx);
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 ctx->cmd->handle.table.name,
+				 ctx->cmd->handle.family);
 	if (!table)
 		return table_not_found(ctx);
 
@@ -4274,13 +4274,15 @@ static int table_evaluate(struct eval_ctx *ctx, struct table *table)
 	struct set *set;
 	struct obj *obj;
 
-	if (table_lookup(&ctx->cmd->handle, &ctx->nft->cache) == NULL) {
-		if (table == NULL) {
+	if (!table_cache_find(&ctx->nft->cache.table_cache,
+			      ctx->cmd->handle.table.name,
+			      ctx->cmd->handle.family)) {
+		if (!table) {
 			table = table_alloc();
 			handle_merge(&table->handle, &ctx->cmd->handle);
-			table_add_hash(table, &ctx->nft->cache);
+			table_cache_add(table, &ctx->nft->cache);
 		} else {
-			table_add_hash(table_get(table), &ctx->nft->cache);
+			table_cache_add(table_get(table), &ctx->nft->cache);
 		}
 	}
 
@@ -4355,11 +4357,13 @@ static void table_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
 	if (!cmd->handle.table.name)
 		return;
 
-	table = table_lookup(&cmd->handle, &ctx->nft->cache);
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 cmd->handle.table.name,
+				 cmd->handle.family);
 	if (!table)
 		return;
 
-	list_del(&table->list);
+	table_cache_del(table);
 	table_free(table);
 }
 
@@ -4425,7 +4429,9 @@ static int cmd_evaluate_list_obj(struct eval_ctx *ctx, const struct cmd *cmd,
 	if (obj_type == NFT_OBJECT_UNSPEC)
 		obj_type = NFT_OBJECT_COUNTER;
 
-	table = table_lookup(&cmd->handle, &ctx->nft->cache);
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 cmd->handle.table.name,
+				 cmd->handle.family);
 	if (table == NULL)
 		return table_not_found(ctx);
 
@@ -4447,14 +4453,18 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
 		if (cmd->handle.table.name == NULL)
 			return 0;
 
-		table = table_lookup(&cmd->handle, &ctx->nft->cache);
-		if (table == NULL)
+		table = table_cache_find(&ctx->nft->cache.table_cache,
+					 cmd->handle.table.name,
+					 cmd->handle.family);
+		if (!table)
 			return table_not_found(ctx);
 
 		return 0;
 	case CMD_OBJ_SET:
-		table = table_lookup(&cmd->handle, &ctx->nft->cache);
-		if (table == NULL)
+		table = table_cache_find(&ctx->nft->cache.table_cache,
+					 cmd->handle.table.name,
+					 cmd->handle.family);
+		if (!table)
 			return table_not_found(ctx);
 
 		set = set_cache_find(table, cmd->handle.set.name);
@@ -4467,8 +4477,10 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
 
 		return 0;
 	case CMD_OBJ_METER:
-		table = table_lookup(&cmd->handle, &ctx->nft->cache);
-		if (table == NULL)
+		table = table_cache_find(&ctx->nft->cache.table_cache,
+					 cmd->handle.table.name,
+					 cmd->handle.family);
+		if (!table)
 			return table_not_found(ctx);
 
 		set = set_cache_find(table, cmd->handle.set.name);
@@ -4481,8 +4493,10 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
 
 		return 0;
 	case CMD_OBJ_MAP:
-		table = table_lookup(&cmd->handle, &ctx->nft->cache);
-		if (table == NULL)
+		table = table_cache_find(&ctx->nft->cache.table_cache,
+					 cmd->handle.table.name,
+					 cmd->handle.family);
+		if (!table)
 			return table_not_found(ctx);
 
 		set = set_cache_find(table, cmd->handle.set.name);
@@ -4495,8 +4509,10 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
 
 		return 0;
 	case CMD_OBJ_CHAIN:
-		table = table_lookup(&cmd->handle, &ctx->nft->cache);
-		if (table == NULL)
+		table = table_cache_find(&ctx->nft->cache.table_cache,
+					 cmd->handle.table.name,
+					 cmd->handle.family);
+		if (!table)
 			return table_not_found(ctx);
 
 		if (!chain_cache_find(table, cmd->handle.chain.name))
@@ -4504,8 +4520,10 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
 
 		return 0;
 	case CMD_OBJ_FLOWTABLE:
-		table = table_lookup(&cmd->handle, &ctx->nft->cache);
-		if (table == NULL)
+		table = table_cache_find(&ctx->nft->cache.table_cache,
+					 cmd->handle.table.name,
+					 cmd->handle.family);
+		if (!table)
 			return table_not_found(ctx);
 
 		ft = ft_cache_find(table, cmd->handle.flowtable.name);
@@ -4540,7 +4558,9 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
 	case CMD_OBJ_SYNPROXYS:
 		if (cmd->handle.table.name == NULL)
 			return 0;
-		if (table_lookup(&cmd->handle, &ctx->nft->cache) == NULL)
+		if (!table_cache_find(&ctx->nft->cache.table_cache,
+				      cmd->handle.table.name,
+				      cmd->handle.family))
 			return table_not_found(ctx);
 
 		return 0;
@@ -4563,7 +4583,9 @@ static int cmd_evaluate_reset(struct eval_ctx *ctx, struct cmd *cmd)
 	case CMD_OBJ_QUOTAS:
 		if (cmd->handle.table.name == NULL)
 			return 0;
-		if (table_lookup(&cmd->handle, &ctx->nft->cache) == NULL)
+		if (!table_cache_find(&ctx->nft->cache.table_cache,
+				      cmd->handle.table.name,
+				      cmd->handle.family))
 			return table_not_found(ctx);
 
 		return 0;
@@ -4582,6 +4604,7 @@ static void __flush_set_cache(struct set *set)
 
 static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
 {
+	struct cache *table_cache = &ctx->nft->cache.table_cache;
 	struct table *table;
 	struct set *set;
 
@@ -4596,8 +4619,9 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
 		/* Chains don't hold sets */
 		break;
 	case CMD_OBJ_SET:
-		table = table_lookup(&cmd->handle, &ctx->nft->cache);
-		if (table == NULL)
+		table = table_cache_find(table_cache, cmd->handle.table.name,
+					 cmd->handle.family);
+		if (!table)
 			return table_not_found(ctx);
 
 		set = set_cache_find(table, cmd->handle.set.name);
@@ -4612,8 +4636,9 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
 
 		return 0;
 	case CMD_OBJ_MAP:
-		table = table_lookup(&cmd->handle, &ctx->nft->cache);
-		if (table == NULL)
+		table = table_cache_find(table_cache, cmd->handle.table.name,
+					 cmd->handle.family);
+		if (!table)
 			return table_not_found(ctx);
 
 		set = set_cache_find(table, cmd->handle.set.name);
@@ -4628,8 +4653,9 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
 
 		return 0;
 	case CMD_OBJ_METER:
-		table = table_lookup(&cmd->handle, &ctx->nft->cache);
-		if (table == NULL)
+		table = table_cache_find(table_cache, cmd->handle.table.name,
+					 cmd->handle.family);
+		if (!table)
 			return table_not_found(ctx);
 
 		set = set_cache_find(table, cmd->handle.set.name);
@@ -4655,8 +4681,10 @@ static int cmd_evaluate_rename(struct eval_ctx *ctx, struct cmd *cmd)
 
 	switch (cmd->obj) {
 	case CMD_OBJ_CHAIN:
-		table = table_lookup(&ctx->cmd->handle, &ctx->nft->cache);
-		if (table == NULL)
+		table = table_cache_find(&ctx->nft->cache.table_cache,
+					 cmd->handle.table.name,
+					 cmd->handle.family);
+		if (!table)
 			return table_not_found(ctx);
 
 		if (!chain_cache_find(table, ctx->cmd->handle.chain.name))
diff --git a/src/json.c b/src/json.c
index 9358cbc3da8d..b4197b2fef0c 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1603,7 +1603,7 @@ static json_t *do_list_ruleset_json(struct netlink_ctx *ctx, struct cmd *cmd)
 	json_t *root = json_array(), *tmp;
 	struct table *table;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (family != NFPROTO_UNSPEC &&
 		    table->handle.family != family)
 			continue;
@@ -1622,7 +1622,7 @@ static json_t *do_list_tables_json(struct netlink_ctx *ctx, struct cmd *cmd)
 	json_t *root = json_array();
 	struct table *table;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (family != NFPROTO_UNSPEC &&
 		    table->handle.family != family)
 			continue;
@@ -1669,7 +1669,7 @@ static json_t *do_list_chains_json(struct netlink_ctx *ctx, struct cmd *cmd)
 	struct table *table;
 	struct chain *chain;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (cmd->handle.family != NFPROTO_UNSPEC &&
 		    cmd->handle.family != table->handle.family)
 			continue;
@@ -1702,7 +1702,7 @@ static json_t *do_list_sets_json(struct netlink_ctx *ctx, struct cmd *cmd)
 	struct table *table;
 	struct set *set;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (cmd->handle.family != NFPROTO_UNSPEC &&
 		    cmd->handle.family != table->handle.family)
 			continue;
@@ -1731,7 +1731,7 @@ static json_t *do_list_obj_json(struct netlink_ctx *ctx,
 	struct table *table;
 	struct obj *obj;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (cmd->handle.family != NFPROTO_UNSPEC &&
 		    cmd->handle.family != table->handle.family)
 			continue;
@@ -1774,7 +1774,7 @@ static json_t *do_list_flowtables_json(struct netlink_ctx *ctx, struct cmd *cmd)
 	struct flowtable *flowtable;
 	struct table *table;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (cmd->handle.family != NFPROTO_UNSPEC &&
 		    cmd->handle.family != table->handle.family)
 			continue;
@@ -1802,7 +1802,9 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
 	json_t *root;
 
 	if (cmd->handle.table.name)
-		table = table_lookup(&cmd->handle, &ctx->nft->cache);
+		table = table_cache_find(&ctx->nft->cache.table_cache,
+					 cmd->handle.table.name,
+					 cmd->handle.family);
 
 	switch (cmd->obj) {
 	case CMD_OBJ_TABLE:
diff --git a/src/libnftables.c b/src/libnftables.c
index 56c51a6104ac..e080eb032770 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -105,6 +105,7 @@ static void nft_init(struct nft_ctx *ctx)
 
 static void nft_exit(struct nft_ctx *ctx)
 {
+	cache_free(&ctx->cache.table_cache);
 	expr_handler_exit();
 	ct_label_table_exit(ctx);
 	realm_table_rt_exit(ctx);
@@ -166,7 +167,7 @@ struct nft_ctx *nft_ctx_new(uint32_t flags)
 	ctx->state = xzalloc(sizeof(struct parser_state));
 	nft_ctx_add_include_path(ctx, DEFAULT_INCLUDE_PATH);
 	ctx->parser_max_errors	= 10;
-	init_list_head(&ctx->cache.list);
+	cache_init(&ctx->cache.table_cache);
 	ctx->top_scope = scope_alloc();
 	ctx->flags = flags;
 	ctx->output.output_fp = stdout;
diff --git a/src/monitor.c b/src/monitor.c
index 00cf7d135034..144fe96c2898 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -575,7 +575,7 @@ static void netlink_events_cache_addtable(struct netlink_mon_handler *monh,
 	t = netlink_delinearize_table(monh->ctx, nlt);
 	nftnl_table_free(nlt);
 
-	table_add_hash(t, &monh->ctx->nft->cache);
+	table_cache_add(t, &monh->ctx->nft->cache);
 }
 
 static void netlink_events_cache_deltable(struct netlink_mon_handler *monh,
@@ -589,11 +589,12 @@ static void netlink_events_cache_deltable(struct netlink_mon_handler *monh,
 	h.family = nftnl_table_get_u32(nlt, NFTNL_TABLE_FAMILY);
 	h.table.name  = nftnl_table_get_str(nlt, NFTNL_TABLE_NAME);
 
-	t = table_lookup(&h, &monh->ctx->nft->cache);
+	t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+			     h.table.name, h.family);
 	if (t == NULL)
 		goto out;
 
-	list_del(&t->list);
+	table_cache_del(t);
 	table_free(t);
 out:
 	nftnl_table_free(nlt);
@@ -619,7 +620,8 @@ static void netlink_events_cache_addset(struct netlink_mon_handler *monh,
 		goto out;
 	s->init = set_expr_alloc(monh->loc, s);
 
-	t = table_lookup(&s->handle, &monh->ctx->nft->cache);
+	t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+			     s->handle.table.name, s->handle.family);
 	if (t == NULL) {
 		fprintf(stderr, "W: Unable to cache set: table not found.\n");
 		set_free(s);
@@ -720,7 +722,8 @@ static void netlink_events_cache_addobj(struct netlink_mon_handler *monh,
 	if (obj == NULL)
 		goto out;
 
-	t = table_lookup(&obj->handle, &monh->ctx->nft->cache);
+	t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+			     obj->handle.table.name, obj->handle.family);
 	if (t == NULL) {
 		fprintf(stderr, "W: Unable to cache object: table not found.\n");
 		obj_free(obj);
@@ -750,7 +753,8 @@ static void netlink_events_cache_delobj(struct netlink_mon_handler *monh,
 	type	 = nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE);
 	h.handle.id	= nftnl_obj_get_u64(nlo, NFTNL_OBJ_HANDLE);
 
-	t = table_lookup(&h, &monh->ctx->nft->cache);
+	t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+			     h.table.name, h.family);
 	if (t == NULL) {
 		fprintf(stderr, "W: Unable to cache object: table not found.\n");
 		goto out;
diff --git a/src/netlink.c b/src/netlink.c
index 5ed6d32fb292..e4926a80d79a 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1695,7 +1695,7 @@ static struct rule *trace_lookup_rule(const struct nftnl_trace *nlt,
 	if (!h.table.name)
 		return NULL;
 
-	table = table_lookup(&h, cache);
+	table = table_cache_find(&cache->table_cache, h.table.name, h.family);
 	if (!table)
 		return NULL;
 
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 710c668a0258..d82d9f51f482 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1792,7 +1792,9 @@ struct stmt *netlink_parse_set_expr(const struct set *set,
 
 	handle_merge(&h, &set->handle);
 	pctx->rule = rule_alloc(&netlink_location, &h);
-	pctx->table = table_lookup(&set->handle, cache);
+	pctx->table = table_cache_find(&cache->table_cache,
+				       set->handle.table.name,
+				       set->handle.family);
 	assert(pctx->table != NULL);
 
 	if (netlink_parse_expr(nle, pctx) < 0)
@@ -2938,7 +2940,8 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
 		h.position.id = nftnl_rule_get_u64(nlr, NFTNL_RULE_POSITION);
 
 	pctx->rule = rule_alloc(&netlink_location, &h);
-	pctx->table = table_lookup(&h, &ctx->nft->cache);
+	pctx->table = table_cache_find(&ctx->nft->cache.table_cache,
+				       h.table.name, h.family);
 	assert(pctx->table != NULL);
 
 	pctx->rule->comment = nftnl_rule_get_comment(nlr);
diff --git a/src/rule.c b/src/rule.c
index 95016320dfd3..07a541a20bb9 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -211,7 +211,7 @@ struct set *set_lookup_fuzzy(const char *set_name,
 
 	string_misspell_init(&st);
 
-	list_for_each_entry(table, &cache->list, list) {
+	list_for_each_entry(table, &cache->table_cache.list, cache.list) {
 		list_for_each_entry(set, &table->set_cache.list, cache.list) {
 			if (set_is_anonymous(set->flags))
 				continue;
@@ -230,13 +230,9 @@ struct set *set_lookup_fuzzy(const char *set_name,
 struct set *set_lookup_global(uint32_t family, const char *table,
 			      const char *name, struct nft_cache *cache)
 {
-	struct handle h;
 	struct table *t;
 
-	h.family = family;
-	h.table.name = table;
-
-	t = table_lookup(&h, cache);
+	t = table_cache_find(&cache->table_cache, table, family);
 	if (t == NULL)
 		return NULL;
 
@@ -767,7 +763,7 @@ struct chain *chain_lookup_fuzzy(const struct handle *h,
 
 	string_misspell_init(&st);
 
-	list_for_each_entry(table, &cache->list, list) {
+	list_for_each_entry(table, &cache->table_cache.list, cache.list) {
 		list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
 			if (!strcmp(chain->handle.chain.name, h->chain.name)) {
 				*t = table;
@@ -1169,24 +1165,6 @@ struct table *table_get(struct table *table)
 	return table;
 }
 
-void table_add_hash(struct table *table, struct nft_cache *cache)
-{
-	list_add_tail(&table->list, &cache->list);
-}
-
-struct table *table_lookup(const struct handle *h,
-			   const struct nft_cache *cache)
-{
-	struct table *table;
-
-	list_for_each_entry(table, &cache->list, list) {
-		if (table->handle.family == h->family &&
-		    !strcmp(table->handle.table.name, h->table.name))
-			return table;
-	}
-	return NULL;
-}
-
 struct table *table_lookup_fuzzy(const struct handle *h,
 				 const struct nft_cache *cache)
 {
@@ -1195,7 +1173,7 @@ struct table *table_lookup_fuzzy(const struct handle *h,
 
 	string_misspell_init(&st);
 
-	list_for_each_entry(table, &cache->list, list) {
+	list_for_each_entry(table, &cache->table_cache.list, cache.list) {
 		if (!strcmp(table->handle.table.name, h->table.name))
 			return table;
 
@@ -1683,7 +1661,7 @@ static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
 	struct table *table;
 	struct set *set;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (cmd->handle.family != NFPROTO_UNSPEC &&
 		    cmd->handle.family != table->handle.family)
 			continue;
@@ -1748,7 +1726,7 @@ struct obj *obj_lookup_fuzzy(const char *obj_name,
 
 	string_misspell_init(&st);
 
-	list_for_each_entry(table, &cache->list, list) {
+	list_for_each_entry(table, &cache->table_cache.list, cache.list) {
 		list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
 			if (!strcmp(obj->handle.obj.name, obj_name)) {
 				*t = table;
@@ -2085,7 +2063,7 @@ static int do_list_obj(struct netlink_ctx *ctx, struct cmd *cmd, uint32_t type)
 	struct table *table;
 	struct obj *obj;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (cmd->handle.family != NFPROTO_UNSPEC &&
 		    cmd->handle.family != table->handle.family)
 			continue;
@@ -2226,7 +2204,7 @@ struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
 
 	string_misspell_init(&st);
 
-	list_for_each_entry(table, &cache->list, list) {
+	list_for_each_entry(table, &cache->table_cache.list, cache.list) {
 		list_for_each_entry(ft, &table->ft_cache.list, cache.list) {
 			if (!strcmp(ft->handle.flowtable.name, ft_name)) {
 				*t = table;
@@ -2269,7 +2247,7 @@ static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd)
 	struct flowtable *flowtable;
 	struct table *table;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (cmd->handle.family != NFPROTO_UNSPEC &&
 		    cmd->handle.family != table->handle.family)
 			continue;
@@ -2293,7 +2271,7 @@ static int do_list_ruleset(struct netlink_ctx *ctx, struct cmd *cmd)
 	unsigned int family = cmd->handle.family;
 	struct table *table;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (family != NFPROTO_UNSPEC &&
 		    table->handle.family != family)
 			continue;
@@ -2314,7 +2292,7 @@ static int do_list_tables(struct netlink_ctx *ctx, struct cmd *cmd)
 {
 	struct table *table;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (cmd->handle.family != NFPROTO_UNSPEC &&
 		    cmd->handle.family != table->handle.family)
 			continue;
@@ -2360,7 +2338,7 @@ static int do_list_chains(struct netlink_ctx *ctx, struct cmd *cmd)
 	struct table *table;
 	struct chain *chain;
 
-	list_for_each_entry(table, &ctx->nft->cache.list, list) {
+	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (cmd->handle.family != NFPROTO_UNSPEC &&
 		    cmd->handle.family != table->handle.family)
 			continue;
@@ -2413,8 +2391,9 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
 		return do_command_list_json(ctx, cmd);
 
 	if (cmd->handle.table.name != NULL)
-		table = table_lookup(&cmd->handle, &ctx->nft->cache);
-
+		table = table_cache_find(&ctx->nft->cache.table_cache,
+					 cmd->handle.table.name,
+					 cmd->handle.family);
 	switch (cmd->obj) {
 	case CMD_OBJ_TABLE:
 		if (!cmd->handle.table.name)
@@ -2540,7 +2519,9 @@ static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd)
 
 	ret = netlink_reset_objs(ctx, cmd, type, dump);
 	list_for_each_entry_safe(obj, next, &ctx->list, list) {
-		table = table_lookup(&obj->handle, &ctx->nft->cache);
+		table = table_cache_find(&ctx->nft->cache.table_cache,
+					 obj->handle.table.name,
+					 obj->handle.family);
 		if (!obj_cache_find(table, obj->handle.obj.name, obj->type)) {
 			list_del(&obj->list);
 			obj_cache_add(obj, table);
@@ -2572,7 +2553,9 @@ static int do_command_flush(struct netlink_ctx *ctx, struct cmd *cmd)
 
 static int do_command_rename(struct netlink_ctx *ctx, struct cmd *cmd)
 {
-	struct table *table = table_lookup(&cmd->handle, &ctx->nft->cache);
+	struct table *table = table_cache_find(&ctx->nft->cache.table_cache,
+					       cmd->handle.table.name,
+					       cmd->handle.family);
 	const struct chain *chain;
 
 	switch (cmd->obj) {
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 15/18] evaluate: remove chain from cache on delete chain command
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (13 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 14/18] cache: add hashtable cache for table Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 16/18] evaluate: remove set from cache on delete set command Pablo Neira Ayuso
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Update the cache to remove this chain from the evaluation phase. Add
chain_cache_del() function for this purpose.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/cache.h |  2 ++
 src/cache.c     |  5 +++++
 src/evaluate.c  | 24 ++++++++++++++++++++++++
 3 files changed, 31 insertions(+)

diff --git a/include/cache.h b/include/cache.h
index fddb843b510e..3823e9a78653 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -62,7 +62,9 @@ struct table;
 struct chain;
 
 void chain_cache_add(struct chain *chain, struct table *table);
+void chain_cache_del(struct chain *chain);
 struct chain *chain_cache_find(const struct table *table, const char *name);
+
 void set_cache_add(struct set *set, struct table *table);
 void set_cache_del(struct set *set);
 struct set *set_cache_find(const struct table *table, const char *name);
diff --git a/src/cache.c b/src/cache.c
index 3c139f1a5dbb..a98ee5954c36 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -278,6 +278,11 @@ void chain_cache_add(struct chain *chain, struct table *table)
 	cache_add(&chain->cache, &table->chain_cache, hash);
 }
 
+void chain_cache_del(struct chain *chain)
+{
+	cache_del(&chain->cache);
+}
+
 struct chain *chain_cache_find(const struct table *table, const char *name)
 {
 	struct chain *chain;
diff --git a/src/evaluate.c b/src/evaluate.c
index e770cffa6d99..49d47d0b4f34 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4367,6 +4367,28 @@ static void table_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
 	table_free(table);
 }
 
+static void chain_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
+{
+	struct table *table;
+	struct chain *chain;
+
+	if (!cmd->handle.chain.name)
+		return;
+
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 cmd->handle.table.name,
+				 cmd->handle.family);
+	if (!table)
+		return;
+
+	chain = chain_cache_find(table, cmd->handle.chain.name);
+	if (!chain)
+		return;
+
+	chain_cache_del(chain);
+	chain_free(chain);
+}
+
 static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
 {
 	switch (cmd->obj) {
@@ -4374,7 +4396,9 @@ static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
 		return setelem_evaluate(ctx, cmd);
 	case CMD_OBJ_SET:
 	case CMD_OBJ_RULE:
+		return 0;
 	case CMD_OBJ_CHAIN:
+		chain_del_cache(ctx, cmd);
 		return 0;
 	case CMD_OBJ_TABLE:
 		table_del_cache(ctx, cmd);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 16/18] evaluate: remove set from cache on delete set command
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (14 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 15/18] evaluate: remove chain from cache on delete chain command Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 17/18] evaluate: remove flowtable from cache on delete flowtable command Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 18/18] evaluate: remove object from cache on delete object command Pablo Neira Ayuso
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Update the cache to remove this set from the evaluation phase.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/evaluate.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/src/evaluate.c b/src/evaluate.c
index 49d47d0b4f34..19bf73878181 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4389,12 +4389,36 @@ static void chain_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
 	chain_free(chain);
 }
 
+static void set_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
+{
+	struct table *table;
+	struct set *set;
+
+	if (!cmd->handle.set.name)
+		return;
+
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 cmd->handle.table.name,
+				 cmd->handle.family);
+	if (!table)
+		return;
+
+	set = set_cache_find(table, cmd->handle.set.name);
+	if (!set)
+		return;
+
+	set_cache_del(set);
+	set_free(set);
+}
+
 static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
 {
 	switch (cmd->obj) {
 	case CMD_OBJ_ELEMENTS:
 		return setelem_evaluate(ctx, cmd);
 	case CMD_OBJ_SET:
+		set_del_cache(ctx, cmd);
+		return 0;
 	case CMD_OBJ_RULE:
 		return 0;
 	case CMD_OBJ_CHAIN:
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 17/18] evaluate: remove flowtable from cache on delete flowtable command
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (15 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 16/18] evaluate: remove set from cache on delete set command Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  2021-04-29 23:42 ` [PATCH nft 18/18] evaluate: remove object from cache on delete object command Pablo Neira Ayuso
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Update the cache to remove this flowtable from the evaluation phase.
Add flowtable_cache_del() function for this purpose.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/cache.h |  1 +
 src/cache.c     |  5 +++++
 src/evaluate.c  | 24 ++++++++++++++++++++++++
 3 files changed, 30 insertions(+)

diff --git a/include/cache.h b/include/cache.h
index 3823e9a78653..ad9078432c73 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -96,6 +96,7 @@ struct obj *obj_cache_find(const struct table *table, const char *name,
 
 struct flowtable;
 void ft_cache_add(struct flowtable *ft, struct table *table);
+void ft_cache_del(struct flowtable *ft);
 struct flowtable *ft_cache_find(const struct table *table, const char *name);
 
 struct nft_cache {
diff --git a/src/cache.c b/src/cache.c
index a98ee5954c36..f59bba03b81e 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -527,6 +527,11 @@ void ft_cache_add(struct flowtable *ft, struct table *table)
 	cache_add(&ft->cache, &table->ft_cache, hash);
 }
 
+void ft_cache_del(struct flowtable *ft)
+{
+	cache_del(&ft->cache);
+}
+
 struct flowtable *ft_cache_find(const struct table *table, const char *name)
 {
 	struct flowtable *ft;
diff --git a/src/evaluate.c b/src/evaluate.c
index 19bf73878181..97a77657bbd6 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4411,6 +4411,28 @@ static void set_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
 	set_free(set);
 }
 
+static void ft_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
+{
+	struct flowtable *ft;
+	struct table *table;
+
+	if (!cmd->handle.flowtable.name)
+		return;
+
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 cmd->handle.table.name,
+				 cmd->handle.family);
+	if (!table)
+		return;
+
+	ft = ft_cache_find(table, cmd->handle.flowtable.name);
+	if (!ft)
+		return;
+
+	ft_cache_del(ft);
+	flowtable_free(ft);
+}
+
 static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
 {
 	switch (cmd->obj) {
@@ -4428,6 +4450,8 @@ static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
 		table_del_cache(ctx, cmd);
 		return 0;
 	case CMD_OBJ_FLOWTABLE:
+		ft_del_cache(ctx, cmd);
+		return 0;
 	case CMD_OBJ_COUNTER:
 	case CMD_OBJ_QUOTA:
 	case CMD_OBJ_CT_HELPER:
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH nft 18/18] evaluate: remove object from cache on delete object command
  2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
                   ` (16 preceding siblings ...)
  2021-04-29 23:42 ` [PATCH nft 17/18] evaluate: remove flowtable from cache on delete flowtable command Pablo Neira Ayuso
@ 2021-04-29 23:42 ` Pablo Neira Ayuso
  17 siblings, 0 replies; 19+ messages in thread
From: Pablo Neira Ayuso @ 2021-04-29 23:42 UTC (permalink / raw)
  To: netfilter-devel

Update the cache to remove this object from the evaluation phase.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/evaluate.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/src/evaluate.c b/src/evaluate.c
index 97a77657bbd6..b5dcdd3542f1 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4433,6 +4433,28 @@ static void ft_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
 	flowtable_free(ft);
 }
 
+static void obj_del_cache(struct eval_ctx *ctx, struct cmd *cmd, int type)
+{
+	struct table *table;
+	struct obj *obj;
+
+	if (!cmd->handle.obj.name)
+		return;
+
+	table = table_cache_find(&ctx->nft->cache.table_cache,
+				 cmd->handle.table.name,
+				 cmd->handle.family);
+	if (!table)
+		return;
+
+	obj = obj_cache_find(table, cmd->handle.obj.name, type);
+	if (!obj)
+		return;
+
+	obj_cache_del(obj);
+	obj_free(obj);
+}
+
 static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
 {
 	switch (cmd->obj) {
@@ -4453,13 +4475,28 @@ static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
 		ft_del_cache(ctx, cmd);
 		return 0;
 	case CMD_OBJ_COUNTER:
+		obj_del_cache(ctx, cmd, NFT_OBJECT_COUNTER);
+		return 0;
 	case CMD_OBJ_QUOTA:
+		obj_del_cache(ctx, cmd, NFT_OBJECT_QUOTA);
+		return 0;
 	case CMD_OBJ_CT_HELPER:
+		obj_del_cache(ctx, cmd, NFT_OBJECT_CT_HELPER);
+		return 0;
 	case CMD_OBJ_CT_TIMEOUT:
+		obj_del_cache(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
+		return 0;
 	case CMD_OBJ_LIMIT:
+		obj_del_cache(ctx, cmd, NFT_OBJECT_LIMIT);
+		return 0;
 	case CMD_OBJ_SECMARK:
+		obj_del_cache(ctx, cmd, NFT_OBJECT_SECMARK);
+		return 0;
 	case CMD_OBJ_CT_EXPECT:
+		obj_del_cache(ctx, cmd, NFT_OBJECT_CT_EXPECT);
+		return 0;
 	case CMD_OBJ_SYNPROXY:
+		obj_del_cache(ctx, cmd, NFT_OBJECT_SYNPROXY);
 		return 0;
 	default:
 		BUG("invalid command object type %u\n", cmd->obj);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2021-04-29 23:43 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 01/18] tests: shell: remove missing modules Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 02/18] src: unbreak deletion by table handle Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 03/18] rule: skip fuzzy lookup for unexisting 64-bit handle Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 04/18] src: pass chain name to chain_cache_find() Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 05/18] src: consolidate nft_cache infrastructure Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 06/18] src: consolidate object cache infrastructure Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 07/18] cache: add hashtable cache for object Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 08/18] cache: add hashtable cache for flowtable Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 09/18] cache: add set_cache_del() and use it Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 10/18] evaluate: add set to the cache Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 11/18] evaluate: add flowtable " Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 12/18] cache: missing table cache for several policy objects Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 13/18] evaluate: add object to the cache Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 14/18] cache: add hashtable cache for table Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 15/18] evaluate: remove chain from cache on delete chain command Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 16/18] evaluate: remove set from cache on delete set command Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 17/18] evaluate: remove flowtable from cache on delete flowtable command Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 18/18] evaluate: remove object from cache on delete object command Pablo Neira Ayuso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.