All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nft 1/2] cache: finer grain cache population for list commands
@ 2021-09-29 11:33 Pablo Neira Ayuso
  2021-09-29 11:33 ` [PATCH nft 2/2] cache: filter out tables that are not requested Pablo Neira Ayuso
  0 siblings, 1 reply; 2+ messages in thread
From: Pablo Neira Ayuso @ 2021-09-29 11:33 UTC (permalink / raw)
  To: netfilter-devel

Skip full cache population for list commands to speed up listing.

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

diff --git a/src/cache.c b/src/cache.c
index 544f64a20396..a0898a976e88 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -127,6 +127,27 @@ static unsigned int evaluate_cache_rename(struct cmd *cmd, unsigned int flags)
 	return flags;
 }
 
+static unsigned int evaluate_cache_list(struct cmd *cmd, unsigned int flags)
+{
+	switch (cmd->obj) {
+	case CMD_OBJ_CHAINS:
+		flags |= NFT_CACHE_TABLE | NFT_CACHE_CHAIN;
+		break;
+	case CMD_OBJ_SETS:
+	case CMD_OBJ_MAPS:
+		flags |= NFT_CACHE_TABLE | NFT_CACHE_SET;
+		break;
+	case CMD_OBJ_FLOWTABLES:
+		flags |= NFT_CACHE_TABLE | NFT_CACHE_FLOWTABLE;
+		break;
+	default:
+		flags |= NFT_CACHE_FULL | NFT_CACHE_REFRESH;
+		break;
+	}
+
+	return flags;
+}
+
 unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
 {
 	unsigned int flags = NFT_CACHE_EMPTY;
@@ -160,8 +181,7 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
 			flags |= NFT_CACHE_TABLE;
 			break;
 		case CMD_LIST:
-		case CMD_EXPORT:
-			flags |= NFT_CACHE_FULL | NFT_CACHE_REFRESH;
+			flags |= evaluate_cache_list(cmd, flags);
 			break;
 		case CMD_MONITOR:
 			flags |= NFT_CACHE_FULL;
@@ -174,6 +194,7 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
 			break;
 		case CMD_DESCRIBE:
 		case CMD_IMPORT:
+		case CMD_EXPORT:
 			break;
 		default:
 			break;
-- 
2.30.2


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

* [PATCH nft 2/2] cache: filter out tables that are not requested
  2021-09-29 11:33 [PATCH nft 1/2] cache: finer grain cache population for list commands Pablo Neira Ayuso
@ 2021-09-29 11:33 ` Pablo Neira Ayuso
  0 siblings, 0 replies; 2+ messages in thread
From: Pablo Neira Ayuso @ 2021-09-29 11:33 UTC (permalink / raw)
  To: netfilter-devel

Do not fetch table content for list commands that specify a
table name, e.g.

 # nft list table filter

This speeds up listing of a given table by not populating the
cache with tables that are not needed.

 - Full ruleset (huge with ~100k lines).

 # sudo nft list ruleset &> /dev/null
 real    0m3,049s
 user    0m2,080s
 sys     0m0,968s

- Listing per table is now faster:

 # nft list table nat &> /dev/null
 real    0m1,969s
 user    0m1,412s
 sys     0m0,556s

 # nft list table filter &> /dev/null
 real    0m0,697s
 user    0m0,478s
 sys     0m0,220s

Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1326
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/cache.h   | 11 +++++++++--
 src/cache.c       | 42 ++++++++++++++++++++++++++++++++----------
 src/cmd.c         |  2 +-
 src/libnftables.c |  5 +++--
 4 files changed, 45 insertions(+), 15 deletions(-)

diff --git a/include/cache.h b/include/cache.h
index 70aaf735f7d9..b238c1cfe326 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -38,12 +38,19 @@ enum cache_level_flags {
 	NFT_CACHE_FLUSHED	= (1 << 31),
 };
 
+struct nft_cache_filter {
+	bool			enabled;
+	const char		*table;
+};
+
 struct nft_cache;
 enum cmd_ops;
 
-unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds);
+unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
+				struct nft_cache_filter *filter);
 int nft_cache_update(struct nft_ctx *ctx, enum cmd_ops cmd,
-		     struct list_head *msgs);
+		     struct list_head *msgs,
+		     const struct nft_cache_filter *filter);
 bool nft_cache_needs_update(struct nft_cache *cache);
 void nft_cache_release(struct nft_cache *cache);
 
diff --git a/src/cache.c b/src/cache.c
index a0898a976e88..563860e82fb8 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -127,9 +127,17 @@ static unsigned int evaluate_cache_rename(struct cmd *cmd, unsigned int flags)
 	return flags;
 }
 
-static unsigned int evaluate_cache_list(struct cmd *cmd, unsigned int flags)
+static unsigned int evaluate_cache_list(struct cmd *cmd, unsigned int flags,
+					struct nft_cache_filter *filter)
 {
 	switch (cmd->obj) {
+	case CMD_OBJ_TABLE:
+		if (filter && cmd->handle.table.name) {
+			filter->table = cmd->handle.table.name;
+			filter->enabled = true;
+		}
+		flags |= NFT_CACHE_FULL | NFT_CACHE_REFRESH;
+		break;
 	case CMD_OBJ_CHAINS:
 		flags |= NFT_CACHE_TABLE | NFT_CACHE_CHAIN;
 		break;
@@ -148,12 +156,16 @@ static unsigned int evaluate_cache_list(struct cmd *cmd, unsigned int flags)
 	return flags;
 }
 
-unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
+unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
+				struct nft_cache_filter *filter)
 {
 	unsigned int flags = NFT_CACHE_EMPTY;
 	struct cmd *cmd;
 
 	list_for_each_entry(cmd, cmds, list) {
+		if (filter->enabled && cmd->op != CMD_LIST)
+			filter->enabled = false;
+
 		switch (cmd->op) {
 		case CMD_ADD:
 		case CMD_INSERT:
@@ -181,7 +193,7 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
 			flags |= NFT_CACHE_TABLE;
 			break;
 		case CMD_LIST:
-			flags |= evaluate_cache_list(cmd, flags);
+			flags |= evaluate_cache_list(cmd, flags, filter);
 			break;
 		case CMD_MONITOR:
 			flags |= NFT_CACHE_FULL;
@@ -582,7 +594,8 @@ 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 nft_cache *cache,
+			     const struct nft_cache_filter *filter)
 {
 	struct table *table, *next;
 	int ret;
@@ -593,13 +606,20 @@ static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
 
 	list_for_each_entry_safe(table, next, &ctx->list, list) {
 		list_del(&table->list);
+
+		if (filter && filter->enabled &&
+		    (strcmp(filter->table, table->handle.table.name))) {
+			table_free(table);
+			continue;
+		}
 		table_cache_add(table, cache);
 	}
 
 	return 0;
 }
 
-static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
+static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
+			      const struct nft_cache_filter *filter)
 {
 	struct nftnl_flowtable_list *ft_list = NULL;
 	struct nftnl_chain_list *chain_list = NULL;
@@ -721,7 +741,8 @@ cache_fails:
 	return ret;
 }
 
-static int nft_cache_init(struct netlink_ctx *ctx, unsigned int flags)
+static int nft_cache_init(struct netlink_ctx *ctx, unsigned int flags,
+			  const struct nft_cache_filter *filter)
 {
 	struct handle handle = {
 		.family = NFPROTO_UNSPEC,
@@ -732,10 +753,10 @@ static int nft_cache_init(struct netlink_ctx *ctx, unsigned int flags)
 		return 0;
 
 	/* assume NFT_CACHE_TABLE is always set. */
-	ret = cache_init_tables(ctx, &handle, &ctx->nft->cache);
+	ret = cache_init_tables(ctx, &handle, &ctx->nft->cache, filter);
 	if (ret < 0)
 		return ret;
-	ret = cache_init_objects(ctx, flags);
+	ret = cache_init_objects(ctx, flags, filter);
 	if (ret < 0)
 		return ret;
 
@@ -763,7 +784,8 @@ bool nft_cache_needs_update(struct nft_cache *cache)
 }
 
 int nft_cache_update(struct nft_ctx *nft, unsigned int flags,
-		     struct list_head *msgs)
+		     struct list_head *msgs,
+		     const struct nft_cache_filter *filter)
 {
 	struct netlink_ctx ctx = {
 		.list		= LIST_HEAD_INIT(ctx.list),
@@ -792,7 +814,7 @@ replay:
 		goto skip;
 	}
 
-	ret = nft_cache_init(&ctx, flags);
+	ret = nft_cache_init(&ctx, flags, filter);
 	if (ret < 0) {
 		if (errno == EINTR) {
 			nft_cache_release(cache);
diff --git a/src/cmd.c b/src/cmd.c
index d956919b6b5e..f6a8aa114768 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -81,7 +81,7 @@ static int nft_cmd_enoent_rule(struct netlink_ctx *ctx, const struct cmd *cmd,
 	const struct table *table = NULL;
 	struct chain *chain;
 
-	if (nft_cache_update(ctx->nft, flags, ctx->msgs) < 0)
+	if (nft_cache_update(ctx->nft, flags, ctx->msgs, NULL) < 0)
 		return 0;
 
 	chain = chain_lookup_fuzzy(&cmd->handle, &ctx->nft->cache, &table);
diff --git a/src/libnftables.c b/src/libnftables.c
index fc52fbc35d21..2b2ed1a44329 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -459,11 +459,12 @@ static int nft_parse_bison_filename(struct nft_ctx *nft, const char *filename,
 static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
 			struct list_head *cmds)
 {
+	struct nft_cache_filter filter = {};
 	unsigned int flags;
 	struct cmd *cmd;
 
-	flags = nft_cache_evaluate(nft, cmds);
-	if (nft_cache_update(nft, flags, msgs) < 0)
+	flags = nft_cache_evaluate(nft, cmds, &filter);
+	if (nft_cache_update(nft, flags, msgs, &filter) < 0)
 		return -1;
 
 	list_for_each_entry(cmd, cmds, list) {
-- 
2.30.2


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

end of thread, other threads:[~2021-09-29 11:33 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-29 11:33 [PATCH nft 1/2] cache: finer grain cache population for list commands Pablo Neira Ayuso
2021-09-29 11:33 ` [PATCH nft 2/2] cache: filter out tables that are not requested 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.