netfilter: nf_tables: add support to destroy operation
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>
This commit is contained in:
parent
d9e7891476
commit
f80a612dd7
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue