summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2018-05-25 01:25:48 +0300
committerPablo Neira Ayuso <pablo@netfilter.org>2018-05-29 15:49:59 +0300
commit0cbc06b3faba756113d4ac748b089529f813eda4 (patch)
treeb45c95130159d0d177305862612698a4db397592 /include
parent003087911af28941a95fa053db0ac36b2ee27207 (diff)
downloadlinux-0cbc06b3faba756113d4ac748b089529f813eda4.tar.xz
netfilter: nf_tables: remove synchronize_rcu in commit phase
synchronize_rcu() is expensive. The commit phase currently enforces an unconditional synchronize_rcu() after incrementing the generation counter. This is to make sure that a packet always sees a consistent chain, either nft_do_chain is still using old generation (it will skip the newly added rules), or the new one (it will skip old ones that might still be linked into the list). We could just remove the synchronize_rcu(), it would not cause a crash but it could cause us to evaluate a rule that was removed and new rule for the same packet, instead of either-or. To resolve this, add rule pointer array holding two generations, the current one and the future generation. In commit phase, allocate the rule blob and populate it with the rules that will be active in the new generation. Then, make this rule blob public, replacing the old generation pointer. Then the generation counter can be incremented. nft_do_chain() will either continue to use the current generation (in case loop was invoked right before increment), or the new one. Suggested-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'include')
-rw-r--r--include/net/netfilter/nf_tables.h5
1 files changed, 5 insertions, 0 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 603b51401deb..6b9ddb99f3a8 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -858,6 +858,8 @@ enum nft_chain_flags {
* @name: name of the chain
*/
struct nft_chain {
+ struct nft_rule *__rcu *rules_gen_0;
+ struct nft_rule *__rcu *rules_gen_1;
struct list_head rules;
struct list_head list;
struct nft_table *table;
@@ -867,6 +869,9 @@ struct nft_chain {
u8 flags:6,
genmask:2;
char *name;
+
+ /* Only used during control plane commit phase: */
+ struct nft_rule **rules_next;
};
enum nft_chain_types {