]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
cache: filter out tables that are not requested
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 29 Sep 2021 11:09:03 +0000 (13:09 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 29 Sep 2021 22:26:16 +0000 (00:26 +0200)
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
src/cache.c
src/cmd.c
src/libnftables.c

index 70aaf735f7d9b0910a633f42e1324dbd193ef804..3130b2c043722e19c0f4be668b4da708a4ba6eab 100644 (file)
@@ -38,12 +38,18 @@ enum cache_level_flags {
        NFT_CACHE_FLUSHED       = (1 << 31),
 };
 
+struct nft_cache_filter {
+       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);
 
index a0898a976e8888d607ce93cf54c74abae10fa8d9..6684111fc0f1fc5f375e58c797bd3890d5ef7e65 100644 (file)
@@ -127,9 +127,16 @@ 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;
+
+               flags |= NFT_CACHE_FULL | NFT_CACHE_REFRESH;
+               break;
        case CMD_OBJ_CHAINS:
                flags |= NFT_CACHE_TABLE | NFT_CACHE_CHAIN;
                break;
@@ -148,12 +155,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->table && cmd->op != CMD_LIST)
+                       memset(filter, 0, sizeof(*filter));
+
                switch (cmd->op) {
                case CMD_ADD:
                case CMD_INSERT:
@@ -181,7 +192,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 +593,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 +605,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->table &&
+                   (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 +740,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 +752,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 +783,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 +813,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);
index d956919b6b5e55f7f1421f40ce3f407b791b3fec..f6a8aa11476830c9467e961bc41495167a5560b8 100644 (file)
--- 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);
index fc52fbc35d21abddc5642b0d91e3b6e559b4031c..2b2ed1a44329ac9bb2768c7d7ebd597722db2763 100644 (file)
@@ -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) {