From df48e56e987f84bb32ea53dfe98569dfe3fb7e37 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 2 Apr 2021 20:26:15 +0200 Subject: cache: add hashtable cache for sets This patch adds a hashtable for set lookups. This patch also splits table->sets in two: - Sets that reside in the cache are stored in the new tables->cache_set and tables->cache_set_ht. - Set that defined via command line / ruleset file reside in tables->set. Sets in the cache (already in the kernel) are not placed in the table->sets list. By keeping separated lists, sets defined via command line / ruleset file can be added to cache. Adding 10000 sets, before: # time nft -f x real 0m6,415s user 0m3,126s sys 0m3,284s After: # time nft -f x real 0m3,949s user 0m0,743s sys 0m3,205s Signed-off-by: Pablo Neira Ayuso --- src/cache.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 3 deletions(-) (limited to 'src/cache.c') diff --git a/src/cache.c b/src/cache.c index 4e573676..80632c86 100644 --- a/src/cache.c +++ b/src/cache.c @@ -259,6 +259,85 @@ struct chain *chain_cache_find(const struct table *table, return NULL; } +struct set_cache_dump_ctx { + struct netlink_ctx *nlctx; + struct table *table; +}; + +static int set_cache_cb(struct nftnl_set *nls, void *arg) +{ + struct set_cache_dump_ctx *ctx = arg; + const char *set_name; + struct set *set; + uint32_t hash; + + set = netlink_delinearize_set(ctx->nlctx, nls); + if (!set) + return -1; + + set_name = nftnl_set_get_str(nls, NFTNL_SET_NAME); + hash = djb_hash(set_name) % NFT_CACHE_HSIZE; + list_add_tail(&set->cache_hlist, &ctx->table->cache_set_ht[hash]); + list_add_tail(&set->cache_list, &ctx->table->cache_set); + + return 0; +} + +static int set_cache_init(struct netlink_ctx *ctx, struct table *table, + struct nftnl_set_list *set_list) +{ + struct set_cache_dump_ctx dump_ctx = { + .nlctx = ctx, + .table = table, + }; + 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) +{ + struct nftnl_set_list *set_list; + + set_list = mnl_nft_set_dump(ctx, table->handle.family, + table->handle.table.name); + if (!set_list) { + if (errno == EINTR) { + *err = -1; + return NULL; + } + *err = 0; + return NULL; + } + + return set_list; +} + +void set_cache_add(struct set *set, struct table *table) +{ + uint32_t hash; + + hash = djb_hash(set->handle.set.name) % NFT_CACHE_HSIZE; + list_add_tail(&set->cache_hlist, &table->cache_set_ht[hash]); + list_add_tail(&set->cache_list, &table->cache_set); +} + +struct set *set_cache_find(const struct table *table, const char *name) +{ + struct set *set; + uint32_t hash; + + hash = djb_hash(name) % NFT_CACHE_HSIZE; + list_for_each_entry(set, &table->cache_set_ht[hash], cache_hlist) { + if (!strcmp(set->handle.set.name, name)) + return set; + } + + return NULL; +} + static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h, struct nft_cache *cache) { @@ -276,6 +355,7 @@ static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h, static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags) { struct nftnl_chain_list *chain_list = NULL; + struct nftnl_set_list *set_list = NULL; struct rule *rule, *nrule; struct table *table; struct chain *chain; @@ -290,15 +370,22 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags) list_for_each_entry(table, &ctx->nft->cache.list, list) { if (flags & NFT_CACHE_SET_BIT) { - ret = netlink_list_sets(ctx, &table->handle); - list_splice_tail_init(&ctx->list, &table->sets); + set_list = set_cache_dump(ctx, table, &ret); + if (!set_list) { + ret = -1; + goto cache_fails; + } + ret = set_cache_init(ctx, table, set_list); + + nftnl_set_list_free(set_list); + if (ret < 0) { ret = -1; goto cache_fails; } } if (flags & NFT_CACHE_SETELEM_BIT) { - list_for_each_entry(set, &table->sets, list) { + list_for_each_entry(set, &table->cache_set, cache_list) { ret = netlink_list_setelems(ctx, &set->handle, set); if (ret < 0) { -- cgit v1.2.3