summaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2014-04-10 00:31:10 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2014-05-19 12:06:13 +0200
commitc7c32e72cbe23cea97c5d87ffcf6e23cc1ec1a65 (patch)
tree82615a2c98f2cf8d3f7446aa31040c0791f93287 /net/netfilter
parent128ad3322ba5de8fa346203c9931d1fdcab8da87 (diff)
netfilter: nf_tables: defer all object release via rcu
Now that all objects are released in the reverse order via the transaction infrastructure, we can enqueue the release via call_rcu to save one synchronize_rcu. For small rule-sets loaded via nft -f, it now takes around 50ms less here. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nf_tables_api.c93
1 files changed, 54 insertions, 39 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 4147166ad17..e171c635d08 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -3298,6 +3298,30 @@ static void nft_chain_commit_update(struct nft_trans *trans)
}
}
+/* Schedule objects for release via rcu to make sure no packets are accesing
+ * removed rules.
+ */
+static void nf_tables_commit_release_rcu(struct rcu_head *rt)
+{
+ struct nft_trans *trans = container_of(rt, struct nft_trans, rcu_head);
+
+ switch (trans->msg_type) {
+ case NFT_MSG_DELTABLE:
+ nf_tables_table_destroy(&trans->ctx);
+ break;
+ case NFT_MSG_DELCHAIN:
+ nf_tables_chain_destroy(trans->ctx.chain);
+ break;
+ case NFT_MSG_DELRULE:
+ nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
+ break;
+ case NFT_MSG_DELSET:
+ nft_set_destroy(nft_trans_set(trans));
+ break;
+ }
+ kfree(trans);
+}
+
static int nf_tables_commit(struct sk_buff *skb)
{
struct net *net = sock_net(skb->sk);
@@ -3397,32 +3421,39 @@ static int nf_tables_commit(struct sk_buff *skb)
}
}
- /* Make sure we don't see any packet traversing old rules */
- synchronize_rcu();
-
- /* Now we can safely release unused old rules */
list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
- switch (trans->msg_type) {
- case NFT_MSG_DELTABLE:
- nf_tables_table_destroy(&trans->ctx);
- break;
- case NFT_MSG_DELCHAIN:
- nf_tables_chain_destroy(trans->ctx.chain);
- break;
- case NFT_MSG_DELRULE:
- nf_tables_rule_destroy(&trans->ctx,
- nft_trans_rule(trans));
- break;
- case NFT_MSG_DELSET:
- nft_set_destroy(nft_trans_set(trans));
- break;
- }
- nft_trans_destroy(trans);
+ list_del(&trans->list);
+ trans->ctx.nla = NULL;
+ call_rcu(&trans->rcu_head, nf_tables_commit_release_rcu);
}
return 0;
}
+/* Schedule objects for release via rcu to make sure no packets are accesing
+ * aborted rules.
+ */
+static void nf_tables_abort_release_rcu(struct rcu_head *rt)
+{
+ struct nft_trans *trans = container_of(rt, struct nft_trans, rcu_head);
+
+ switch (trans->msg_type) {
+ case NFT_MSG_NEWTABLE:
+ nf_tables_table_destroy(&trans->ctx);
+ break;
+ case NFT_MSG_NEWCHAIN:
+ nf_tables_chain_destroy(trans->ctx.chain);
+ break;
+ case NFT_MSG_NEWRULE:
+ nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
+ break;
+ case NFT_MSG_NEWSET:
+ nft_set_destroy(nft_trans_set(trans));
+ break;
+ }
+ kfree(trans);
+}
+
static int nf_tables_abort(struct sk_buff *skb)
{
struct net *net = sock_net(skb->sk);
@@ -3495,26 +3526,10 @@ static int nf_tables_abort(struct sk_buff *skb)
}
}
- /* Make sure we don't see any packet accessing aborted rules */
- synchronize_rcu();
-
list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
- switch (trans->msg_type) {
- case NFT_MSG_NEWTABLE:
- nf_tables_table_destroy(&trans->ctx);
- break;
- case NFT_MSG_NEWCHAIN:
- nf_tables_chain_destroy(trans->ctx.chain);
- break;
- case NFT_MSG_NEWRULE:
- nf_tables_rule_destroy(&trans->ctx,
- nft_trans_rule(trans));
- break;
- case NFT_MSG_NEWSET:
- nft_set_destroy(nft_trans_set(trans));
- break;
- }
- nft_trans_destroy(trans);
+ list_del(&trans->list);
+ trans->ctx.nla = NULL;
+ call_rcu(&trans->rcu_head, nf_tables_abort_release_rcu);
}
return 0;