summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2019-06-17 12:03:08 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2019-06-17 19:54:57 +0200
commit01e5c6f0ed0315046537612f5a80e506d37a7f8e (patch)
tree5e6dc94860d876f6851808812c59d83935c6c689 /src
parenta331eca90d25a1bc519a5a3a53d72a982cedb029 (diff)
src: add cache level flags
The score approach based on command type is confusing. This patch introduces cache level flags, each flag specifies what kind of object type is needed. These flags are set on/off depending on the list of commands coming in this batch. cache_is_complete() now checks if the cache contains the objects that are needed through these new flags. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/cache.c86
-rw-r--r--src/evaluate.c3
-rw-r--r--src/libnftables.c6
-rw-r--r--src/rule.c106
4 files changed, 97 insertions, 104 deletions
diff --git a/src/cache.c b/src/cache.c
index d7153f6f..d371c548 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -11,112 +11,116 @@
#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:
@@ -126,5 +130,5 @@ int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
}
}
- return max(completeness, echo_completeness);
+ return flags;
}
diff --git a/src/evaluate.c b/src/evaluate.c
index 73a4be33..511f9f14 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -29,6 +29,7 @@
#include <netlink.h>
#include <time.h>
#include <rule.h>
+#include <cache.h>
#include <erec.h>
#include <gmputil.h>
#include <utils.h>
@@ -3294,7 +3295,7 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule,
}
/* add rules to cache only if it is complete enough to contain them */
- if (!cache_is_complete(&ctx->nft->cache, CMD_LIST))
+ if (!cache_is_complete(&ctx->nft->cache, NFT_CACHE_RULE))
return 0;
return rule_cache_update(ctx, op);
diff --git a/src/libnftables.c b/src/libnftables.c
index abd133be..dccb8ab4 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -381,11 +381,11 @@ 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)
{
- unsigned int completeness;
+ unsigned int flags;
struct cmd *cmd;
- completeness = cache_evaluate(nft, cmds);
- if (cache_update(nft, completeness, msgs) < 0)
+ flags = cache_evaluate(nft, cmds);
+ if (cache_update(nft, flags, msgs) < 0)
return -1;
list_for_each_entry(cmd, cmds, list) {
diff --git a/src/rule.c b/src/rule.c
index ed199889..f60374ab 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -24,6 +24,7 @@
#include <mnl.h>
#include <misspell.h>
#include <json.h>
+#include <cache.h>
#include <libnftnl/common.h>
#include <libnftnl/ruleset.h>
@@ -147,97 +148,85 @@ static int cache_init_tables(struct netlink_ctx *ctx, struct handle *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)
@@ -245,7 +234,7 @@ 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),
@@ -259,14 +248,14 @@ int cache_update(struct nft_ctx *nft, enum cmd_ops cmd, struct list_head *msgs)
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) {
@@ -283,7 +272,7 @@ replay:
}
cache->genid = genid;
- cache->cmd = cmd;
+ cache->flags = flags;
return 0;
}
@@ -308,15 +297,14 @@ void cache_flush(struct nft_ctx *nft, struct list_head *msgs)
__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 */