@@ -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);
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com> --- net/netfilter/nf_tables_api.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-)