summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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