]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
cache: do not populate cache if it is going to be flushed
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 9 Nov 2021 09:44:46 +0000 (10:44 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 11 Nov 2021 09:55:29 +0000 (10:55 +0100)
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>
include/cache.h
src/cache.c
src/libnftables.c

index 7d61701a02b5c6713e258600c91569c60fb756bb..cdf1f4fbf6f761ff45beb4f24379e0172be63e4f 100644 (file)
@@ -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;
index 58397551aafca41349be4f96caf6c2414f6b8a9c..28604aab5532eb0a9b7e328e95e63f24b0908a7f 100644 (file)
@@ -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;
 
index 2b2ed1a44329ac9bb2768c7d7ebd597722db2763..7b9d7efaeaae91cb1d94954bccea0fe21e31e421 100644 (file)
@@ -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 = {