From patchwork Thu Mar 27 21:53:12 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 334475 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id B2EE1140092 for ; Fri, 28 Mar 2014 08:53:42 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757407AbaC0Vxe (ORCPT ); Thu, 27 Mar 2014 17:53:34 -0400 Received: from mail.us.es ([193.147.175.20]:49510 "EHLO mail.us.es" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757213AbaC0Vxd (ORCPT ); Thu, 27 Mar 2014 17:53:33 -0400 Received: (qmail 25650 invoked from network); 27 Mar 2014 22:53:32 +0100 Received: from unknown (HELO us.es) (192.168.2.15) by us.es with SMTP; 27 Mar 2014 22:53:32 +0100 Received: (qmail 15700 invoked by uid 507); 27 Mar 2014 21:53:31 -0000 X-Qmail-Scanner-Diagnostics: from 127.0.0.1 by antivirus5 (envelope-from , uid 501) with qmail-scanner-2.10 (clamdscan: 0.98.1/18706. spamassassin: 3.3.2. Clear:RC:1(127.0.0.1):SA:0(-102.2/7.5):. Processed in 2.898375 secs); 27 Mar 2014 21:53:31 -0000 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on antivirus5 X-Spam-Level: X-Spam-Status: No, score=-102.2 required=7.5 tests=ALL_TRUSTED,BAYES_50, SMTPAUTH_US,USER_IN_WHITELIST autolearn=disabled version=3.3.2 X-Spam-ASN: X-Envelope-From: pablo@netfilter.org Received: from unknown (HELO antivirus5) (127.0.0.1) by us.es with SMTP; 27 Mar 2014 21:53:29 -0000 Received: from 192.168.1.13 (192.168.1.13) by antivirus5 (F-Secure/fsigk_smtp/412/antivirus5); Thu, 27 Mar 2014 22:53:28 +0100 (CET) X-Virus-Status: clean(F-Secure/fsigk_smtp/412/antivirus5) Received: (qmail 2412 invoked from network); 27 Mar 2014 22:53:28 +0100 Received: from unknown (HELO soleta.us.es) (pneira@us.es@10.100.44.199) by mail.us.es with SMTP; 27 Mar 2014 22:53:28 +0100 From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Cc: kaber@trash.net Subject: [PATCH 2/7] netfilter: nf_tables: generalise transaction infrastructure Date: Thu, 27 Mar 2014 22:53:12 +0100 Message-Id: <1395957197-4899-3-git-send-email-pablo@netfilter.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1395957197-4899-1-git-send-email-pablo@netfilter.org> References: <1395957197-4899-1-git-send-email-pablo@netfilter.org> Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org This patch generalises the existing rule transaction infrastructure so it can be used to handle set, table and chain object transactions as well. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 15 +++-- net/netfilter/nf_tables_api.c | 114 +++++++++++++++++++++---------------- 2 files changed, 75 insertions(+), 54 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 13cd713..03940f3 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -340,17 +340,24 @@ struct nft_rule { __attribute__((aligned(__alignof__(struct nft_expr)))); }; +enum nft_trans_type { + NFT_TRANS_RULE, +}; + /** - * struct nft_rule_trans - nf_tables rule update in transaction + * struct nft_trans - nf_tables object update in transaction * * @list: used internally + * @type: object type * @ctx: rule context - * @rule: rule that needs to be updated */ -struct nft_rule_trans { +struct nft_trans { struct list_head list; + enum nft_trans_type type; struct nft_ctx ctx; - struct nft_rule *rule; + union { + struct nft_rule *rule; + }; }; static inline struct nft_expr *nft_expr_first(const struct nft_rule *rule) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 48a5645..203a6bd 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -105,6 +105,21 @@ static void nft_ctx_init(struct nft_ctx *ctx, ctx->nla = nla; } +static struct nft_trans *nft_trans_alloc(struct nft_ctx *ctx, + enum nft_trans_type type) +{ + struct nft_trans *trans; + + trans = kzalloc(sizeof(struct nft_trans), GFP_KERNEL); + if (trans == NULL) + return NULL; + + trans->type = type; + trans->ctx = *ctx; + + return trans; +} + /* * Tables */ @@ -1558,20 +1573,19 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx, static struct nft_expr_info *info; -static struct nft_rule_trans * -nf_tables_trans_add(struct nft_ctx *ctx, struct nft_rule *rule) +static struct nft_trans * +nft_rule_trans_add(struct nft_ctx *ctx, struct nft_rule *rule) { - struct nft_rule_trans *rupd; + struct nft_trans *trans; - rupd = kmalloc(sizeof(struct nft_rule_trans), GFP_KERNEL); - if (rupd == NULL) - return NULL; + trans = nft_trans_alloc(ctx, NFT_TRANS_RULE); + if (trans == NULL) + return NULL; - rupd->ctx = *ctx; - rupd->rule = rule; - list_add_tail(&rupd->list, &ctx->net->nft.commit_list); + trans->rule = rule; + list_add_tail(&trans->list, &ctx->net->nft.commit_list); - return rupd; + return trans; } static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, @@ -1584,7 +1598,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, struct nft_table *table; struct nft_chain *chain; struct nft_rule *rule, *old_rule = NULL; - struct nft_rule_trans *repl = NULL; + struct nft_trans *trans = NULL; struct nft_expr *expr; struct nft_ctx ctx; struct nlattr *tmp; @@ -1682,8 +1696,8 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, if (nlh->nlmsg_flags & NLM_F_REPLACE) { if (nft_rule_is_active_next(net, old_rule)) { - repl = nf_tables_trans_add(&ctx, old_rule); - if (repl == NULL) { + trans = nft_rule_trans_add(&ctx, old_rule); + if (trans == NULL) { err = -ENOMEM; goto err2; } @@ -1705,7 +1719,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, list_add_rcu(&rule->list, &chain->rules); } - if (nf_tables_trans_add(&ctx, rule) == NULL) { + if (nft_rule_trans_add(&ctx, rule) == NULL) { err = -ENOMEM; goto err3; } @@ -1713,11 +1727,11 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, err3: list_del_rcu(&rule->list); - if (repl) { - list_del_rcu(&repl->rule->list); - list_del(&repl->list); - nft_rule_clear(net, repl->rule); - kfree(repl); + if (trans) { + list_del_rcu(&trans->rule->list); + list_del(&trans->list); + nft_rule_clear(net, trans->rule); + kfree(trans); } err2: nf_tables_rule_destroy(&ctx, rule); @@ -1734,7 +1748,7 @@ nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule) { /* You cannot delete the same rule twice */ if (nft_rule_is_active_next(ctx->net, rule)) { - if (nf_tables_trans_add(ctx, rule) == NULL) + if (nft_rule_trans_add(ctx, rule) == NULL) return -ENOMEM; nft_rule_disactivate_next(ctx->net, rule); return 0; @@ -1810,7 +1824,7 @@ static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb, static int nf_tables_commit(struct sk_buff *skb) { struct net *net = sock_net(skb->sk); - struct nft_rule_trans *rupd, *tmp; + struct nft_trans *trans, *next; /* Bump generation counter, invalidate any dump in progress */ net->nft.genctr++; @@ -1823,38 +1837,38 @@ static int nf_tables_commit(struct sk_buff *skb) */ synchronize_rcu(); - list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) { + list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { /* This rule was inactive in the past and just became active. * Clear the next bit of the genmask since its meaning has * changed, now it is the future. */ - if (nft_rule_is_active(net, rupd->rule)) { - nft_rule_clear(net, rupd->rule); - nf_tables_rule_notify(skb, rupd->ctx.nlh, - rupd->ctx.table, rupd->ctx.chain, - rupd->rule, NFT_MSG_NEWRULE, 0, - rupd->ctx.afi->family); - list_del(&rupd->list); - kfree(rupd); + if (nft_rule_is_active(net, trans->rule)) { + nft_rule_clear(net, trans->rule); + nf_tables_rule_notify(skb, trans->ctx.nlh, + trans->ctx.table, trans->ctx.chain, + trans->rule, NFT_MSG_NEWRULE, 0, + trans->ctx.afi->family); + list_del(&trans->list); + kfree(trans); continue; } /* This rule is in the past, get rid of it */ - list_del_rcu(&rupd->rule->list); - nf_tables_rule_notify(skb, rupd->ctx.nlh, - rupd->ctx.table, rupd->ctx.chain, - rupd->rule, NFT_MSG_DELRULE, 0, - rupd->ctx.afi->family); + list_del_rcu(&trans->rule->list); + nf_tables_rule_notify(skb, trans->ctx.nlh, + trans->ctx.table, trans->ctx.chain, + trans->rule, NFT_MSG_DELRULE, 0, + trans->ctx.afi->family); } /* 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(rupd, tmp, &net->nft.commit_list, list) { - nf_tables_rule_destroy(&rupd->ctx, rupd->rule); - list_del(&rupd->list); - kfree(rupd); + list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { + nf_tables_rule_destroy(&trans->ctx, trans->rule); + list_del(&trans->list); + kfree(trans); } return 0; @@ -1863,27 +1877,27 @@ static int nf_tables_commit(struct sk_buff *skb) static int nf_tables_abort(struct sk_buff *skb) { struct net *net = sock_net(skb->sk); - struct nft_rule_trans *rupd, *tmp; + struct nft_trans *trans, *next; - list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) { - if (!nft_rule_is_active_next(net, rupd->rule)) { - nft_rule_clear(net, rupd->rule); - list_del(&rupd->list); - kfree(rupd); + list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { + if (!nft_rule_is_active_next(net, trans->rule)) { + nft_rule_clear(net, trans->rule); + list_del(&trans->list); + kfree(trans); continue; } /* This rule is inactive, get rid of it */ - list_del_rcu(&rupd->rule->list); + list_del_rcu(&trans->rule->list); } /* Make sure we don't see any packet accessing aborted rules */ synchronize_rcu(); - list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) { - nf_tables_rule_destroy(&rupd->ctx, rupd->rule); - list_del(&rupd->list); - kfree(rupd); + list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { + nf_tables_rule_destroy(&trans->ctx, trans->rule); + list_del(&trans->list); + kfree(trans); } return 0;