]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: update cache if cmd is more specific
authorEric Garver <eric@garver.life>
Wed, 22 May 2019 19:44:04 +0000 (21:44 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 24 May 2019 19:14:30 +0000 (21:14 +0200)
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>
include/nftables.h
src/rule.c
tests/shell/testcases/cache/0003_cache_update_0

index b17a16a4adef7e553a65dc381b9709e1a0108a85..bb9bb2091716d36ce93618d23e0939be282f856b 100644 (file)
@@ -81,6 +81,7 @@ struct nft_cache {
        uint16_t                genid;
        struct list_head        list;
        uint32_t                seqnum;
+       uint32_t                cmd;
 };
 
 struct mnl_socket;
index dc75c7cd5fb0862d0a58f166a438309536229a24..17bf5bbbe680c771aa47a6fc4ce3dc2fba9a5e7e 100644 (file)
@@ -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;
 }
 
index deb45db2c43be7e88bfa20a1fda73141fbcf4b93..fa9b5df380a4155a716b4b7c7cc28c0c8fdd5970 100755 (executable)
@@ -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