path: root/iptables/tests
diff options
authorPhil Sutter <>2020-10-05 16:06:49 +0200
committerPhil Sutter <>2020-10-13 12:08:37 +0200
commitdac904bdcd9a18aabafee7275ccf0c2bd53800f3 (patch)
treee29b5f964110b6d213f8791fb2e42bc18a0631cb /iptables/tests
parentc6cff7ddd4ee8ac8b500a9c928612acf39bfa9ec (diff)
nft: Fix for concurrent noflush restore calls
Transaction refresh was broken with regards to nft_chain_restore(): It created a rule flush batch object only if the chain was found in cache and a chain add object only if the chain was not found. Yet with concurrent ruleset updates, one has to expect both situations: * If a chain vanishes, the rule flush job must be skipped and instead the chain add job become active. * If a chain appears, the chain add job must be skipped and instead rules flushed. Change the code accordingly: Create both batch objects and set their 'skip' field depending on the situation in cache and adjust both in nft_refresh_transaction(). As a side-effect, the implicit rule flush becomes explicit and all handling of implicit batch jobs is dropped along with the related field indicating such. Reuse the 'implicit' parameter of __nft_rule_flush() to control the initial 'skip' field value instead. A subtle caveat is vanishing of existing chains: Creating the chain add job based on the chain in cache causes a netlink message containing that chain's handle which the kernel dislikes. Therefore unset the chain's handle in that case. Fixes: 58d7de0181f61 ("xtables: handle concurrent ruleset modifications") Signed-off-by: Phil Sutter <>
Diffstat (limited to 'iptables/tests')
1 files changed, 53 insertions, 0 deletions
diff --git a/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0 b/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
new file mode 100755
index 00000000..53ec12fa
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
@@ -0,0 +1,53 @@
+set -e
+:INPUT ACCEPT [12024:3123388]
+:OUTPUT ACCEPT [12840:2144421]
+:FOO - [0:0]
+:BAR0 - [0:0]
+:BAR1 - [0:0]
+:BAR2 - [0:0]
+:BAR3 - [0:0]
+:BAR4 - [0:0]
+:BAR5 - [0:0]
+:BAR6 - [0:0]
+:BAR7 - [0:0]
+:BAR8 - [0:0]
+:BAR9 - [0:0]
+-X BAR3
+-X BAR6
+-X BAR9
+-A FOO -s -j BAR1
+-A FOO -s -j BAR2
+-A FOO -s -j BAR4
+-A FOO -s -j BAR5
+-A FOO -s -j BAR7
+-A FOO -s -j BAR8
+-X BAR2
+-X BAR5
+-X BAR7
+-A FOO -s -j BAR1
+-A FOO -s -j BAR3
+-A FOO -s -j BAR4
+-A FOO -s -j BAR6
+-A FOO -s -j BAR8
+-A FOO -s -j BAR9
+for n in $(seq 1 10); do
+ $XT_MULTI iptables-restore --noflush -w <<< "$RS1" &
+ $XT_MULTI iptables-restore --noflush -w <<< "$RS2" &
+ wait -n
+ wait -n