summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Garver <eric@garver.life>2019-05-22 21:44:04 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2019-05-24 21:14:30 +0200
commiteeda228c2d1719f5b6276b40ad14a5b3c3e88536 (patch)
tree1f4db86616df6eeb13ad92c94447766dbea73f45
parent7e71e06b7b724006c84e789aa7bcb7faadd21c48 (diff)
src: update cache if cmd is more specific
If we've done a partial fetch of the cache and the genid is the same the cache update will be skipped without fetching the needed items. This change flushes the cache if the new request is more specific than the current cache - forcing a cache update which includes the needed items. Introduces a simple scoring system which reflects how cache_init_objects() looks at the current command to decide if it is finished already or not. Then use that in cache_needs_more(): If current command's score is higher than old command's, cache needs an update. Fixes: 816d8c7659c1 ("Support 'add/insert rule index <IDX>'") Signed-off-by: Eric Garver <eric@garver.life> Signed-off-by: Phil Sutter <phil@nwl.cc> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/nftables.h1
-rw-r--r--src/rule.c20
-rwxr-xr-xtests/shell/testcases/cache/0003_cache_update_014
3 files changed, 35 insertions, 0 deletions
diff --git a/include/nftables.h b/include/nftables.h
index b17a16a4..bb9bb209 100644
--- a/include/nftables.h
+++ b/include/nftables.h
@@ -81,6 +81,7 @@ struct nft_cache {
uint16_t genid;
struct list_head list;
uint32_t seqnum;
+ uint32_t cmd;
};
struct mnl_socket;
diff --git a/src/rule.c b/src/rule.c
index dc75c7cd..17bf5bbb 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -220,6 +220,23 @@ static int cache_init(struct netlink_ctx *ctx, enum cmd_ops cmd)
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)
+{
+ if (cmd == CMD_LIST)
+ return 3;
+ if (cmd != CMD_RESET)
+ return 2;
+ return 1;
+}
+
+static bool cache_needs_more(enum cmd_ops old_cmd, enum cmd_ops cmd)
+{
+ return cache_completeness(old_cmd) < cache_completeness(cmd);
+}
+
int cache_update(struct nft_ctx *nft, enum cmd_ops cmd, struct list_head *msgs)
{
uint16_t genid;
@@ -235,6 +252,8 @@ 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->genid && cache_needs_more(cache->cmd, cmd))
+ cache_release(cache);
if (genid && genid == cache->genid)
return 0;
if (cache->genid)
@@ -250,6 +269,7 @@ replay:
return -1;
}
cache->genid = genid;
+ cache->cmd = cmd;
return 0;
}
diff --git a/tests/shell/testcases/cache/0003_cache_update_0 b/tests/shell/testcases/cache/0003_cache_update_0
index deb45db2..fa9b5df3 100755
--- a/tests/shell/testcases/cache/0003_cache_update_0
+++ b/tests/shell/testcases/cache/0003_cache_update_0
@@ -27,3 +27,17 @@ EOF
$NFT -i >/dev/null <<EOF
add table ip t3; add chain ip t c
EOF
+
+# The following test exposes a problem with incremental cache update when
+# reading commands from a file that add a rule using the "index" keyword.
+#
+# add rule ip t4 c meta l4proto icmp accept -> rule to reference in next step
+# add rule ip t4 c index 0 drop -> index 0 is not found due to rule cache not
+# being updated
+$NFT -i >/dev/null <<EOF
+add table ip t4; add chain ip t4 c
+add rule ip t4 c meta l4proto icmp accept
+EOF
+$NFT -f - >/dev/null <<EOF
+add rule ip t4 c index 0 drop
+EOF