summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2021-11-09 10:44:46 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2021-11-11 10:55:29 +0100
commitdffc0e109ed4780c6d79c52fb5be8cda2d63fc6b (patch)
tree6e70f590d1b7d6b4606e9b11e0254743a0c0235e
parent88e53b5dac2b55905dbf86d7def2fee51bf2a8dd (diff)
cache: do not populate cache if it is going to be flushed
Skip set element netlink dump if set is flushed, this speeds up set flush + add element operation in a batch file for an existing set. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/cache.h16
-rw-r--r--src/cache.c71
-rw-r--r--src/libnftables.c11
3 files changed, 92 insertions, 6 deletions
diff --git a/include/cache.h b/include/cache.h
index 7d61701a..cdf1f4fb 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -38,11 +38,24 @@ enum cache_level_flags {
NFT_CACHE_FLUSHED = (1 << 31),
};
+struct nft_filter_obj {
+ struct list_head list;
+ uint32_t family;
+ const char *table;
+ const char *set;
+};
+
+#define NFT_CACHE_HSIZE 8192
+
struct nft_cache_filter {
struct {
const char *table;
const char *set;
} list;
+
+ struct {
+ struct list_head head;
+ } obj[NFT_CACHE_HSIZE];
};
struct nft_cache;
@@ -66,7 +79,8 @@ static inline uint32_t djb_hash(const char *key)
return hash;
}
-#define NFT_CACHE_HSIZE 8192
+struct nft_cache_filter *nft_cache_filter_init(void);
+void nft_cache_filter_fini(struct nft_cache_filter *filter);
struct table;
struct chain;
diff --git a/src/cache.c b/src/cache.c
index 58397551..28604aab 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -96,13 +96,74 @@ static unsigned int evaluate_cache_get(struct cmd *cmd, unsigned int flags)
return flags;
}
-static unsigned int evaluate_cache_flush(struct cmd *cmd, unsigned int flags)
+struct nft_cache_filter *nft_cache_filter_init(void)
+{
+ struct nft_cache_filter *filter;
+ int i;
+
+ filter = xzalloc(sizeof(struct nft_cache_filter));
+ memset(&filter->list, 0, sizeof(filter->list));
+ for (i = 0; i < NFT_CACHE_HSIZE; i++)
+ init_list_head(&filter->obj[i].head);
+
+ return filter;
+}
+
+void nft_cache_filter_fini(struct nft_cache_filter *filter)
+{
+ int i;
+
+ for (i = 0; i < NFT_CACHE_HSIZE; i++) {
+ struct nft_filter_obj *obj, *next;
+
+ list_for_each_entry_safe(obj, next, &filter->obj[i].head, list)
+ xfree(obj);
+ }
+ xfree(filter);
+}
+
+static void cache_filter_add(struct nft_cache_filter *filter,
+ const struct cmd *cmd)
+{
+ struct nft_filter_obj *obj;
+ uint32_t hash;
+
+ obj = xmalloc(sizeof(struct nft_filter_obj));
+ obj->family = cmd->handle.family;
+ obj->table = cmd->handle.table.name;
+ obj->set = cmd->handle.set.name;
+
+ hash = djb_hash(cmd->handle.set.name) % NFT_CACHE_HSIZE;
+ list_add_tail(&obj->list, &filter->obj[hash].head);
+}
+
+static bool cache_filter_find(const struct nft_cache_filter *filter,
+ const struct handle *handle)
+{
+ struct nft_filter_obj *obj;
+ uint32_t hash;
+
+ hash = djb_hash(handle->set.name) % NFT_CACHE_HSIZE;
+
+ list_for_each_entry(obj, &filter->obj[hash].head, list) {
+ if (obj->family == handle->family &&
+ !strcmp(obj->table, handle->table.name) &&
+ !strcmp(obj->set, handle->set.name))
+ return true;
+ }
+
+ return false;
+}
+
+static unsigned int evaluate_cache_flush(struct cmd *cmd, unsigned int flags,
+ struct nft_cache_filter *filter)
{
switch (cmd->obj) {
case CMD_OBJ_SET:
case CMD_OBJ_MAP:
case CMD_OBJ_METER:
flags |= NFT_CACHE_SET;
+ cache_filter_add(filter, cmd);
break;
case CMD_OBJ_RULESET:
flags |= NFT_CACHE_FLUSHED;
@@ -219,7 +280,7 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
flags |= NFT_CACHE_FULL;
break;
case CMD_FLUSH:
- flags = evaluate_cache_flush(cmd, flags);
+ flags = evaluate_cache_flush(cmd, flags, filter);
break;
case CMD_RENAME:
flags = evaluate_cache_rename(cmd, flags);
@@ -685,6 +746,9 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
}
if (flags & NFT_CACHE_SETELEM_BIT) {
list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (cache_filter_find(filter, &set->handle))
+ continue;
+
ret = netlink_list_setelems(ctx, &set->handle,
set);
if (ret < 0) {
@@ -694,6 +758,9 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
}
} else if (flags & NFT_CACHE_SETELEM_MAYBE) {
list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (cache_filter_find(filter, &set->handle))
+ continue;
+
if (!set_is_non_concat_range(set))
continue;
diff --git a/src/libnftables.c b/src/libnftables.c
index 2b2ed1a4..7b9d7efa 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -459,13 +459,18 @@ static int nft_parse_bison_filename(struct nft_ctx *nft, const char *filename,
static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
struct list_head *cmds)
{
- struct nft_cache_filter filter = {};
+ struct nft_cache_filter *filter;
unsigned int flags;
struct cmd *cmd;
- flags = nft_cache_evaluate(nft, cmds, &filter);
- if (nft_cache_update(nft, flags, msgs, &filter) < 0)
+ filter = nft_cache_filter_init();
+ flags = nft_cache_evaluate(nft, cmds, filter);
+ if (nft_cache_update(nft, flags, msgs, filter) < 0) {
+ nft_cache_filter_fini(filter);
return -1;
+ }
+
+ nft_cache_filter_fini(filter);
list_for_each_entry(cmd, cmds, list) {
struct eval_ctx ectx = {