@@ -38,11 +38,23 @@ enum cache_level_flags {
NFT_CACHE_FLUSHED = (1 << 31),
};
+struct nft_filter_obj {
+ struct list_head list;
+ 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,8 +78,6 @@ static inline uint32_t djb_hash(const char *key)
return hash;
}
-#define NFT_CACHE_HSIZE 8192
-
struct table;
struct chain;
@@ -96,13 +96,46 @@ 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)
+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->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 (!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;
@@ -181,6 +214,10 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
{
unsigned int flags = NFT_CACHE_EMPTY;
struct cmd *cmd;
+ int i;
+
+ for (i = 0; i < NFT_CACHE_HSIZE; i++)
+ init_list_head(&filter->obj[i].head);
list_for_each_entry(cmd, cmds, list) {
if (filter->list.table && cmd->op != CMD_LIST)
@@ -219,7 +256,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);
@@ -659,7 +696,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
struct table *table;
struct chain *chain;
struct set *set;
- int ret = 0;
+ int ret = 0, i;
if (flags & NFT_CACHE_CHAIN_BIT) {
chain_list = chain_cache_dump(ctx, &ret);
@@ -685,6 +722,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 +734,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;
@@ -765,6 +808,13 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
}
cache_fails:
+ 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);
+ }
+
if (flags & NFT_CACHE_CHAIN_BIT)
nftnl_chain_list_free(chain_list);
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> --- v2: use a hashtable. include/cache.h | 14 +++++++++++-- src/cache.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 5 deletions(-)