diff mbox

[nf-next/nf_tables-experiments,-,2/2] nf_tables: Add support for replacing a rule by another one.

Message ID 1351675709-14127-3-git-send-email-tomasz.bursztyka@linux.intel.com
State Superseded
Headers show

Commit Message

Tomasz Bursztyka Oct. 31, 2012, 9:28 a.m. UTC
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
---
 net/netfilter/nf_tables_api.c | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)
diff mbox

Patch

diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index fd1b624..3ce8aa1 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -1321,7 +1321,7 @@  static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 	const struct nft_af_info *afi;
 	const struct nft_table *table;
 	struct nft_chain *chain;
-	struct nft_rule *rule;
+	struct nft_rule *rule, *old_rule = NULL;
 	struct nft_expr_info info[NFT_RULE_MAXEXPRS];
 	struct nft_expr *expr;
 	struct nft_ctx ctx;
@@ -1357,9 +1357,11 @@  static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 		if (rule != NULL) {
 			if (nlh->nlmsg_flags & NLM_F_EXCL)
 				return -EEXIST;
-			if (nlh->nlmsg_flags & NLM_F_REPLACE)
-				return -EOPNOTSUPP;
-			return 0;
+			if (nlh->nlmsg_flags & NLM_F_REPLACE) {
+				old_rule = rule;
+				rule = NULL;
+			} else
+				return 0;
 		}
 	} else
 		handle = nf_tables_rule_alloc_handle(chain);
@@ -1402,7 +1404,19 @@  static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 		expr = nft_expr_next(expr);
 	}
 
-	if (nlh->nlmsg_flags & NLM_F_APPEND)
+	if (nlh->nlmsg_flags & NLM_F_REPLACE) {
+		if (old_rule == NULL)
+			goto err2;
+
+		list_replace_rcu(&old_rule->list, &rule->list);
+
+		// FIXME: this makes deletion performance *really* suck
+		synchronize_rcu();
+
+		nf_tables_rule_notify(skb, nlh, table, chain, old_rule,
+				      NFT_MSG_DELRULE, nfmsg->nfgen_family);
+		nf_tables_rule_destroy(&ctx, old_rule);
+	} else if (nlh->nlmsg_flags & NLM_F_APPEND)
 		list_add_tail_rcu(&rule->list, &chain->rules);
 	else
 		list_add_rcu(&rule->list, &chain->rules);