Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@xxxxxxxxxxxxxxx> --- net/netfilter/nf_tables_api.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) 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); -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html