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@xxxxxx> --- Changes since v1: - Catch ENOENT instead of ignoring all errors for non-dump requests. - Use NFPROTO_UNSPEC instead of AF_UNSPEC for default family value. No functional change, merely conformity. --- include/mnl.h | 3 ++- src/cache.c | 38 +++++++++++++++++++------------------- src/mnl.c | 21 ++++++++++++++++++--- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/include/mnl.h b/include/mnl.h index 19faa651fdb91..9d54aac876dc1 100644 --- a/include/mnl.h +++ b/include/mnl.h @@ -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); diff --git a/src/cache.c b/src/cache.c index 484efdb93862b..1e98e6cf7cc17 100644 --- a/src/cache.c +++ b/src/cache.c @@ -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; diff --git a/src/mnl.c b/src/mnl.c index 26f643fb282ea..109c3dd81e578 100644 --- 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; -- 2.33.0