diff mbox series

[net-next,9/9] netfilter: nf_tables: add support to destroy operation

Message ID 20230118123208.17167-10-fw@strlen.de (mailing list archive)
State Accepted
Commit f80a612dd77c4585171e44a06b490466bdeec1ae
Delegated to: Netdev Maintainers
Headers show
Series [net-next,1/9] netfilter: conntrack: sctp: use nf log infrastructure for invalid packets | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next, async
netdev/apply success Patch already applied to net-next

Commit Message

Florian Westphal Jan. 18, 2023, 12:32 p.m. UTC
From: Fernando Fernandez Mancera <ffmancera@riseup.net>

Introduce NFT_MSG_DESTROY* message type. The destroy operation performs a
delete operation but ignoring the ENOENT errors.

This is useful for the transaction semantics, where failing to delete an
object which does not exist results in aborting the transaction.

This new command allows the transaction to proceed in case the object
does not exist.

Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/uapi/linux/netfilter/nf_tables.h |  14 +++
 net/netfilter/nf_tables_api.c            | 111 +++++++++++++++++++++--
 2 files changed, 117 insertions(+), 8 deletions(-)

Comments

Vlad Buslov Jan. 19, 2023, 7:29 a.m. UTC | #1
On Wed 18 Jan 2023 at 13:32, Florian Westphal <fw@strlen.de> wrote:
> From: Fernando Fernandez Mancera <ffmancera@riseup.net>
>
> Introduce NFT_MSG_DESTROY* message type. The destroy operation performs a
> delete operation but ignoring the ENOENT errors.
>
> This is useful for the transaction semantics, where failing to delete an
> object which does not exist results in aborting the transaction.
>
> This new command allows the transaction to proceed in case the object
> does not exist.
>
> Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
> Signed-off-by: Florian Westphal <fw@strlen.de>
> ---
>  include/uapi/linux/netfilter/nf_tables.h |  14 +++
>  net/netfilter/nf_tables_api.c            | 111 +++++++++++++++++++++--
>  2 files changed, 117 insertions(+), 8 deletions(-)
>
> diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
> index cfa844da1ce6..ff677f3a6cad 100644
> --- a/include/uapi/linux/netfilter/nf_tables.h
> +++ b/include/uapi/linux/netfilter/nf_tables.h
> @@ -98,6 +98,13 @@ enum nft_verdicts {
>   * @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
>   * @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
>   * @NFT_MSG_GETRULE_RESET: get rules and reset stateful expressions (enum nft_obj_attributes)
> + * @NFT_MSG_DESTROYTABLE: destroy a table (enum nft_table_attributes)
> + * @NFT_MSG_DESTROYCHAIN: destroy a chain (enum nft_chain_attributes)
> + * @NFT_MSG_DESTROYRULE: destroy a rule (enum nft_rule_attributes)
> + * @NFT_MSG_DESTROYSET: destroy a set (enum nft_set_attributes)
> + * @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes)
> + * @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes)
> + * @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes)
>   */
>  enum nf_tables_msg_types {
>  	NFT_MSG_NEWTABLE,
> @@ -126,6 +133,13 @@ enum nf_tables_msg_types {
>  	NFT_MSG_GETFLOWTABLE,
>  	NFT_MSG_DELFLOWTABLE,
>  	NFT_MSG_GETRULE_RESET,
> +	NFT_MSG_DESTROYTABLE,
> +	NFT_MSG_DESTROYCHAIN,
> +	NFT_MSG_DESTROYRULE,
> +	NFT_MSG_DESTROYSET,
> +	NFT_MSG_DESTROYSETELEM,
> +	NFT_MSG_DESTROYOBJ,
> +	NFT_MSG_DESTROYFLOWTABLE,
>  	NFT_MSG_MAX,
>  };
>  
> diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
> index 8c09e4d12ac1..974b95dece1d 100644
> --- a/net/netfilter/nf_tables_api.c
> +++ b/net/netfilter/nf_tables_api.c
> @@ -1401,6 +1401,10 @@ static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info,
>  	}
>  
>  	if (IS_ERR(table)) {
> +		if (PTR_ERR(table) == -ENOENT &&
> +		    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYTABLE)
> +			return 0;
> +
>  		NL_SET_BAD_ATTR(extack, attr);
>  		return PTR_ERR(table);
>  	}
> @@ -2639,6 +2643,10 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
>  		chain = nft_chain_lookup(net, table, attr, genmask);
>  	}
>  	if (IS_ERR(chain)) {
> +		if (PTR_ERR(chain) == -ENOENT &&
> +		    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYCHAIN)
> +			return 0;
> +
>  		NL_SET_BAD_ATTR(extack, attr);
>  		return PTR_ERR(chain);
>  	}
> @@ -3716,6 +3724,10 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
>  		chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN],
>  					 genmask);
>  		if (IS_ERR(chain)) {
> +			if (PTR_ERR(rule) == -ENOENT &&

Coverity complains that at this point rule is not initialized yet, which
looks like to be the case to me.

[...]
Fernando F. Mancera Jan. 20, 2023, 9:58 a.m. UTC | #2
Hi Vlad,

On 19/01/2023 08:29, Vlad Buslov wrote:
> On Wed 18 Jan 2023 at 13:32, Florian Westphal <fw@strlen.de> wrote:
>> From: Fernando Fernandez Mancera <ffmancera@riseup.net>
>>
>> Introduce NFT_MSG_DESTROY* message type. The destroy operation performs a
>> delete operation but ignoring the ENOENT errors.
>>
>> This is useful for the transaction semantics, where failing to delete an
>> object which does not exist results in aborting the transaction.
>>
>> This new command allows the transaction to proceed in case the object
>> does not exist.
>>
>> Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
>> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
>> Signed-off-by: Florian Westphal <fw@strlen.de>
>> ---
>>   include/uapi/linux/netfilter/nf_tables.h |  14 +++
>>   net/netfilter/nf_tables_api.c            | 111 +++++++++++++++++++++--
>>   2 files changed, 117 insertions(+), 8 deletions(-)
>>
>> diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
>> index cfa844da1ce6..ff677f3a6cad 100644
>> --- a/include/uapi/linux/netfilter/nf_tables.h
>> +++ b/include/uapi/linux/netfilter/nf_tables.h
>> @@ -98,6 +98,13 @@ enum nft_verdicts {
>>    * @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
>>    * @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
>>    * @NFT_MSG_GETRULE_RESET: get rules and reset stateful expressions (enum nft_obj_attributes)
>> + * @NFT_MSG_DESTROYTABLE: destroy a table (enum nft_table_attributes)
>> + * @NFT_MSG_DESTROYCHAIN: destroy a chain (enum nft_chain_attributes)
>> + * @NFT_MSG_DESTROYRULE: destroy a rule (enum nft_rule_attributes)
>> + * @NFT_MSG_DESTROYSET: destroy a set (enum nft_set_attributes)
>> + * @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes)
>> + * @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes)
>> + * @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes)
>>    */
>>   enum nf_tables_msg_types {
>>   	NFT_MSG_NEWTABLE,
>> @@ -126,6 +133,13 @@ enum nf_tables_msg_types {
>>   	NFT_MSG_GETFLOWTABLE,
>>   	NFT_MSG_DELFLOWTABLE,
>>   	NFT_MSG_GETRULE_RESET,
>> +	NFT_MSG_DESTROYTABLE,
>> +	NFT_MSG_DESTROYCHAIN,
>> +	NFT_MSG_DESTROYRULE,
>> +	NFT_MSG_DESTROYSET,
>> +	NFT_MSG_DESTROYSETELEM,
>> +	NFT_MSG_DESTROYOBJ,
>> +	NFT_MSG_DESTROYFLOWTABLE,
>>   	NFT_MSG_MAX,
>>   };
>>   
>> diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
>> index 8c09e4d12ac1..974b95dece1d 100644
>> --- a/net/netfilter/nf_tables_api.c
>> +++ b/net/netfilter/nf_tables_api.c
>> @@ -1401,6 +1401,10 @@ static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info,
>>   	}
>>   
>>   	if (IS_ERR(table)) {
>> +		if (PTR_ERR(table) == -ENOENT &&
>> +		    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYTABLE)
>> +			return 0;
>> +
>>   		NL_SET_BAD_ATTR(extack, attr);
>>   		return PTR_ERR(table);
>>   	}
>> @@ -2639,6 +2643,10 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
>>   		chain = nft_chain_lookup(net, table, attr, genmask);
>>   	}
>>   	if (IS_ERR(chain)) {
>> +		if (PTR_ERR(chain) == -ENOENT &&
>> +		    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYCHAIN)
>> +			return 0;
>> +
>>   		NL_SET_BAD_ATTR(extack, attr);
>>   		return PTR_ERR(chain);
>>   	}
>> @@ -3716,6 +3724,10 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
>>   		chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN],
>>   					 genmask);
>>   		if (IS_ERR(chain)) {
>> +			if (PTR_ERR(rule) == -ENOENT &&
> 
> Coverity complains that at this point rule is not initialized yet, which
> looks like to be the case to me.
> 

Thanks, I am sending a patch fixing this.

> [...]
>
Fernando F. Mancera Jan. 20, 2023, 10:06 a.m. UTC | #3
On 20/01/2023 10:58, Fernando F. Mancera wrote:
> Hi Vlad,
> 
> On 19/01/2023 08:29, Vlad Buslov wrote:
>> On Wed 18 Jan 2023 at 13:32, Florian Westphal <fw@strlen.de> wrote:
>>> From: Fernando Fernandez Mancera <ffmancera@riseup.net>
>>>
>>> Introduce NFT_MSG_DESTROY* message type. The destroy operation 
>>> performs a
>>> delete operation but ignoring the ENOENT errors.
>>>
>>> This is useful for the transaction semantics, where failing to delete an
>>> object which does not exist results in aborting the transaction.
>>>
>>> This new command allows the transaction to proceed in case the object
>>> does not exist.
>>>
>>> Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
>>> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
>>> Signed-off-by: Florian Westphal <fw@strlen.de>
>>> ---
>>>   include/uapi/linux/netfilter/nf_tables.h |  14 +++
>>>   net/netfilter/nf_tables_api.c            | 111 +++++++++++++++++++++--
>>>   2 files changed, 117 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/include/uapi/linux/netfilter/nf_tables.h 
>>> b/include/uapi/linux/netfilter/nf_tables.h
>>> index cfa844da1ce6..ff677f3a6cad 100644
>>> --- a/include/uapi/linux/netfilter/nf_tables.h
>>> +++ b/include/uapi/linux/netfilter/nf_tables.h
>>> @@ -98,6 +98,13 @@ enum nft_verdicts {
>>>    * @NFT_MSG_GETFLOWTABLE: get flow table (enum 
>>> nft_flowtable_attributes)
>>>    * @NFT_MSG_DELFLOWTABLE: delete flow table (enum 
>>> nft_flowtable_attributes)
>>>    * @NFT_MSG_GETRULE_RESET: get rules and reset stateful expressions 
>>> (enum nft_obj_attributes)
>>> + * @NFT_MSG_DESTROYTABLE: destroy a table (enum nft_table_attributes)
>>> + * @NFT_MSG_DESTROYCHAIN: destroy a chain (enum nft_chain_attributes)
>>> + * @NFT_MSG_DESTROYRULE: destroy a rule (enum nft_rule_attributes)
>>> + * @NFT_MSG_DESTROYSET: destroy a set (enum nft_set_attributes)
>>> + * @NFT_MSG_DESTROYSETELEM: destroy a set element (enum 
>>> nft_set_elem_attributes)
>>> + * @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum 
>>> nft_object_attributes)
>>> + * @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum 
>>> nft_flowtable_attributes)
>>>    */
>>>   enum nf_tables_msg_types {
>>>       NFT_MSG_NEWTABLE,
>>> @@ -126,6 +133,13 @@ enum nf_tables_msg_types {
>>>       NFT_MSG_GETFLOWTABLE,
>>>       NFT_MSG_DELFLOWTABLE,
>>>       NFT_MSG_GETRULE_RESET,
>>> +    NFT_MSG_DESTROYTABLE,
>>> +    NFT_MSG_DESTROYCHAIN,
>>> +    NFT_MSG_DESTROYRULE,
>>> +    NFT_MSG_DESTROYSET,
>>> +    NFT_MSG_DESTROYSETELEM,
>>> +    NFT_MSG_DESTROYOBJ,
>>> +    NFT_MSG_DESTROYFLOWTABLE,
>>>       NFT_MSG_MAX,
>>>   };
>>> diff --git a/net/netfilter/nf_tables_api.c 
>>> b/net/netfilter/nf_tables_api.c
>>> index 8c09e4d12ac1..974b95dece1d 100644
>>> --- a/net/netfilter/nf_tables_api.c
>>> +++ b/net/netfilter/nf_tables_api.c
>>> @@ -1401,6 +1401,10 @@ static int nf_tables_deltable(struct sk_buff 
>>> *skb, const struct nfnl_info *info,
>>>       }
>>>       if (IS_ERR(table)) {
>>> +        if (PTR_ERR(table) == -ENOENT &&
>>> +            NFNL_MSG_TYPE(info->nlh->nlmsg_type) == 
>>> NFT_MSG_DESTROYTABLE)
>>> +            return 0;
>>> +
>>>           NL_SET_BAD_ATTR(extack, attr);
>>>           return PTR_ERR(table);
>>>       }
>>> @@ -2639,6 +2643,10 @@ static int nf_tables_delchain(struct sk_buff 
>>> *skb, const struct nfnl_info *info,
>>>           chain = nft_chain_lookup(net, table, attr, genmask);
>>>       }
>>>       if (IS_ERR(chain)) {
>>> +        if (PTR_ERR(chain) == -ENOENT &&
>>> +            NFNL_MSG_TYPE(info->nlh->nlmsg_type) == 
>>> NFT_MSG_DESTROYCHAIN)
>>> +            return 0;
>>> +
>>>           NL_SET_BAD_ATTR(extack, attr);
>>>           return PTR_ERR(chain);
>>>       }
>>> @@ -3716,6 +3724,10 @@ static int nf_tables_delrule(struct sk_buff 
>>> *skb, const struct nfnl_info *info,
>>>           chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN],
>>>                        genmask);
>>>           if (IS_ERR(chain)) {
>>> +            if (PTR_ERR(rule) == -ENOENT &&
>>
>> Coverity complains that at this point rule is not initialized yet, which
>> looks like to be the case to me.
>>
> 
> Thanks, I am sending a patch fixing this.
> 
>> [...]
>>

There is already a patch sent by Yang Yingliang, 
https://lore.kernel.org/netfilter-devel/20230119075125.3598627-1-yangyingliang@huawei.com/T/#u
diff mbox series

Patch

diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index cfa844da1ce6..ff677f3a6cad 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -98,6 +98,13 @@  enum nft_verdicts {
  * @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
  * @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
  * @NFT_MSG_GETRULE_RESET: get rules and reset stateful expressions (enum nft_obj_attributes)
+ * @NFT_MSG_DESTROYTABLE: destroy a table (enum nft_table_attributes)
+ * @NFT_MSG_DESTROYCHAIN: destroy a chain (enum nft_chain_attributes)
+ * @NFT_MSG_DESTROYRULE: destroy a rule (enum nft_rule_attributes)
+ * @NFT_MSG_DESTROYSET: destroy a set (enum nft_set_attributes)
+ * @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes)
+ * @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes)
+ * @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes)
  */
 enum nf_tables_msg_types {
 	NFT_MSG_NEWTABLE,
@@ -126,6 +133,13 @@  enum nf_tables_msg_types {
 	NFT_MSG_GETFLOWTABLE,
 	NFT_MSG_DELFLOWTABLE,
 	NFT_MSG_GETRULE_RESET,
+	NFT_MSG_DESTROYTABLE,
+	NFT_MSG_DESTROYCHAIN,
+	NFT_MSG_DESTROYRULE,
+	NFT_MSG_DESTROYSET,
+	NFT_MSG_DESTROYSETELEM,
+	NFT_MSG_DESTROYOBJ,
+	NFT_MSG_DESTROYFLOWTABLE,
 	NFT_MSG_MAX,
 };
 
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 8c09e4d12ac1..974b95dece1d 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -1401,6 +1401,10 @@  static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info,
 	}
 
 	if (IS_ERR(table)) {
+		if (PTR_ERR(table) == -ENOENT &&
+		    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYTABLE)
+			return 0;
+
 		NL_SET_BAD_ATTR(extack, attr);
 		return PTR_ERR(table);
 	}
@@ -2639,6 +2643,10 @@  static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
 		chain = nft_chain_lookup(net, table, attr, genmask);
 	}
 	if (IS_ERR(chain)) {
+		if (PTR_ERR(chain) == -ENOENT &&
+		    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYCHAIN)
+			return 0;
+
 		NL_SET_BAD_ATTR(extack, attr);
 		return PTR_ERR(chain);
 	}
@@ -3716,6 +3724,10 @@  static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
 		chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN],
 					 genmask);
 		if (IS_ERR(chain)) {
+			if (PTR_ERR(rule) == -ENOENT &&
+			    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYRULE)
+				return 0;
+
 			NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
 			return PTR_ERR(chain);
 		}
@@ -3729,6 +3741,10 @@  static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
 		if (nla[NFTA_RULE_HANDLE]) {
 			rule = nft_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
 			if (IS_ERR(rule)) {
+				if (PTR_ERR(rule) == -ENOENT &&
+				    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYRULE)
+					return 0;
+
 				NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_HANDLE]);
 				return PTR_ERR(rule);
 			}
@@ -4808,6 +4824,10 @@  static int nf_tables_delset(struct sk_buff *skb, const struct nfnl_info *info,
 	}
 
 	if (IS_ERR(set)) {
+		if (PTR_ERR(set) == -ENOENT &&
+		    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSET)
+			return 0;
+
 		NL_SET_BAD_ATTR(extack, attr);
 		return PTR_ERR(set);
 	}
@@ -6690,6 +6710,10 @@  static int nf_tables_delsetelem(struct sk_buff *skb,
 
 	nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
 		err = nft_del_setelem(&ctx, set, attr);
+		if (err == -ENOENT &&
+		    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM)
+			continue;
+
 		if (err < 0) {
 			NL_SET_BAD_ATTR(extack, attr);
 			break;
@@ -7334,6 +7358,10 @@  static int nf_tables_delobj(struct sk_buff *skb, const struct nfnl_info *info,
 	}
 
 	if (IS_ERR(obj)) {
+		if (PTR_ERR(obj) == -ENOENT &&
+		    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYOBJ)
+			return 0;
+
 		NL_SET_BAD_ATTR(extack, attr);
 		return PTR_ERR(obj);
 	}
@@ -7964,6 +7992,10 @@  static int nf_tables_delflowtable(struct sk_buff *skb,
 	}
 
 	if (IS_ERR(flowtable)) {
+		if (PTR_ERR(flowtable) == -ENOENT &&
+		    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYFLOWTABLE)
+			return 0;
+
 		NL_SET_BAD_ATTR(extack, attr);
 		return PTR_ERR(flowtable);
 	}
@@ -8373,6 +8405,12 @@  static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
 		.attr_count	= NFTA_TABLE_MAX,
 		.policy		= nft_table_policy,
 	},
+	[NFT_MSG_DESTROYTABLE] = {
+		.call		= nf_tables_deltable,
+		.type		= NFNL_CB_BATCH,
+		.attr_count	= NFTA_TABLE_MAX,
+		.policy		= nft_table_policy,
+	},
 	[NFT_MSG_NEWCHAIN] = {
 		.call		= nf_tables_newchain,
 		.type		= NFNL_CB_BATCH,
@@ -8391,6 +8429,12 @@  static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
 		.attr_count	= NFTA_CHAIN_MAX,
 		.policy		= nft_chain_policy,
 	},
+	[NFT_MSG_DESTROYCHAIN] = {
+		.call		= nf_tables_delchain,
+		.type		= NFNL_CB_BATCH,
+		.attr_count	= NFTA_CHAIN_MAX,
+		.policy		= nft_chain_policy,
+	},
 	[NFT_MSG_NEWRULE] = {
 		.call		= nf_tables_newrule,
 		.type		= NFNL_CB_BATCH,
@@ -8415,6 +8459,12 @@  static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
 		.attr_count	= NFTA_RULE_MAX,
 		.policy		= nft_rule_policy,
 	},
+	[NFT_MSG_DESTROYRULE] = {
+		.call		= nf_tables_delrule,
+		.type		= NFNL_CB_BATCH,
+		.attr_count	= NFTA_RULE_MAX,
+		.policy		= nft_rule_policy,
+	},
 	[NFT_MSG_NEWSET] = {
 		.call		= nf_tables_newset,
 		.type		= NFNL_CB_BATCH,
@@ -8433,6 +8483,12 @@  static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
 		.attr_count	= NFTA_SET_MAX,
 		.policy		= nft_set_policy,
 	},
+	[NFT_MSG_DESTROYSET] = {
+		.call		= nf_tables_delset,
+		.type		= NFNL_CB_BATCH,
+		.attr_count	= NFTA_SET_MAX,
+		.policy		= nft_set_policy,
+	},
 	[NFT_MSG_NEWSETELEM] = {
 		.call		= nf_tables_newsetelem,
 		.type		= NFNL_CB_BATCH,
@@ -8451,6 +8507,12 @@  static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
 		.attr_count	= NFTA_SET_ELEM_LIST_MAX,
 		.policy		= nft_set_elem_list_policy,
 	},
+	[NFT_MSG_DESTROYSETELEM] = {
+		.call		= nf_tables_delsetelem,
+		.type		= NFNL_CB_BATCH,
+		.attr_count	= NFTA_SET_ELEM_LIST_MAX,
+		.policy		= nft_set_elem_list_policy,
+	},
 	[NFT_MSG_GETGEN] = {
 		.call		= nf_tables_getgen,
 		.type		= NFNL_CB_RCU,
@@ -8473,6 +8535,12 @@  static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
 		.attr_count	= NFTA_OBJ_MAX,
 		.policy		= nft_obj_policy,
 	},
+	[NFT_MSG_DESTROYOBJ] = {
+		.call		= nf_tables_delobj,
+		.type		= NFNL_CB_BATCH,
+		.attr_count	= NFTA_OBJ_MAX,
+		.policy		= nft_obj_policy,
+	},
 	[NFT_MSG_GETOBJ_RESET] = {
 		.call		= nf_tables_getobj,
 		.type		= NFNL_CB_RCU,
@@ -8497,6 +8565,12 @@  static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
 		.attr_count	= NFTA_FLOWTABLE_MAX,
 		.policy		= nft_flowtable_policy,
 	},
+	[NFT_MSG_DESTROYFLOWTABLE] = {
+		.call		= nf_tables_delflowtable,
+		.type		= NFNL_CB_BATCH,
+		.attr_count	= NFTA_FLOWTABLE_MAX,
+		.policy		= nft_flowtable_policy,
+	},
 };
 
 static int nf_tables_validate(struct net *net)
@@ -8590,6 +8664,7 @@  static void nft_commit_release(struct nft_trans *trans)
 {
 	switch (trans->msg_type) {
 	case NFT_MSG_DELTABLE:
+	case NFT_MSG_DESTROYTABLE:
 		nf_tables_table_destroy(&trans->ctx);
 		break;
 	case NFT_MSG_NEWCHAIN:
@@ -8597,23 +8672,29 @@  static void nft_commit_release(struct nft_trans *trans)
 		kfree(nft_trans_chain_name(trans));
 		break;
 	case NFT_MSG_DELCHAIN:
+	case NFT_MSG_DESTROYCHAIN:
 		nf_tables_chain_destroy(&trans->ctx);
 		break;
 	case NFT_MSG_DELRULE:
+	case NFT_MSG_DESTROYRULE:
 		nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
 		break;
 	case NFT_MSG_DELSET:
+	case NFT_MSG_DESTROYSET:
 		nft_set_destroy(&trans->ctx, nft_trans_set(trans));
 		break;
 	case NFT_MSG_DELSETELEM:
+	case NFT_MSG_DESTROYSETELEM:
 		nf_tables_set_elem_destroy(&trans->ctx,
 					   nft_trans_elem_set(trans),
 					   nft_trans_elem(trans).priv);
 		break;
 	case NFT_MSG_DELOBJ:
+	case NFT_MSG_DESTROYOBJ:
 		nft_obj_destroy(&trans->ctx, nft_trans_obj(trans));
 		break;
 	case NFT_MSG_DELFLOWTABLE:
+	case NFT_MSG_DESTROYFLOWTABLE:
 		if (nft_trans_flowtable_update(trans))
 			nft_flowtable_hooks_destroy(&nft_trans_flowtable_hooks(trans));
 		else
@@ -9065,8 +9146,9 @@  static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 			nft_trans_destroy(trans);
 			break;
 		case NFT_MSG_DELTABLE:
+		case NFT_MSG_DESTROYTABLE:
 			list_del_rcu(&trans->ctx.table->list);
-			nf_tables_table_notify(&trans->ctx, NFT_MSG_DELTABLE);
+			nf_tables_table_notify(&trans->ctx, trans->msg_type);
 			break;
 		case NFT_MSG_NEWCHAIN:
 			if (nft_trans_chain_update(trans)) {
@@ -9081,8 +9163,9 @@  static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 			}
 			break;
 		case NFT_MSG_DELCHAIN:
+		case NFT_MSG_DESTROYCHAIN:
 			nft_chain_del(trans->ctx.chain);
-			nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
+			nf_tables_chain_notify(&trans->ctx, trans->msg_type);
 			nf_tables_unregister_hook(trans->ctx.net,
 						  trans->ctx.table,
 						  trans->ctx.chain);
@@ -9098,10 +9181,11 @@  static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 			nft_trans_destroy(trans);
 			break;
 		case NFT_MSG_DELRULE:
+		case NFT_MSG_DESTROYRULE:
 			list_del_rcu(&nft_trans_rule(trans)->list);
 			nf_tables_rule_notify(&trans->ctx,
 					      nft_trans_rule(trans),
-					      NFT_MSG_DELRULE);
+					      trans->msg_type);
 			nft_rule_expr_deactivate(&trans->ctx,
 						 nft_trans_rule(trans),
 						 NFT_TRANS_COMMIT);
@@ -9129,9 +9213,10 @@  static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 			nft_trans_destroy(trans);
 			break;
 		case NFT_MSG_DELSET:
+		case NFT_MSG_DESTROYSET:
 			list_del_rcu(&nft_trans_set(trans)->list);
 			nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
-					     NFT_MSG_DELSET, GFP_KERNEL);
+					     trans->msg_type, GFP_KERNEL);
 			break;
 		case NFT_MSG_NEWSETELEM:
 			te = (struct nft_trans_elem *)trans->data;
@@ -9143,11 +9228,12 @@  static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 			nft_trans_destroy(trans);
 			break;
 		case NFT_MSG_DELSETELEM:
+		case NFT_MSG_DESTROYSETELEM:
 			te = (struct nft_trans_elem *)trans->data;
 
 			nf_tables_setelem_notify(&trans->ctx, te->set,
 						 &te->elem,
-						 NFT_MSG_DELSETELEM);
+						 trans->msg_type);
 			nft_setelem_remove(net, te->set, &te->elem);
 			if (!nft_setelem_is_catchall(te->set, &te->elem)) {
 				atomic_dec(&te->set->nelems);
@@ -9169,9 +9255,10 @@  static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 			}
 			break;
 		case NFT_MSG_DELOBJ:
+		case NFT_MSG_DESTROYOBJ:
 			nft_obj_del(nft_trans_obj(trans));
 			nf_tables_obj_notify(&trans->ctx, nft_trans_obj(trans),
-					     NFT_MSG_DELOBJ);
+					     trans->msg_type);
 			break;
 		case NFT_MSG_NEWFLOWTABLE:
 			if (nft_trans_flowtable_update(trans)) {
@@ -9193,11 +9280,12 @@  static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 			nft_trans_destroy(trans);
 			break;
 		case NFT_MSG_DELFLOWTABLE:
+		case NFT_MSG_DESTROYFLOWTABLE:
 			if (nft_trans_flowtable_update(trans)) {
 				nf_tables_flowtable_notify(&trans->ctx,
 							   nft_trans_flowtable(trans),
 							   &nft_trans_flowtable_hooks(trans),
-							   NFT_MSG_DELFLOWTABLE);
+							   trans->msg_type);
 				nft_unregister_flowtable_net_hooks(net,
 								   &nft_trans_flowtable_hooks(trans));
 			} else {
@@ -9205,7 +9293,7 @@  static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 				nf_tables_flowtable_notify(&trans->ctx,
 							   nft_trans_flowtable(trans),
 							   &nft_trans_flowtable(trans)->hook_list,
-							   NFT_MSG_DELFLOWTABLE);
+							   trans->msg_type);
 				nft_unregister_flowtable_net_hooks(net,
 						&nft_trans_flowtable(trans)->hook_list);
 			}
@@ -9301,6 +9389,7 @@  static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
 			}
 			break;
 		case NFT_MSG_DELTABLE:
+		case NFT_MSG_DESTROYTABLE:
 			nft_clear(trans->ctx.net, trans->ctx.table);
 			nft_trans_destroy(trans);
 			break;
@@ -9322,6 +9411,7 @@  static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
 			}
 			break;
 		case NFT_MSG_DELCHAIN:
+		case NFT_MSG_DESTROYCHAIN:
 			trans->ctx.table->use++;
 			nft_clear(trans->ctx.net, trans->ctx.chain);
 			nft_trans_destroy(trans);
@@ -9336,6 +9426,7 @@  static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
 				nft_flow_rule_destroy(nft_trans_flow_rule(trans));
 			break;
 		case NFT_MSG_DELRULE:
+		case NFT_MSG_DESTROYRULE:
 			trans->ctx.chain->use++;
 			nft_clear(trans->ctx.net, nft_trans_rule(trans));
 			nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
@@ -9357,6 +9448,7 @@  static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
 			list_del_rcu(&nft_trans_set(trans)->list);
 			break;
 		case NFT_MSG_DELSET:
+		case NFT_MSG_DESTROYSET:
 			trans->ctx.table->use++;
 			nft_clear(trans->ctx.net, nft_trans_set(trans));
 			nft_trans_destroy(trans);
@@ -9372,6 +9464,7 @@  static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
 				atomic_dec(&te->set->nelems);
 			break;
 		case NFT_MSG_DELSETELEM:
+		case NFT_MSG_DESTROYSETELEM:
 			te = (struct nft_trans_elem *)trans->data;
 
 			nft_setelem_data_activate(net, te->set, &te->elem);
@@ -9391,6 +9484,7 @@  static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
 			}
 			break;
 		case NFT_MSG_DELOBJ:
+		case NFT_MSG_DESTROYOBJ:
 			trans->ctx.table->use++;
 			nft_clear(trans->ctx.net, nft_trans_obj(trans));
 			nft_trans_destroy(trans);
@@ -9407,6 +9501,7 @@  static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
 			}
 			break;
 		case NFT_MSG_DELFLOWTABLE:
+		case NFT_MSG_DESTROYFLOWTABLE:
 			if (nft_trans_flowtable_update(trans)) {
 				list_splice(&nft_trans_flowtable_hooks(trans),
 					    &nft_trans_flowtable(trans)->hook_list);