]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
cache: filter out rules by chain
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 10 Nov 2021 17:08:41 +0000 (18:08 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 11 Nov 2021 09:55:29 +0000 (10:55 +0100)
With an autogenerated ruleset with ~20k chains.

 # time nft list ruleset &> /dev/null

 real    0m1,712s
 user    0m1,258s
 sys     0m0,454s

Speed up listing of a specific chain:

 # time nft list chain nat MWDG-UGR-234PNG3YBUOTS5QD &> /dev/null

 real    0m0,542s
 user    0m0,251s
 sys     0m0,292s

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/cache.h
include/netlink.h
src/cache.c
src/netlink.c

index 120a1b8d91b5bc08a4540746861f5cf93183d29c..e5c509e8510cafed5e0da030219bb0a738b54fda 100644 (file)
@@ -51,6 +51,7 @@ struct nft_cache_filter {
        struct {
                uint32_t        family;
                const char      *table;
+               const char      *chain;
                const char      *set;
        } list;
 
index c1d7d3189455fe3fe4b24406088aa5b9fd833d91..a692edcdb5bf24b54fd420d5dedc28ae5aef0692 100644 (file)
@@ -124,8 +124,6 @@ extern struct expr *netlink_alloc_data(const struct location *loc,
                                       const struct nft_data_delinearize *nld,
                                       enum nft_registers dreg);
 
-extern int netlink_list_rules(struct netlink_ctx *ctx, const struct handle *h);
-
 struct netlink_linearize_ctx;
 extern void netlink_linearize_rule(struct netlink_ctx *ctx,
                                   const struct rule *rule,
index e82e0b8d12158bc1e5a41fca425803ce61a57bd1..fe31e3f02163c5b16fe0da1098fe8946e576e358 100644 (file)
@@ -200,6 +200,14 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
                }
                flags |= NFT_CACHE_FULL;
                break;
+       case CMD_OBJ_CHAIN:
+               if (filter && cmd->handle.chain.name) {
+                       filter->list.family = cmd->handle.family;
+                       filter->list.table = cmd->handle.table.name;
+                       filter->list.chain = cmd->handle.chain.name;
+               }
+               flags |= NFT_CACHE_FULL;
+               break;
        case CMD_OBJ_SET:
        case CMD_OBJ_MAP:
                if (filter && cmd->handle.table.name && cmd->handle.set.name) {
@@ -334,11 +342,13 @@ struct table *table_cache_find(const struct cache *cache,
 struct chain_cache_dump_ctx {
        struct netlink_ctx      *nlctx;
        struct table            *table;
+       const struct nft_cache_filter *filter;
 };
 
 static int chain_cache_cb(struct nftnl_chain *nlc, void *arg)
 {
        struct chain_cache_dump_ctx *ctx = arg;
+       const struct nft_cache_filter *filter = ctx->filter;
        const char *chain_name, *table_name;
        uint32_t hash, family;
        struct chain *chain;
@@ -351,6 +361,12 @@ static int chain_cache_cb(struct nftnl_chain *nlc, void *arg)
            family != ctx->table->handle.family)
                return 0;
 
+       if (filter && filter->list.table && filter->list.chain &&
+           (filter->list.family != family ||
+            strcmp(filter->list.table, table_name) ||
+            strcmp(filter->list.chain, chain_name)))
+               return 0;
+
        hash = djb_hash(chain_name) % NFT_CACHE_HSIZE;
        chain = netlink_delinearize_chain(ctx->nlctx, nlc);
 
@@ -367,11 +383,13 @@ static int chain_cache_cb(struct nftnl_chain *nlc, void *arg)
 }
 
 static int chain_cache_init(struct netlink_ctx *ctx, struct table *table,
-                           struct nftnl_chain_list *chain_list)
+                           struct nftnl_chain_list *chain_list,
+                           const struct nft_cache_filter *filter)
 {
        struct chain_cache_dump_ctx dump_ctx = {
                .nlctx  = ctx,
                .table  = table,
+               .filter = filter,
        };
        nftnl_chain_list_foreach(chain_list, chain_cache_cb, &dump_ctx);
 
@@ -423,6 +441,66 @@ struct chain *chain_cache_find(const struct table *table, const char *name)
        return NULL;
 }
 
+struct rule_cache_dump_ctx {
+       struct netlink_ctx      *nlctx;
+       const struct nft_cache_filter *filter;
+};
+
+static int list_rule_cb(struct nftnl_rule *nlr, void *data)
+{
+       struct rule_cache_dump_ctx *rule_ctx = data;
+       const struct nft_cache_filter *filter = rule_ctx->filter;
+       struct netlink_ctx *ctx = rule_ctx->nlctx;
+       const struct handle *h = ctx->data;
+       const char *table, *chain;
+       struct rule *rule;
+       uint32_t family;
+
+       family = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
+       table  = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE);
+       chain  = nftnl_rule_get_str(nlr, NFTNL_RULE_CHAIN);
+
+       if (h->family != family ||
+           strcmp(table, h->table.name) != 0 ||
+           (h->chain.name && strcmp(chain, h->chain.name) != 0))
+               return 0;
+
+       if (filter && filter->list.table && filter->list.chain &&
+           (filter->list.family != family ||
+            strcmp(filter->list.table, table) ||
+            strcmp(filter->list.chain, chain)))
+               return 0;
+
+       netlink_dump_rule(nlr, ctx);
+       rule = netlink_delinearize_rule(ctx, nlr);
+       list_add_tail(&rule->list, &ctx->list);
+
+       return 0;
+}
+
+static int rule_cache_init(struct netlink_ctx *ctx, const struct handle *h,
+                          const struct nft_cache_filter *filter)
+{
+       struct rule_cache_dump_ctx rule_ctx = {
+               .nlctx = ctx,
+               .filter = filter,
+       };
+       struct nftnl_rule_list *rule_cache;
+
+       rule_cache = mnl_nft_rule_dump(ctx, h->family);
+       if (rule_cache == NULL) {
+               if (errno == EINTR)
+                       return -1;
+
+               return 0;
+       }
+
+       ctx->data = h;
+       nftnl_rule_list_foreach(rule_cache, list_rule_cb, &rule_ctx);
+       nftnl_rule_list_free(rule_cache);
+       return 0;
+}
+
 struct set_cache_dump_ctx {
        struct netlink_ctx      *nlctx;
        struct table            *table;
@@ -777,7 +855,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
                        }
                }
                if (flags & NFT_CACHE_CHAIN_BIT) {
-                       ret = chain_cache_init(ctx, table, chain_list);
+                       ret = chain_cache_init(ctx, table, chain_list, filter);
                        if (ret < 0) {
                                ret = -1;
                                goto cache_fails;
@@ -815,7 +893,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);
+                       ret = rule_cache_init(ctx, &table->handle, filter);
                        list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
                                chain = chain_cache_find(table, rule->handle.chain.name);
                                if (!chain)
index f63f2bd1bd60713bd57ec44d5d13b38862f3af8c..ab90d0c05acaf80e9ae2cb8822794930a4ea3a3b 100644 (file)
@@ -483,48 +483,6 @@ void netlink_dump_expr(const struct nftnl_expr *nle,
        fprintf(fp, "\n");
 }
 
-static int list_rule_cb(struct nftnl_rule *nlr, void *arg)
-{
-       struct netlink_ctx *ctx = arg;
-       const struct handle *h = ctx->data;
-       struct rule *rule;
-       const char *table, *chain;
-       uint32_t family;
-
-       family = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
-       table  = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE);
-       chain  = nftnl_rule_get_str(nlr, NFTNL_RULE_CHAIN);
-
-       if (h->family != family ||
-           strcmp(table, h->table.name) != 0 ||
-           (h->chain.name && strcmp(chain, h->chain.name) != 0))
-               return 0;
-
-       netlink_dump_rule(nlr, ctx);
-       rule = netlink_delinearize_rule(ctx, nlr);
-       list_add_tail(&rule->list, &ctx->list);
-
-       return 0;
-}
-
-int netlink_list_rules(struct netlink_ctx *ctx, const struct handle *h)
-{
-       struct nftnl_rule_list *rule_cache;
-
-       rule_cache = mnl_nft_rule_dump(ctx, h->family);
-       if (rule_cache == NULL) {
-               if (errno == EINTR)
-                       return -1;
-
-               return 0;
-       }
-
-       ctx->data = h;
-       nftnl_rule_list_foreach(rule_cache, list_rule_cb, ctx);
-       nftnl_rule_list_free(rule_cache);
-       return 0;
-}
-
 void netlink_dump_chain(const struct nftnl_chain *nlc, struct netlink_ctx *ctx)
 {
        FILE *fp = ctx->nft->output.output_fp;