]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
cache: Filter chain list on kernel side
authorPhil Sutter <phil@nwl.cc>
Mon, 29 Nov 2021 15:26:44 +0000 (16:26 +0100)
committerPhil Sutter <phil@nwl.cc>
Fri, 3 Dec 2021 11:50:18 +0000 (12:50 +0100)
When operating on a specific chain, add payload to NFT_MSG_GETCHAIN so
kernel returns only relevant data. Since ENOENT is an expected return
code, do not treat this as error.

While being at it, improve code in chain_cache_cb() a bit:
- Check chain's family first, it is a less expensive check than
  comparing table names.
- Do not extract chain name of uninteresting chains.

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

index 19faa651fdb911169f29f432a653923641d2853f..9d54aac876dc1524b4d264d6f69d134f116df38e 100644 (file)
@@ -43,7 +43,8 @@ int mnl_nft_chain_rename(struct netlink_ctx *ctx, const struct cmd *cmd,
                         const struct chain *chain);
 
 struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
-                                           int family);
+                                           int family, const char *table,
+                                           const char *chain);
 
 int mnl_nft_table_add(struct netlink_ctx *ctx, struct cmd *cmd,
                      unsigned int flags);
index 484efdb93862b67c57b89565d2abd5a49f1941f3..1e98e6cf7cc178e9ebb2d8eec992d8b8c4bf2e49 100644 (file)
@@ -342,31 +342,23 @@ 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;
 
        table_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE);
-       chain_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME);
        family = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY);
 
-       if (strcmp(table_name, ctx->table->handle.table.name) ||
-           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)))
+       if (family != ctx->table->handle.family ||
+           strcmp(table_name, ctx->table->handle.table.name))
                return 0;
 
+       chain_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME);
        hash = djb_hash(chain_name) % NFT_CACHE_HSIZE;
        chain = netlink_delinearize_chain(ctx->nlctx, nlc);
 
@@ -383,25 +375,33 @@ 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,
-                           const struct nft_cache_filter *filter)
+                           struct nftnl_chain_list *chain_list)
 {
        struct chain_cache_dump_ctx dump_ctx = {
                .nlctx  = ctx,
                .table  = table,
-               .filter = filter,
        };
        nftnl_chain_list_foreach(chain_list, chain_cache_cb, &dump_ctx);
 
        return 0;
 }
 
-static struct nftnl_chain_list *chain_cache_dump(struct netlink_ctx *ctx,
-                                                int *err)
+static struct nftnl_chain_list *
+chain_cache_dump(struct netlink_ctx *ctx,
+                const struct nft_cache_filter *filter, int *err)
 {
        struct nftnl_chain_list *chain_list;
+       const char *table = NULL;
+       const char *chain = NULL;
+       int family = NFPROTO_UNSPEC;
+
+       if (filter && filter->list.table && filter->list.chain) {
+               family = filter->list.family;
+               table = filter->list.table;
+               chain = filter->list.chain;
+       }
 
-       chain_list = mnl_nft_chain_dump(ctx, AF_UNSPEC);
+       chain_list = mnl_nft_chain_dump(ctx, family, table, chain);
        if (chain_list == NULL) {
                if (errno == EINTR) {
                        *err = -1;
@@ -781,7 +781,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
        int ret = 0;
 
        if (flags & NFT_CACHE_CHAIN_BIT) {
-               chain_list = chain_cache_dump(ctx, &ret);
+               chain_list = chain_cache_dump(ctx, filter, &ret);
                if (!chain_list)
                        return -1;
        }
@@ -834,7 +834,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, filter);
+                       ret = chain_cache_init(ctx, table, chain_list);
                        if (ret < 0) {
                                ret = -1;
                                goto cache_fails;
index 26f643fb282ea497f2d40e4f3d2cb3ec47433117..109c3dd81e5785408857045df173ea6268d8eaab 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -906,10 +906,12 @@ err_free:
 }
 
 struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
-                                           int family)
+                                           int family, const char *table,
+                                           const char *chain)
 {
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct nftnl_chain_list *nlc_list;
+       struct nftnl_chain *nlc = NULL;
        struct nlmsghdr *nlh;
        int ret;
 
@@ -917,11 +919,24 @@ struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
        if (nlc_list == NULL)
                memory_allocation_error();
 
+       if (table && chain) {
+               nlc = nftnl_chain_alloc();
+               if (!nlc)
+                       memory_allocation_error();
+
+               nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, table);
+               nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME, chain);
+       }
+
        nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, family,
-                                   NLM_F_DUMP, ctx->seqnum);
+                                   nlc ? NLM_F_ACK : NLM_F_DUMP, ctx->seqnum);
+       if (nlc) {
+               nftnl_chain_nlmsg_build_payload(nlh, nlc);
+               nftnl_chain_free(nlc);
+       }
 
        ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, chain_cb, nlc_list);
-       if (ret < 0)
+       if (ret < 0 && errno != ENOENT)
                goto err;
 
        return nlc_list;