From 580a7c22f1b5419bf3231a7c863cd20784f03b8a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 17 Jul 2026 11:10:09 +0200 Subject: [PATCH] cache: add filtering support for objects JIRA: https://issues.redhat.com/browse/RHEL-190549 Upstream Status: nftables commit 969ce17b66f8084626610202f11d607911e049e6 commit 969ce17b66f8084626610202f11d607911e049e6 Author: Pablo Neira Ayuso Date: Mon Aug 26 00:41:37 2024 +0200 cache: add filtering support for objects Currently, full ruleset flag is set on to fetch objects. Follow a similar approach to these patches from Phil: de961b930660 ("cache: Filter set list on server side") and cb4b07d0b628 ("cache: Support filtering for a specific flowtable") in preparation to update the reset command to use the cache infrastructure. Tested-by: Eric Garver Signed-off-by: Pablo Neira Ayuso Signed-off-by: Phil Sutter --- include/cache.h | 2 + src/cache.c | 100 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 89 insertions(+), 13 deletions(-) diff --git a/include/cache.h b/include/cache.h index 8ca4a9a..e47dc88 100644 --- a/include/cache.h +++ b/include/cache.h @@ -55,8 +55,10 @@ struct nft_cache_filter { uint32_t family; const char *table; const char *chain; + const char *obj; const char *set; const char *ft; + int obj_type; uint64_t rule_handle; } list; diff --git a/src/cache.c b/src/cache.c index eb00480..2407fc2 100644 --- a/src/cache.c +++ b/src/cache.c @@ -197,6 +197,22 @@ static unsigned int evaluate_cache_rename(struct cmd *cmd, unsigned int flags) return flags; } +static void obj_filter_setup(const struct cmd *cmd, unsigned int *flags, + struct nft_cache_filter *filter, int type) +{ + assert(filter); + + if (cmd->handle.family) + filter->list.family = cmd->handle.family; + if (cmd->handle.table.name) + filter->list.table = cmd->handle.table.name; + if (cmd->handle.obj.name) + filter->list.obj = cmd->handle.obj.name; + + filter->list.obj_type = type; + *flags |= NFT_CACHE_TABLE | NFT_CACHE_OBJECT; +} + static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd, unsigned int flags, struct nft_cache_filter *filter) @@ -258,6 +274,37 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd, case CMD_OBJ_FLOWTABLES: flags |= NFT_CACHE_TABLE | NFT_CACHE_FLOWTABLE; break; + case CMD_OBJ_COUNTER: + case CMD_OBJ_COUNTERS: + obj_filter_setup(cmd, &flags, filter, NFT_OBJECT_COUNTER); + break; + case CMD_OBJ_QUOTA: + case CMD_OBJ_QUOTAS: + obj_filter_setup(cmd, &flags, filter, NFT_OBJECT_QUOTA); + break; + case CMD_OBJ_CT_HELPER: + case CMD_OBJ_CT_HELPERS: + obj_filter_setup(cmd, &flags, filter, NFT_OBJECT_CT_HELPER); + break; + case CMD_OBJ_LIMIT: + case CMD_OBJ_LIMITS: + obj_filter_setup(cmd, &flags, filter, NFT_OBJECT_LIMIT); + break; + case CMD_OBJ_CT_TIMEOUT: + case CMD_OBJ_CT_TIMEOUTS: + obj_filter_setup(cmd, &flags, filter, NFT_OBJECT_CT_TIMEOUT); + break; + case CMD_OBJ_SECMARK: + case CMD_OBJ_SECMARKS: + obj_filter_setup(cmd, &flags, filter, NFT_OBJECT_SECMARK); + break; + case CMD_OBJ_CT_EXPECT: + obj_filter_setup(cmd, &flags, filter, NFT_OBJECT_CT_EXPECT); + break; + case CMD_OBJ_SYNPROXY: + case CMD_OBJ_SYNPROXYS: + obj_filter_setup(cmd, &flags, filter, NFT_OBJECT_SYNPROXY); + break; case CMD_OBJ_RULESET: default: flags |= NFT_CACHE_FULL; @@ -793,10 +840,19 @@ struct obj_cache_dump_ctx { static int obj_cache_cb(struct nftnl_obj *nlo, void *arg) { struct obj_cache_dump_ctx *ctx = arg; + const char *obj_table; const char *obj_name; + uint32_t obj_family; struct obj *obj; uint32_t hash; + obj_table = nftnl_obj_get_str(nlo, NFTNL_OBJ_TABLE); + obj_family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY); + + if (obj_family != ctx->table->handle.family || + strcmp(obj_table, ctx->table->handle.table.name)) + return 0; + obj = netlink_delinearize_obj(ctx->nlctx, nlo); if (!obj) return -1; @@ -805,6 +861,9 @@ static int obj_cache_cb(struct nftnl_obj *nlo, void *arg) hash = djb_hash(obj_name) % NFT_CACHE_HSIZE; cache_add(&obj->cache, &ctx->table->obj_cache, hash); + nftnl_obj_list_del(nlo); + nftnl_obj_free(nlo); + return 0; } @@ -821,13 +880,27 @@ static int obj_cache_init(struct netlink_ctx *ctx, struct table *table, } static struct nftnl_obj_list *obj_cache_dump(struct netlink_ctx *ctx, - const struct table *table) + const struct nft_cache_filter *filter) { struct nftnl_obj_list *obj_list; + int type = NFT_OBJECT_UNSPEC; + int family = NFPROTO_UNSPEC; + const char *table = NULL; + const char *obj = NULL; + bool dump = true; - obj_list = mnl_nft_obj_dump(ctx, table->handle.family, - table->handle.table.name, NULL, - 0, true, false); + if (filter) { + family = filter->list.family; + if (filter->list.table) + table = filter->list.table; + if (filter->list.obj) { + obj = filter->list.obj; + dump = false; + } + if (filter->list.obj_type) + type = filter->list.obj_type; + } + obj_list = mnl_nft_obj_dump(ctx, family, table, obj, type, dump, false); if (!obj_list) { if (errno == EINTR) return NULL; @@ -1050,7 +1123,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags, struct nftnl_flowtable_list *ft_list = NULL; struct nftnl_chain_list *chain_list = NULL; struct nftnl_set_list *set_list = NULL; - struct nftnl_obj_list *obj_list; + struct nftnl_obj_list *obj_list = NULL; struct table *table; struct set *set; int ret = 0; @@ -1067,6 +1140,13 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags, goto cache_fails; } } + if (flags & NFT_CACHE_OBJECT_BIT) { + obj_list = obj_cache_dump(ctx, filter); + if (!obj_list) { + ret = -1; + goto cache_fails; + } + } if (flags & NFT_CACHE_FLOWTABLE_BIT) { ft_list = ft_cache_dump(ctx, filter); if (!ft_list) { @@ -1119,15 +1199,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags, goto cache_fails; } if (flags & NFT_CACHE_OBJECT_BIT) { - obj_list = obj_cache_dump(ctx, table); - if (!obj_list) { - ret = -1; - goto cache_fails; - } ret = obj_cache_init(ctx, table, obj_list); - - nftnl_obj_list_free(obj_list); - if (ret < 0) goto cache_fails; } @@ -1148,6 +1220,8 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags, cache_fails: if (set_list) nftnl_set_list_free(set_list); + if (obj_list) + nftnl_obj_list_free(obj_list); if (ft_list) nftnl_flowtable_list_free(ft_list);