--- /dev/null
+#ifndef _NFT_CACHE_H_
+#define _NFT_CACHE_H_
+
+enum cache_level_bits {
+ NFT_CACHE_TABLE_BIT = (1 << 0),
+ NFT_CACHE_CHAIN_BIT = (1 << 1),
+ NFT_CACHE_SET_BIT = (1 << 2),
+ NFT_CACHE_FLOWTABLE_BIT = (1 << 3),
+ NFT_CACHE_OBJECT_BIT = (1 << 4),
+ NFT_CACHE_SETELEM_BIT = (1 << 5),
+ NFT_CACHE_RULE_BIT = (1 << 6),
+ __NFT_CACHE_MAX_BIT = (1 << 7),
+};
+
+enum cache_level_flags {
+ NFT_CACHE_EMPTY = 0,
+ NFT_CACHE_TABLE = NFT_CACHE_TABLE_BIT,
+ NFT_CACHE_CHAIN = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_CHAIN_BIT,
+ NFT_CACHE_SET = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_SET_BIT,
+ NFT_CACHE_FLOWTABLE = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_FLOWTABLE_BIT,
+ NFT_CACHE_OBJECT = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_OBJECT_BIT,
+ NFT_CACHE_SETELEM = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_SET_BIT |
+ NFT_CACHE_SETELEM_BIT,
+ NFT_CACHE_RULE = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_CHAIN_BIT |
+ NFT_CACHE_RULE_BIT,
+ NFT_CACHE_FULL = __NFT_CACHE_MAX_BIT - 1,
+};
+
+#endif /* _NFT_CACHE_H_ */
#include <rule.h>
#include <erec.h>
#include <utils.h>
+#include <cache.h>
-static unsigned int evaluate_cache_add(struct cmd *cmd)
+static unsigned int evaluate_cache_add(struct cmd *cmd, unsigned int flags)
{
- unsigned int completeness = CMD_INVALID;
-
switch (cmd->obj) {
case CMD_OBJ_SETELEM:
- case CMD_OBJ_SET:
- case CMD_OBJ_CHAIN:
- case CMD_OBJ_FLOWTABLE:
- completeness = cmd->op;
+ flags |= NFT_CACHE_SETELEM;
break;
case CMD_OBJ_RULE:
- if (cmd->handle.index.id)
- completeness = CMD_LIST;
+ if (cmd->handle.index.id ||
+ cmd->handle.position.id)
+ flags |= NFT_CACHE_RULE;
break;
default:
break;
}
- return completeness;
+ return flags;
}
-static unsigned int evaluate_cache_del(struct cmd *cmd)
+static unsigned int evaluate_cache_del(struct cmd *cmd, unsigned int flags)
{
- unsigned int completeness = CMD_INVALID;
-
switch (cmd->obj) {
case CMD_OBJ_SETELEM:
- completeness = cmd->op;
+ flags |= NFT_CACHE_SETELEM;
break;
default:
break;
}
- return completeness;
+ return flags;
}
-static unsigned int evaluate_cache_flush(struct cmd *cmd)
+static unsigned int evaluate_cache_flush(struct cmd *cmd, unsigned int flags)
{
- unsigned int completeness = CMD_INVALID;
-
switch (cmd->obj) {
- case CMD_OBJ_RULESET:
- completeness = __CMD_FLUSH_RULESET;
- break;
case CMD_OBJ_SET:
case CMD_OBJ_MAP:
case CMD_OBJ_METER:
- completeness = cmd->op;
+ flags |= NFT_CACHE_SET;
break;
+ case CMD_OBJ_RULESET:
default:
+ flags = NFT_CACHE_EMPTY;
break;
}
- return completeness;
+ return flags;
}
-static unsigned int evaluate_cache_rename(struct cmd *cmd)
+static unsigned int evaluate_cache_rename(struct cmd *cmd, unsigned int flags)
{
- unsigned int completeness = CMD_INVALID;
-
switch (cmd->obj) {
case CMD_OBJ_CHAIN:
- completeness = cmd->op;
+ flags |= NFT_CACHE_CHAIN;
break;
default:
break;
}
- return completeness;
+ return flags;
}
-int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
+unsigned int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
{
- unsigned int echo_completeness = CMD_INVALID;
- unsigned int completeness = CMD_INVALID;
+ unsigned int flags = NFT_CACHE_EMPTY;
struct cmd *cmd;
list_for_each_entry(cmd, cmds, list) {
switch (cmd->op) {
case CMD_ADD:
case CMD_INSERT:
- case CMD_REPLACE:
- if (nft_output_echo(&nft->output))
- echo_completeness = cmd->op;
-
+ if (nft_output_echo(&nft->output)) {
+ flags = NFT_CACHE_FULL;
+ break;
+ }
+
+ flags |= NFT_CACHE_TABLE |
+ NFT_CACHE_CHAIN |
+ NFT_CACHE_SET |
+ NFT_CACHE_FLOWTABLE |
+ NFT_CACHE_OBJECT;
/* Fall through */
case CMD_CREATE:
- completeness = evaluate_cache_add(cmd);
+ flags = evaluate_cache_add(cmd, flags);
+ break;
+ case CMD_REPLACE:
+ flags = NFT_CACHE_FULL;
break;
case CMD_DELETE:
- completeness = evaluate_cache_del(cmd);
+ flags |= NFT_CACHE_TABLE |
+ NFT_CACHE_CHAIN |
+ NFT_CACHE_SET |
+ NFT_CACHE_FLOWTABLE |
+ NFT_CACHE_OBJECT;
+
+ flags = evaluate_cache_del(cmd, flags);
break;
case CMD_GET:
case CMD_LIST:
case CMD_RESET:
case CMD_EXPORT:
case CMD_MONITOR:
- completeness = cmd->op;
+ flags |= NFT_CACHE_FULL;
break;
case CMD_FLUSH:
- completeness = evaluate_cache_flush(cmd);
+ flags = evaluate_cache_flush(cmd, flags);
break;
case CMD_RENAME:
- completeness = evaluate_cache_rename(cmd);
+ flags = evaluate_cache_rename(cmd, flags);
break;
case CMD_DESCRIBE:
case CMD_IMPORT:
}
}
- return max(completeness, echo_completeness);
+ return flags;
}
#include <mnl.h>
#include <misspell.h>
#include <json.h>
+#include <cache.h>
#include <libnftnl/common.h>
#include <libnftnl/ruleset.h>
return 0;
}
-static int cache_init_objects(struct netlink_ctx *ctx, enum cmd_ops cmd)
+static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
{
+ struct rule *rule, *nrule;
struct table *table;
struct chain *chain;
- struct rule *rule, *nrule;
struct set *set;
int ret;
list_for_each_entry(table, &ctx->nft->cache.list, list) {
- ret = netlink_list_sets(ctx, &table->handle);
- list_splice_tail_init(&ctx->list, &table->sets);
-
- if (ret < 0)
- return -1;
-
- list_for_each_entry(set, &table->sets, list) {
- ret = netlink_list_setelems(ctx, &set->handle, set);
+ if (flags & NFT_CACHE_SET_BIT) {
+ ret = netlink_list_sets(ctx, &table->handle);
+ list_splice_tail_init(&ctx->list, &table->sets);
if (ret < 0)
return -1;
}
-
- ret = netlink_list_chains(ctx, &table->handle);
- if (ret < 0)
- return -1;
- list_splice_tail_init(&ctx->list, &table->chains);
-
- ret = netlink_list_flowtables(ctx, &table->handle);
- if (ret < 0)
- return -1;
- list_splice_tail_init(&ctx->list, &table->flowtables);
-
- if (cmd != CMD_RESET) {
+ if (flags & NFT_CACHE_SETELEM_BIT) {
+ list_for_each_entry(set, &table->sets, list) {
+ ret = netlink_list_setelems(ctx, &set->handle,
+ set);
+ if (ret < 0)
+ return -1;
+ }
+ }
+ if (flags & NFT_CACHE_CHAIN_BIT) {
+ ret = netlink_list_chains(ctx, &table->handle);
+ if (ret < 0)
+ return -1;
+ list_splice_tail_init(&ctx->list, &table->chains);
+ }
+ if (flags & NFT_CACHE_FLOWTABLE_BIT) {
+ ret = netlink_list_flowtables(ctx, &table->handle);
+ if (ret < 0)
+ return -1;
+ list_splice_tail_init(&ctx->list, &table->flowtables);
+ }
+ if (flags & NFT_CACHE_OBJECT_BIT) {
ret = netlink_list_objs(ctx, &table->handle);
if (ret < 0)
return -1;
list_splice_tail_init(&ctx->list, &table->objs);
}
- /* Skip caching other objects to speed up things: We only need
- * a full cache when listing the existing ruleset.
- */
- if (cmd != CMD_LIST)
- continue;
-
- ret = netlink_list_rules(ctx, &table->handle);
- list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
- chain = chain_lookup(table, &rule->handle);
- list_move_tail(&rule->list, &chain->rules);
+ if (flags & NFT_CACHE_RULE_BIT) {
+ ret = netlink_list_rules(ctx, &table->handle);
+ list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
+ chain = chain_lookup(table, &rule->handle);
+ list_move_tail(&rule->list, &chain->rules);
+ }
+ if (ret < 0)
+ return -1;
}
-
- if (ret < 0)
- return -1;
}
return 0;
}
-static int cache_init(struct netlink_ctx *ctx, enum cmd_ops cmd)
+static int cache_init(struct netlink_ctx *ctx, unsigned int flags)
{
struct handle handle = {
.family = NFPROTO_UNSPEC,
};
int ret;
- if (cmd == __CMD_FLUSH_RULESET)
+ if (flags == NFT_CACHE_EMPTY)
return 0;
+ /* assume NFT_CACHE_TABLE is always set. */
ret = cache_init_tables(ctx, &handle, &ctx->nft->cache);
if (ret < 0)
return ret;
- ret = cache_init_objects(ctx, cmd);
+ ret = cache_init_objects(ctx, flags);
if (ret < 0)
return ret;
return 0;
}
-/* Return a "score" of how complete local cache will be if
- * cache_init_objects() ran for given cmd. Higher value
- * means more complete. */
-static int cache_completeness(enum cmd_ops cmd)
+bool cache_is_complete(struct nft_cache *cache, unsigned int flags)
{
- if (cmd == CMD_LIST)
- return 3;
- if (cmd != CMD_RESET)
- return 2;
- return 1;
-}
-
-bool cache_is_complete(struct nft_cache *cache, enum cmd_ops cmd)
-{
- return cache_completeness(cache->cmd) >= cache_completeness(cmd);
+ return (cache->flags & flags) == flags;
}
static bool cache_is_updated(struct nft_cache *cache, uint16_t genid)
return genid && genid == cache->genid;
}
-int cache_update(struct nft_ctx *nft, enum cmd_ops cmd, struct list_head *msgs)
+int cache_update(struct nft_ctx *nft, unsigned int flags, struct list_head *msgs)
{
struct netlink_ctx ctx = {
.list = LIST_HEAD_INIT(ctx.list),
replay:
ctx.seqnum = cache->seqnum++;
genid = mnl_genid_get(&ctx);
- if (cache_is_complete(cache, cmd) &&
+ if (cache_is_complete(cache, flags) &&
cache_is_updated(cache, genid))
return 0;
if (cache->genid)
cache_release(cache);
- ret = cache_init(&ctx, cmd);
+ ret = cache_init(&ctx, flags);
if (ret < 0) {
cache_release(cache);
if (errno == EINTR) {
}
cache->genid = genid;
- cache->cmd = cmd;
+ cache->flags = flags;
return 0;
}
__cache_flush(&cache->list);
cache->genid = mnl_genid_get(&ctx);
- cache->cmd = CMD_LIST;
+ cache->flags = NFT_CACHE_FULL;
}
void cache_release(struct nft_cache *cache)
{
__cache_flush(&cache->list);
cache->genid = 0;
- cache->cmd = CMD_INVALID;
-
+ cache->flags = NFT_CACHE_EMPTY;
}
/* internal ID to uniquely identify a set in the batch */