Fetch either all table's sets at once, a specific table's sets or even a specific set if needed instead of iterating over the list of previously fetched tables and fetching for each, then ignoring anything returned that doesn't match the filter. Signed-off-by: Phil Sutter <phil@xxxxxx> --- include/mnl.h | 2 +- src/cache.c | 63 ++++++++++++++++++++++++++++++--------------------- src/mnl.c | 15 ++++++++---- 3 files changed, 49 insertions(+), 31 deletions(-) diff --git a/include/mnl.h b/include/mnl.h index 9d54aac876dc1..8659879c17f44 100644 --- a/include/mnl.h +++ b/include/mnl.h @@ -58,7 +58,7 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, struct cmd *cmd, int mnl_nft_set_del(struct netlink_ctx *ctx, struct cmd *cmd); struct nftnl_set_list *mnl_nft_set_dump(struct netlink_ctx *ctx, int family, - const char *table); + const char *table, const char *set); int mnl_nft_setelem_add(struct netlink_ctx *ctx, const struct set *set, const struct expr *expr, unsigned int flags); diff --git a/src/cache.c b/src/cache.c index 3ecea38b550d4..b0f13e7ebb16a 100644 --- a/src/cache.c +++ b/src/cache.c @@ -487,57 +487,66 @@ static int rule_cache_init(struct netlink_ctx *ctx, const struct handle *h, struct set_cache_dump_ctx { struct netlink_ctx *nlctx; struct table *table; - const struct nft_cache_filter *filter; }; static int set_cache_cb(struct nftnl_set *nls, void *arg) { struct set_cache_dump_ctx *ctx = arg; + const char *set_table; const char *set_name; + uint32_t set_family; struct set *set; uint32_t hash; + set_table = nftnl_set_get_str(nls, NFTNL_SET_TABLE); + set_family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY); + + if (set_family != ctx->table->handle.family || + strcmp(set_table, ctx->table->handle.table.name)) + return 0; + set = netlink_delinearize_set(ctx->nlctx, nls); if (!set) return -1; - if (ctx->filter && ctx->filter->list.set && - (ctx->filter->list.family != set->handle.family || - strcmp(ctx->filter->list.table, set->handle.table.name) || - strcmp(ctx->filter->list.set, set->handle.set.name))) { - set_free(set); - return 0; - } - set_name = nftnl_set_get_str(nls, NFTNL_SET_NAME); hash = djb_hash(set_name) % NFT_CACHE_HSIZE; cache_add(&set->cache, &ctx->table->set_cache, hash); + nftnl_set_list_del(nls); + nftnl_set_free(nls); return 0; } static int set_cache_init(struct netlink_ctx *ctx, struct table *table, - struct nftnl_set_list *set_list, - const struct nft_cache_filter *filter) + struct nftnl_set_list *set_list) { struct set_cache_dump_ctx dump_ctx = { .nlctx = ctx, .table = table, - .filter = filter, }; + nftnl_set_list_foreach(set_list, set_cache_cb, &dump_ctx); return 0; } -static struct nftnl_set_list *set_cache_dump(struct netlink_ctx *ctx, - const struct table *table, - int *err) +static struct nftnl_set_list * +set_cache_dump(struct netlink_ctx *ctx, + const struct nft_cache_filter *filter, int *err) { struct nftnl_set_list *set_list; + int family = NFPROTO_UNSPEC; + const char *table = NULL; + const char *set = NULL; - set_list = mnl_nft_set_dump(ctx, table->handle.family, - table->handle.table.name); + if (filter) { + family = filter->list.family; + table = filter->list.table; + set = filter->list.set; + } + + set_list = mnl_nft_set_dump(ctx, family, table, set); if (!set_list) { if (errno == EINTR) { *err = -1; @@ -785,18 +794,17 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags, if (!chain_list) return -1; } + if (flags & NFT_CACHE_SET_BIT) { + set_list = set_cache_dump(ctx, filter, &ret); + if (!set_list) { + ret = -1; + goto cache_fails; + } + } list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) { if (flags & NFT_CACHE_SET_BIT) { - set_list = set_cache_dump(ctx, table, &ret); - if (!set_list) { - ret = -1; - goto cache_fails; - } - ret = set_cache_init(ctx, table, set_list, filter); - - nftnl_set_list_free(set_list); - + ret = set_cache_init(ctx, table, set_list); if (ret < 0) { ret = -1; goto cache_fails; @@ -893,6 +901,9 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags, } cache_fails: + if (set_list) + nftnl_set_list_free(set_list); + if (flags & NFT_CACHE_CHAIN_BIT) nftnl_chain_list_free(chain_list); diff --git a/src/mnl.c b/src/mnl.c index 03484c03d9ff8..9a98eed1ed9db 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -1300,10 +1300,12 @@ err_free: } struct nftnl_set_list * -mnl_nft_set_dump(struct netlink_ctx *ctx, int family, const char *table) +mnl_nft_set_dump(struct netlink_ctx *ctx, int family, + const char *table, const char *set) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct nftnl_set_list *nls_list; + int flags = NLM_F_DUMP; struct nlmsghdr *nlh; struct nftnl_set *s; int ret; @@ -1312,10 +1314,15 @@ mnl_nft_set_dump(struct netlink_ctx *ctx, int family, const char *table) if (s == NULL) memory_allocation_error(); - nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family, - NLM_F_DUMP, ctx->seqnum); if (table != NULL) nftnl_set_set_str(s, NFTNL_SET_TABLE, table); + if (set) { + nftnl_set_set_str(s, NFTNL_SET_NAME, set); + flags = NLM_F_ACK; + } + + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family, + flags, ctx->seqnum); nftnl_set_nlmsg_build_payload(nlh, s); nftnl_set_free(s); @@ -1324,7 +1331,7 @@ mnl_nft_set_dump(struct netlink_ctx *ctx, int family, const char *table) memory_allocation_error(); ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, set_cb, nls_list); - if (ret < 0) + if (ret < 0 && !set) goto err; return nls_list; -- 2.33.0