summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2021-04-29 22:19:07 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2021-05-02 23:30:35 +0200
commit560963c4d41e153344850e8c98eaac4f131d05cb (patch)
tree4264e7aacfeba866e130e424eb70c85a386fd71a
parent45a84088ecbdd7403de849e169fe2f57f34a8bf1 (diff)
cache: add hashtable cache for flowtable
Add flowtable hashtable cache. Actually I am not expecting that many flowtables to benefit from the hashtable to be created by streamline this code with tables, chains, sets and policy objects. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/cache.h4
-rw-r--r--include/netlink.h2
-rw-r--r--include/rule.h4
-rw-r--r--src/cache.c88
-rw-r--r--src/evaluate.c6
-rw-r--r--src/json.c8
-rw-r--r--src/netlink.c2
-rw-r--r--src/rule.c31
8 files changed, 112 insertions, 33 deletions
diff --git a/include/cache.h b/include/cache.h
index 9605ef96..992f993c 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -92,4 +92,8 @@ void obj_cache_del(struct obj *obj);
struct obj *obj_cache_find(const struct table *table, const char *name,
uint32_t obj_type);
+struct flowtable;
+void ft_cache_add(struct flowtable *ft, struct table *table);
+struct flowtable *ft_cache_find(const struct table *table, const char *name);
+
#endif /* _NFT_CACHE_H_ */
diff --git a/include/netlink.h b/include/netlink.h
index f93c5322..a7c524ca 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -163,6 +163,8 @@ extern struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
extern int netlink_list_flowtables(struct netlink_ctx *ctx,
const struct handle *h);
+extern struct flowtable *netlink_delinearize_flowtable(struct netlink_ctx *ctx,
+ struct nftnl_flowtable *nlo);
extern void netlink_dump_chain(const struct nftnl_chain *nlc,
struct netlink_ctx *ctx);
diff --git a/include/rule.h b/include/rule.h
index f264bc8a..c6fd4c4c 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -158,6 +158,7 @@ struct table {
struct cache chain_cache;
struct cache set_cache;
struct cache obj_cache;
+ struct cache ft_cache;
struct list_head chains;
struct list_head sets;
struct list_head objs;
@@ -516,6 +517,7 @@ uint32_t obj_type_to_cmd(uint32_t type);
struct flowtable {
struct list_head list;
+ struct cache_item cache;
struct handle handle;
struct scope scope;
struct location location;
@@ -531,8 +533,6 @@ struct flowtable {
extern struct flowtable *flowtable_alloc(const struct location *loc);
extern struct flowtable *flowtable_get(struct flowtable *flowtable);
extern void flowtable_free(struct flowtable *flowtable);
-extern void flowtable_add_hash(struct flowtable *flowtable, struct table *table);
-extern struct flowtable *flowtable_lookup(const struct table *table, const char *name);
extern struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
const struct nft_cache *cache,
const struct table **table);
diff --git a/src/cache.c b/src/cache.c
index b2f796ec..1aec1266 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -418,6 +418,82 @@ struct obj *obj_cache_find(const struct table *table, const char *name,
return NULL;
}
+struct ft_cache_dump_ctx {
+ struct netlink_ctx *nlctx;
+ struct table *table;
+};
+
+static int ft_cache_cb(struct nftnl_flowtable *nlf, void *arg)
+{
+ struct ft_cache_dump_ctx *ctx = arg;
+ const char *ft_name;
+ struct flowtable *ft;
+ uint32_t hash;
+
+ ft = netlink_delinearize_flowtable(ctx->nlctx, nlf);
+ if (!ft)
+ return -1;
+
+ ft_name = nftnl_flowtable_get_str(nlf, NFTNL_FLOWTABLE_NAME);
+ hash = djb_hash(ft_name) % NFT_CACHE_HSIZE;
+ cache_add(&ft->cache, &ctx->table->ft_cache, hash);
+
+ return 0;
+}
+
+static int ft_cache_init(struct netlink_ctx *ctx, struct table *table,
+ struct nftnl_flowtable_list *ft_list)
+{
+ struct ft_cache_dump_ctx dump_ctx = {
+ .nlctx = ctx,
+ .table = table,
+ };
+ nftnl_flowtable_list_foreach(ft_list, ft_cache_cb, &dump_ctx);
+
+ return 0;
+}
+
+static struct nftnl_flowtable_list *ft_cache_dump(struct netlink_ctx *ctx,
+ const struct table *table,
+ int *err)
+{
+ struct nftnl_flowtable_list *ft_list;
+
+ ft_list = mnl_nft_flowtable_dump(ctx, table->handle.family,
+ table->handle.table.name);
+ if (!ft_list) {
+ if (errno == EINTR) {
+ *err = -1;
+ return NULL;
+ }
+ *err = 0;
+ return NULL;
+ }
+
+ return ft_list;
+}
+
+void ft_cache_add(struct flowtable *ft, struct table *table)
+{
+ uint32_t hash;
+
+ hash = djb_hash(ft->handle.flowtable.name) % NFT_CACHE_HSIZE;
+ cache_add(&ft->cache, &table->ft_cache, hash);
+}
+
+struct flowtable *ft_cache_find(const struct table *table, const char *name)
+{
+ struct flowtable *ft;
+ uint32_t hash;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(ft, &table->ft_cache.ht[hash], cache.hlist) {
+ if (!strcmp(ft->handle.flowtable.name, name))
+ return ft;
+ }
+
+ return NULL;
+}
static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
struct nft_cache *cache)
@@ -435,6 +511,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_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;
@@ -484,12 +561,19 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
}
}
if (flags & NFT_CACHE_FLOWTABLE_BIT) {
- ret = netlink_list_flowtables(ctx, &table->handle);
+ ft_list = ft_cache_dump(ctx, table, &ret);
+ if (!ft_list) {
+ ret = -1;
+ goto cache_fails;
+ }
+ ret = ft_cache_init(ctx, table, ft_list);
+
+ nftnl_flowtable_list_free(ft_list);
+
if (ret < 0) {
ret = -1;
goto cache_fails;
}
- list_splice_tail_init(&ctx->list, &table->flowtables);
}
if (flags & NFT_CACHE_OBJECT_BIT) {
obj_list = obj_cache_dump(ctx, table, &ret);
diff --git a/src/evaluate.c b/src/evaluate.c
index 91cedf4c..8f35ca59 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -238,7 +238,7 @@ static int flowtable_not_found(struct eval_ctx *ctx, const struct location *loc,
struct flowtable *ft;
ft = flowtable_lookup_fuzzy(ft_name, &ctx->nft->cache, &table);
- if (ft == NULL)
+ if (!ft)
return cmd_error(ctx, loc, "%s", strerror(ENOENT));
return cmd_error(ctx, loc,
@@ -4491,8 +4491,8 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
if (table == NULL)
return table_not_found(ctx);
- ft = flowtable_lookup(table, cmd->handle.flowtable.name);
- if (ft == NULL)
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
return flowtable_not_found(ctx, &ctx->cmd->handle.flowtable.location,
ctx->cmd->handle.flowtable.name);
diff --git a/src/json.c b/src/json.c
index 0b7699a6..9358cbc3 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1580,7 +1580,7 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx,
tmp = set_print_json(&ctx->nft->output, set);
json_array_append_new(root, tmp);
}
- list_for_each_entry(flowtable, &table->flowtables, list) {
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
tmp = flowtable_print_json(flowtable);
json_array_append_new(root, tmp);
}
@@ -1759,8 +1759,8 @@ static json_t *do_list_flowtable_json(struct netlink_ctx *ctx,
json_t *root = json_array();
struct flowtable *ft;
- ft = flowtable_lookup(table, cmd->handle.flowtable.name);
- if (ft == NULL)
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
return json_null();
json_array_append_new(root, flowtable_print_json(ft));
@@ -1779,7 +1779,7 @@ static json_t *do_list_flowtables_json(struct netlink_ctx *ctx, struct cmd *cmd)
cmd->handle.family != table->handle.family)
continue;
- list_for_each_entry(flowtable, &table->flowtables, list) {
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
tmp = flowtable_print_json(flowtable);
json_array_append_new(root, tmp);
}
diff --git a/src/netlink.c b/src/netlink.c
index 6323fe4e..5ed6d32f 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1534,7 +1534,7 @@ int netlink_reset_objs(struct netlink_ctx *ctx, const struct cmd *cmd,
return err;
}
-static struct flowtable *
+struct flowtable *
netlink_delinearize_flowtable(struct netlink_ctx *ctx,
struct nftnl_flowtable *nlo)
{
diff --git a/src/rule.c b/src/rule.c
index 56fb19c7..95016320 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1115,6 +1115,7 @@ struct table *table_alloc(void)
cache_init(&table->chain_cache);
cache_init(&table->set_cache);
cache_init(&table->obj_cache);
+ cache_init(&table->ft_cache);
return table;
}
@@ -1144,6 +1145,9 @@ void table_free(struct table *table)
set_free(set);
list_for_each_entry_safe(ft, nft, &table->flowtables, list)
flowtable_free(ft);
+ /* this is implicitly releasing flowtables in the hashtable cache */
+ list_for_each_entry_safe(ft, nft, &table->ft_cache.list, cache.list)
+ 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 */
@@ -1155,6 +1159,7 @@ void table_free(struct table *table)
cache_free(&table->chain_cache);
cache_free(&table->set_cache);
cache_free(&table->obj_cache);
+ cache_free(&table->ft_cache);
xfree(table);
}
@@ -1272,7 +1277,7 @@ static void table_print(const struct table *table, struct output_ctx *octx)
set_print(set, octx);
delim = "\n";
}
- list_for_each_entry(flowtable, &table->flowtables, list) {
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
nft_print(octx, "%s", delim);
flowtable_print(flowtable, octx);
delim = "\n";
@@ -2146,11 +2151,6 @@ void flowtable_free(struct flowtable *flowtable)
xfree(flowtable);
}
-void flowtable_add_hash(struct flowtable *flowtable, struct table *table)
-{
- list_add_tail(&flowtable->list, &table->flowtables);
-}
-
static void flowtable_print_declaration(const struct flowtable *flowtable,
struct print_fmt_options *opts,
struct output_ctx *octx)
@@ -2216,17 +2216,6 @@ void flowtable_print(const struct flowtable *s, struct output_ctx *octx)
do_flowtable_print(s, &opts, octx);
}
-struct flowtable *flowtable_lookup(const struct table *table, const char *name)
-{
- struct flowtable *ft;
-
- list_for_each_entry(ft, &table->flowtables, list) {
- if (!strcmp(ft->handle.flowtable.name, name))
- return ft;
- }
- return NULL;
-}
-
struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
const struct nft_cache *cache,
const struct table **t)
@@ -2238,7 +2227,7 @@ struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
string_misspell_init(&st);
list_for_each_entry(table, &cache->list, list) {
- list_for_each_entry(ft, &table->flowtables, list) {
+ list_for_each_entry(ft, &table->ft_cache.list, cache.list) {
if (!strcmp(ft->handle.flowtable.name, ft_name)) {
*t = table;
return ft;
@@ -2256,8 +2245,8 @@ static int do_list_flowtable(struct netlink_ctx *ctx, struct cmd *cmd,
{
struct flowtable *ft;
- ft = flowtable_lookup(table, cmd->handle.flowtable.name);
- if (ft == NULL)
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
return -1;
nft_print(&ctx->nft->output, "table %s %s {\n",
@@ -2289,7 +2278,7 @@ static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd)
family2str(table->handle.family),
table->handle.table.name);
- list_for_each_entry(flowtable, &table->flowtables, list) {
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
flowtable_print_declaration(flowtable, &opts, &ctx->nft->output);
nft_print(&ctx->nft->output, "%s}%s", opts.tab, opts.nl);
}