]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
cache: Filter rule list on kernel side
authorPhil Sutter <phil@nwl.cc>
Mon, 29 Nov 2021 14:36:45 +0000 (15:36 +0100)
committerPhil Sutter <phil@nwl.cc>
Fri, 3 Dec 2021 11:50:18 +0000 (12:50 +0100)
Instead of fetching all existing rules in kernel's ruleset and filtering
in user space, add payload to the dump request specifying the table and
chain to filter for.

Since list_rule_cb() no longer needs the filter, pass only netlink_ctx
to the callback and drop struct rule_cache_dump_ctx.

Signed-off-by: Phil Sutter <phil@nwl.cc>
include/mnl.h
src/cache.c
src/mnl.c

index 344030f30694024cf5a713c6bbd6f53ac9657b00..19faa651fdb911169f29f432a653923641d2853f 100644 (file)
@@ -33,8 +33,8 @@ int mnl_nft_rule_add(struct netlink_ctx *ctx, struct cmd *cmd,
 int mnl_nft_rule_del(struct netlink_ctx *ctx, struct cmd *cmd);
 int mnl_nft_rule_replace(struct netlink_ctx *ctx, struct cmd *cmd);
 
-struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx,
-                                         int family);
+struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
+                                         const struct nft_cache_filter *filter);
 
 int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
                      unsigned int flags);
index 66da2b347573256391769cae060c8b70ec176b82..484efdb93862b67c57b89565d2abd5a49f1941f3 100644 (file)
@@ -441,16 +441,9 @@ 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;
+       struct netlink_ctx *ctx = data;
        const struct handle *h = ctx->data;
        const char *table, *chain;
        struct rule *rule;
@@ -465,12 +458,6 @@ static int list_rule_cb(struct nftnl_rule *nlr, void *data)
            (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);
@@ -481,13 +468,9 @@ static int list_rule_cb(struct nftnl_rule *nlr, void *data)
 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);
+       rule_cache = mnl_nft_rule_dump(ctx, h->family, filter);
        if (rule_cache == NULL) {
                if (errno == EINTR)
                        return -1;
@@ -496,7 +479,7 @@ static int rule_cache_init(struct netlink_ctx *ctx, const struct handle *h,
        }
 
        ctx->data = h;
-       nftnl_rule_list_foreach(rule_cache, list_rule_cb, &rule_ctx);
+       nftnl_rule_list_foreach(rule_cache, list_rule_cb, ctx);
        nftnl_rule_list_free(rule_cache);
        return 0;
 }
index 21b98e34ed1762d8c5504c292714e87256713886..26f643fb282ea497f2d40e4f3d2cb3ec47433117 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -653,20 +653,37 @@ err_free:
        return MNL_CB_OK;
 }
 
-struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx,
-                                         int family)
+struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
+                                         const struct nft_cache_filter *filter)
 {
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct nftnl_rule_list *nlr_list;
+       struct nftnl_rule *nlr = NULL;
        struct nlmsghdr *nlh;
        int ret;
 
+       if (filter && filter->list.table) {
+               nlr = nftnl_rule_alloc();
+               if (!nlr)
+                       memory_allocation_error();
+
+               nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE,
+                                  filter->list.table);
+               if (filter->list.chain)
+                       nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN,
+                                          filter->list.chain);
+       }
+
        nlr_list = nftnl_rule_list_alloc();
        if (nlr_list == NULL)
                memory_allocation_error();
 
        nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family,
                                    NLM_F_DUMP, ctx->seqnum);
+       if (nlr) {
+               nftnl_rule_nlmsg_build_payload(nlh, nlr);
+               nftnl_rule_free(nlr);
+       }
 
        ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, rule_cb, nlr_list);
        if (ret < 0)