Skip to content

Commit

Permalink
netfilter: nf_tables: defer all object release via rcu
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Pablo Neira Ayuso committed May 19, 2014
1 parent 128ad33 commit c7c32e7
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 39 deletions.
2 changes: 2 additions & 0 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -393,12 +393,14 @@ struct nft_rule {
/**
* struct nft_trans - nf_tables object update in transaction
*
* @rcu_head: rcu head to defer release of transaction data
* @list: used internally
* @msg_type: message type
* @ctx: transaction context
* @data: internal information related to the transaction
*/
struct nft_trans {
struct rcu_head rcu_head;
struct list_head list;
int msg_type;
struct nft_ctx ctx;
Expand Down
93 changes: 54 additions & 39 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit c7c32e7

Please sign in to comment.