From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Subject: [PATCH nft 07/18] cache: add hashtable cache for object
Date: Fri, 30 Apr 2021 01:42:44 +0200 [thread overview]
Message-ID: <20210429234255.16840-8-pablo@netfilter.org> (raw)
In-Reply-To: <20210429234255.16840-1-pablo@netfilter.org>
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>
---
include/cache.h | 5 +++
include/rule.h | 5 +--
src/cache.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++-
src/evaluate.c | 2 +-
src/json.c | 4 +-
src/monitor.c | 8 ++--
src/netlink.c | 19 ----------
src/rule.c | 38 +++++++------------
8 files changed, 124 insertions(+), 55 deletions(-)
diff --git a/include/cache.h b/include/cache.h
index 4d91a73624c8..9605ef96c853 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -87,4 +87,9 @@ void cache_free(struct cache *cache);
void cache_add(struct cache_item *item, struct cache *cache, uint32_t hash);
void cache_del(struct cache_item *item);
+void obj_cache_add(struct obj *obj, struct table *table);
+void obj_cache_del(struct obj *obj);
+struct obj *obj_cache_find(const struct table *table, const char *name,
+ uint32_t obj_type);
+
#endif /* _NFT_CACHE_H_ */
diff --git a/include/rule.h b/include/rule.h
index b238c85bcba9..f264bc8a1a01 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -157,6 +157,7 @@ struct table {
struct scope scope;
struct cache chain_cache;
struct cache set_cache;
+ struct cache obj_cache;
struct list_head chains;
struct list_head sets;
struct list_head objs;
@@ -484,6 +485,7 @@ struct secmark {
*/
struct obj {
struct list_head list;
+ struct cache_item cache;
struct location location;
struct handle handle;
uint32_t type;
@@ -504,9 +506,6 @@ struct obj {
struct obj *obj_alloc(const struct location *loc);
extern struct obj *obj_get(struct obj *obj);
void obj_free(struct obj *obj);
-void obj_add_hash(struct obj *obj, struct table *table);
-struct obj *obj_lookup(const struct table *table, const char *name,
- uint32_t type);
struct obj *obj_lookup_fuzzy(const char *obj_name,
const struct nft_cache *cache,
const struct table **t);
diff --git a/src/cache.c b/src/cache.c
index 70e47064848e..b2f796ec9975 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) {
diff --git a/src/evaluate.c b/src/evaluate.c
index a3f468aab104..91cedf4ca021 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4412,7 +4412,7 @@ static int cmd_evaluate_list_obj(struct eval_ctx *ctx, const struct cmd *cmd,
if (table == NULL)
return table_not_found(ctx);
- if (obj_lookup(table, cmd->handle.obj.name, obj_type) == NULL)
+ if (!obj_cache_find(table, cmd->handle.obj.name, obj_type))
return obj_not_found(ctx, &cmd->handle.obj.location,
cmd->handle.obj.name);
diff --git a/src/json.c b/src/json.c
index a375093eb785..0b7699a625b5 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1570,7 +1570,7 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx,
tmp = table_print_json(table);
json_array_append_new(root, tmp);
- list_for_each_entry(obj, &table->objs, list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
tmp = obj_print_json(obj);
json_array_append_new(root, tmp);
}
@@ -1740,7 +1740,7 @@ static json_t *do_list_obj_json(struct netlink_ctx *ctx,
strcmp(cmd->handle.table.name, table->handle.table.name))
continue;
- list_for_each_entry(obj, &table->objs, list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
if (obj->type != type ||
(cmd->handle.obj.name &&
strcmp(cmd->handle.obj.name, obj->handle.obj.name)))
diff --git a/src/monitor.c b/src/monitor.c
index dc3f0848ba66..ae288f6cb212 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -477,7 +477,7 @@ static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
nlo = netlink_obj_alloc(nlh);
obj = netlink_delinearize_obj(monh->ctx, nlo);
- if (obj == NULL) {
+ if (!obj) {
nftnl_obj_free(nlo);
return MNL_CB_ERROR;
}
@@ -727,7 +727,7 @@ static void netlink_events_cache_addobj(struct netlink_mon_handler *monh,
goto out;
}
- obj_add_hash(obj, t);
+ obj_cache_add(obj, t);
out:
nftnl_obj_free(nlo);
}
@@ -756,13 +756,13 @@ static void netlink_events_cache_delobj(struct netlink_mon_handler *monh,
goto out;
}
- obj = obj_lookup(t, name, type);
+ obj = obj_cache_find(t, name, type);
if (obj == NULL) {
fprintf(stderr, "W: Unable to find object in cache\n");
goto out;
}
- list_del(&obj->list);
+ obj_cache_del(obj);
obj_free(obj);
out:
nftnl_obj_free(nlo);
diff --git a/src/netlink.c b/src/netlink.c
index 123525570c39..6323fe4e810f 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1517,25 +1517,6 @@ static int list_obj_cb(struct nftnl_obj *nls, void *arg)
return 0;
}
-int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h)
-{
- struct nftnl_obj_list *obj_cache;
- int err;
-
- obj_cache = mnl_nft_obj_dump(ctx, h->family,
- h->table.name, NULL, 0, true, false);
- if (obj_cache == NULL) {
- if (errno == EINTR)
- return -1;
-
- return 0;
- }
-
- err = nftnl_obj_list_foreach(obj_cache, list_obj_cb, ctx);
- nftnl_obj_list_free(obj_cache);
- return err;
-}
-
int netlink_reset_objs(struct netlink_ctx *ctx, const struct cmd *cmd,
uint32_t type, bool dump)
{
diff --git a/src/rule.c b/src/rule.c
index 7dbb02f5b04f..56fb19c77e7d 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1114,6 +1114,7 @@ struct table *table_alloc(void)
cache_init(&table->chain_cache);
cache_init(&table->set_cache);
+ cache_init(&table->obj_cache);
return table;
}
@@ -1145,10 +1146,15 @@ void table_free(struct table *table)
flowtable_free(ft);
list_for_each_entry_safe(obj, nobj, &table->objs, list)
obj_free(obj);
+ /* this is implicitly releasing objs in the hashtable cache */
+ list_for_each_entry_safe(obj, nobj, &table->obj_cache.list, cache.list)
+ obj_free(obj);
+
handle_free(&table->handle);
scope_release(&table->scope);
cache_free(&table->chain_cache);
cache_free(&table->set_cache);
+ cache_free(&table->obj_cache);
xfree(table);
}
@@ -1254,7 +1260,7 @@ static void table_print(const struct table *table, struct output_ctx *octx)
if (table->comment)
nft_print(octx, "\tcomment \"%s\"\n", table->comment);
- list_for_each_entry(obj, &table->objs, list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
nft_print(octx, "%s", delim);
obj_print(obj, octx);
delim = "\n";
@@ -1727,24 +1733,6 @@ void obj_free(struct obj *obj)
xfree(obj);
}
-void obj_add_hash(struct obj *obj, struct table *table)
-{
- list_add_tail(&obj->list, &table->objs);
-}
-
-struct obj *obj_lookup(const struct table *table, const char *name,
- uint32_t type)
-{
- struct obj *obj;
-
- list_for_each_entry(obj, &table->objs, list) {
- if (!strcmp(obj->handle.obj.name, name) &&
- obj->type == type)
- return obj;
- }
- return NULL;
-}
-
struct obj *obj_lookup_fuzzy(const char *obj_name,
const struct nft_cache *cache,
const struct table **t)
@@ -1756,7 +1744,7 @@ struct obj *obj_lookup_fuzzy(const char *obj_name,
string_misspell_init(&st);
list_for_each_entry(table, &cache->list, list) {
- list_for_each_entry(obj, &table->objs, list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
if (!strcmp(obj->handle.obj.name, obj_name)) {
*t = table;
return obj;
@@ -2101,14 +2089,14 @@ static int do_list_obj(struct netlink_ctx *ctx, struct cmd *cmd, uint32_t type)
strcmp(cmd->handle.table.name, table->handle.table.name))
continue;
- if (list_empty(&table->objs))
+ if (list_empty(&table->obj_cache.list))
continue;
nft_print(&ctx->nft->output, "table %s %s {\n",
family2str(table->handle.family),
table->handle.table.name);
- list_for_each_entry(obj, &table->objs, list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
if (obj->type != type ||
(cmd->handle.obj.name != NULL &&
strcmp(cmd->handle.obj.name, obj->handle.obj.name)))
@@ -2564,8 +2552,10 @@ static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd)
ret = netlink_reset_objs(ctx, cmd, type, dump);
list_for_each_entry_safe(obj, next, &ctx->list, list) {
table = table_lookup(&obj->handle, &ctx->nft->cache);
- if (!obj_lookup(table, obj->handle.obj.name, obj->type))
- list_move(&obj->list, &table->objs);
+ if (!obj_cache_find(table, obj->handle.obj.name, obj->type)) {
+ list_del(&obj->list);
+ obj_cache_add(obj, table);
+ }
}
if (ret < 0)
return ret;
--
2.20.1
next prev parent reply other threads:[~2021-04-29 23:43 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-04-29 23:42 [PATCH nft 00/18] cache updates,v2 Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 01/18] tests: shell: remove missing modules Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 02/18] src: unbreak deletion by table handle Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 03/18] rule: skip fuzzy lookup for unexisting 64-bit handle Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 04/18] src: pass chain name to chain_cache_find() Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 05/18] src: consolidate nft_cache infrastructure Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 06/18] src: consolidate object cache infrastructure Pablo Neira Ayuso
2021-04-29 23:42 ` Pablo Neira Ayuso [this message]
2021-04-29 23:42 ` [PATCH nft 08/18] cache: add hashtable cache for flowtable Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 09/18] cache: add set_cache_del() and use it Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 10/18] evaluate: add set to the cache Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 11/18] evaluate: add flowtable " Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 12/18] cache: missing table cache for several policy objects Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 13/18] evaluate: add object to the cache Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 14/18] cache: add hashtable cache for table Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 15/18] evaluate: remove chain from cache on delete chain command Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 16/18] evaluate: remove set from cache on delete set command Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 17/18] evaluate: remove flowtable from cache on delete flowtable command Pablo Neira Ayuso
2021-04-29 23:42 ` [PATCH nft 18/18] evaluate: remove object from cache on delete object command Pablo Neira Ayuso
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210429234255.16840-8-pablo@netfilter.org \
--to=pablo@netfilter.org \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).