summaryrefslogtreecommitdiffstats
path: root/src/cache.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2021-04-29 22:09:15 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2021-05-02 23:30:35 +0200
commit45a84088ecbdd7403de849e169fe2f57f34a8bf1 (patch)
treee36851f77d717209b9befc6d584f77c91d0ebc69 /src/cache.c
parenteac934393c18c094da3dba2131340f3a82459d97 (diff)
cache: add hashtable cache for object
This patch adds a hashtable for object lookups. This patch also splits table->objs in two: - Sets that reside in the cache are stored in the new tables->cache_obj and tables->cache_obj_ht. - Set that defined via command line / ruleset file reside in tables->obj. Sets in the cache (already in the kernel) are not placed in the table->objs list. By keeping separated lists, objs defined via command line / ruleset file can be added to cache. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/cache.c')
-rw-r--r--src/cache.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/src/cache.c b/src/cache.c
index 70e47064..b2f796ec 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -333,6 +333,92 @@ struct set *set_cache_find(const struct table *table, const char *name)
return NULL;
}
+struct obj_cache_dump_ctx {
+ struct netlink_ctx *nlctx;
+ struct table *table;
+};
+
+static int obj_cache_cb(struct nftnl_obj *nlo, void *arg)
+{
+ struct obj_cache_dump_ctx *ctx = arg;
+ const char *obj_name;
+ struct obj *obj;
+ uint32_t hash;
+
+ obj = netlink_delinearize_obj(ctx->nlctx, nlo);
+ if (!obj)
+ return -1;
+
+ obj_name = nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME);
+ hash = djb_hash(obj_name) % NFT_CACHE_HSIZE;
+ cache_add(&obj->cache, &ctx->table->obj_cache, hash);
+
+ return 0;
+}
+
+static int obj_cache_init(struct netlink_ctx *ctx, struct table *table,
+ struct nftnl_obj_list *obj_list)
+{
+ struct obj_cache_dump_ctx dump_ctx = {
+ .nlctx = ctx,
+ .table = table,
+ };
+ nftnl_obj_list_foreach(obj_list, obj_cache_cb, &dump_ctx);
+
+ return 0;
+}
+
+static struct nftnl_obj_list *obj_cache_dump(struct netlink_ctx *ctx,
+ const struct table *table,
+ int *err)
+{
+ struct nftnl_obj_list *obj_list;
+
+ obj_list = mnl_nft_obj_dump(ctx, table->handle.family,
+ table->handle.table.name, NULL,
+ 0, true, false);
+ if (!obj_list) {
+ if (errno == EINTR) {
+ *err = -1;
+ return NULL;
+ }
+ *err = 0;
+ return NULL;
+ }
+
+ return obj_list;
+}
+
+void obj_cache_add(struct obj *obj, struct table *table)
+{
+ uint32_t hash;
+
+ hash = djb_hash(obj->handle.obj.name) % NFT_CACHE_HSIZE;
+ cache_add(&obj->cache, &table->obj_cache, hash);
+}
+
+void obj_cache_del(struct obj *obj)
+{
+ cache_del(&obj->cache);
+}
+
+struct obj *obj_cache_find(const struct table *table, const char *name,
+ uint32_t obj_type)
+{
+ struct obj *obj;
+ uint32_t hash;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(obj, &table->obj_cache.ht[hash], cache.hlist) {
+ if (!strcmp(obj->handle.obj.name, name) &&
+ obj->type == obj_type)
+ return obj;
+ }
+
+ return NULL;
+}
+
+
static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
struct nft_cache *cache)
{
@@ -351,6 +437,7 @@ 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 nftnl_obj_list *obj_list;
struct rule *rule, *nrule;
struct table *table;
struct chain *chain;
@@ -405,12 +492,19 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
list_splice_tail_init(&ctx->list, &table->flowtables);
}
if (flags & NFT_CACHE_OBJECT_BIT) {
- ret = netlink_list_objs(ctx, &table->handle);
+ obj_list = obj_cache_dump(ctx, table, &ret);
+ 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) {
ret = -1;
goto cache_fails;
}
- list_splice_tail_init(&ctx->list, &table->objs);
}
if (flags & NFT_CACHE_RULE_BIT) {