Skip to content

Commit f80a612

Browse files
ffmanceraFlorian Westphal
authored andcommitted
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 <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]> Signed-off-by: Florian Westphal <[email protected]>
1 parent d9e7891 commit f80a612

File tree

2 files changed

+117
-8
lines changed

2 files changed

+117
-8
lines changed

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ enum nft_verdicts {
9898
* @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
9999
* @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
100100
* @NFT_MSG_GETRULE_RESET: get rules and reset stateful expressions (enum nft_obj_attributes)
101+
* @NFT_MSG_DESTROYTABLE: destroy a table (enum nft_table_attributes)
102+
* @NFT_MSG_DESTROYCHAIN: destroy a chain (enum nft_chain_attributes)
103+
* @NFT_MSG_DESTROYRULE: destroy a rule (enum nft_rule_attributes)
104+
* @NFT_MSG_DESTROYSET: destroy a set (enum nft_set_attributes)
105+
* @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes)
106+
* @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes)
107+
* @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes)
101108
*/
102109
enum nf_tables_msg_types {
103110
NFT_MSG_NEWTABLE,
@@ -126,6 +133,13 @@ enum nf_tables_msg_types {
126133
NFT_MSG_GETFLOWTABLE,
127134
NFT_MSG_DELFLOWTABLE,
128135
NFT_MSG_GETRULE_RESET,
136+
NFT_MSG_DESTROYTABLE,
137+
NFT_MSG_DESTROYCHAIN,
138+
NFT_MSG_DESTROYRULE,
139+
NFT_MSG_DESTROYSET,
140+
NFT_MSG_DESTROYSETELEM,
141+
NFT_MSG_DESTROYOBJ,
142+
NFT_MSG_DESTROYFLOWTABLE,
129143
NFT_MSG_MAX,
130144
};
131145

net/netfilter/nf_tables_api.c

Lines changed: 103 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,10 @@ static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info,
14011401
}
14021402

14031403
if (IS_ERR(table)) {
1404+
if (PTR_ERR(table) == -ENOENT &&
1405+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYTABLE)
1406+
return 0;
1407+
14041408
NL_SET_BAD_ATTR(extack, attr);
14051409
return PTR_ERR(table);
14061410
}
@@ -2639,6 +2643,10 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
26392643
chain = nft_chain_lookup(net, table, attr, genmask);
26402644
}
26412645
if (IS_ERR(chain)) {
2646+
if (PTR_ERR(chain) == -ENOENT &&
2647+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYCHAIN)
2648+
return 0;
2649+
26422650
NL_SET_BAD_ATTR(extack, attr);
26432651
return PTR_ERR(chain);
26442652
}
@@ -3716,6 +3724,10 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
37163724
chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN],
37173725
genmask);
37183726
if (IS_ERR(chain)) {
3727+
if (PTR_ERR(rule) == -ENOENT &&
3728+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYRULE)
3729+
return 0;
3730+
37193731
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
37203732
return PTR_ERR(chain);
37213733
}
@@ -3729,6 +3741,10 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
37293741
if (nla[NFTA_RULE_HANDLE]) {
37303742
rule = nft_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
37313743
if (IS_ERR(rule)) {
3744+
if (PTR_ERR(rule) == -ENOENT &&
3745+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYRULE)
3746+
return 0;
3747+
37323748
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_HANDLE]);
37333749
return PTR_ERR(rule);
37343750
}
@@ -4808,6 +4824,10 @@ static int nf_tables_delset(struct sk_buff *skb, const struct nfnl_info *info,
48084824
}
48094825

48104826
if (IS_ERR(set)) {
4827+
if (PTR_ERR(set) == -ENOENT &&
4828+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSET)
4829+
return 0;
4830+
48114831
NL_SET_BAD_ATTR(extack, attr);
48124832
return PTR_ERR(set);
48134833
}
@@ -6690,6 +6710,10 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
66906710

66916711
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
66926712
err = nft_del_setelem(&ctx, set, attr);
6713+
if (err == -ENOENT &&
6714+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM)
6715+
continue;
6716+
66936717
if (err < 0) {
66946718
NL_SET_BAD_ATTR(extack, attr);
66956719
break;
@@ -7334,6 +7358,10 @@ static int nf_tables_delobj(struct sk_buff *skb, const struct nfnl_info *info,
73347358
}
73357359

73367360
if (IS_ERR(obj)) {
7361+
if (PTR_ERR(obj) == -ENOENT &&
7362+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYOBJ)
7363+
return 0;
7364+
73377365
NL_SET_BAD_ATTR(extack, attr);
73387366
return PTR_ERR(obj);
73397367
}
@@ -7964,6 +7992,10 @@ static int nf_tables_delflowtable(struct sk_buff *skb,
79647992
}
79657993

79667994
if (IS_ERR(flowtable)) {
7995+
if (PTR_ERR(flowtable) == -ENOENT &&
7996+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYFLOWTABLE)
7997+
return 0;
7998+
79677999
NL_SET_BAD_ATTR(extack, attr);
79688000
return PTR_ERR(flowtable);
79698001
}
@@ -8373,6 +8405,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
83738405
.attr_count = NFTA_TABLE_MAX,
83748406
.policy = nft_table_policy,
83758407
},
8408+
[NFT_MSG_DESTROYTABLE] = {
8409+
.call = nf_tables_deltable,
8410+
.type = NFNL_CB_BATCH,
8411+
.attr_count = NFTA_TABLE_MAX,
8412+
.policy = nft_table_policy,
8413+
},
83768414
[NFT_MSG_NEWCHAIN] = {
83778415
.call = nf_tables_newchain,
83788416
.type = NFNL_CB_BATCH,
@@ -8391,6 +8429,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
83918429
.attr_count = NFTA_CHAIN_MAX,
83928430
.policy = nft_chain_policy,
83938431
},
8432+
[NFT_MSG_DESTROYCHAIN] = {
8433+
.call = nf_tables_delchain,
8434+
.type = NFNL_CB_BATCH,
8435+
.attr_count = NFTA_CHAIN_MAX,
8436+
.policy = nft_chain_policy,
8437+
},
83948438
[NFT_MSG_NEWRULE] = {
83958439
.call = nf_tables_newrule,
83968440
.type = NFNL_CB_BATCH,
@@ -8415,6 +8459,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
84158459
.attr_count = NFTA_RULE_MAX,
84168460
.policy = nft_rule_policy,
84178461
},
8462+
[NFT_MSG_DESTROYRULE] = {
8463+
.call = nf_tables_delrule,
8464+
.type = NFNL_CB_BATCH,
8465+
.attr_count = NFTA_RULE_MAX,
8466+
.policy = nft_rule_policy,
8467+
},
84188468
[NFT_MSG_NEWSET] = {
84198469
.call = nf_tables_newset,
84208470
.type = NFNL_CB_BATCH,
@@ -8433,6 +8483,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
84338483
.attr_count = NFTA_SET_MAX,
84348484
.policy = nft_set_policy,
84358485
},
8486+
[NFT_MSG_DESTROYSET] = {
8487+
.call = nf_tables_delset,
8488+
.type = NFNL_CB_BATCH,
8489+
.attr_count = NFTA_SET_MAX,
8490+
.policy = nft_set_policy,
8491+
},
84368492
[NFT_MSG_NEWSETELEM] = {
84378493
.call = nf_tables_newsetelem,
84388494
.type = NFNL_CB_BATCH,
@@ -8451,6 +8507,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
84518507
.attr_count = NFTA_SET_ELEM_LIST_MAX,
84528508
.policy = nft_set_elem_list_policy,
84538509
},
8510+
[NFT_MSG_DESTROYSETELEM] = {
8511+
.call = nf_tables_delsetelem,
8512+
.type = NFNL_CB_BATCH,
8513+
.attr_count = NFTA_SET_ELEM_LIST_MAX,
8514+
.policy = nft_set_elem_list_policy,
8515+
},
84548516
[NFT_MSG_GETGEN] = {
84558517
.call = nf_tables_getgen,
84568518
.type = NFNL_CB_RCU,
@@ -8473,6 +8535,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
84738535
.attr_count = NFTA_OBJ_MAX,
84748536
.policy = nft_obj_policy,
84758537
},
8538+
[NFT_MSG_DESTROYOBJ] = {
8539+
.call = nf_tables_delobj,
8540+
.type = NFNL_CB_BATCH,
8541+
.attr_count = NFTA_OBJ_MAX,
8542+
.policy = nft_obj_policy,
8543+
},
84768544
[NFT_MSG_GETOBJ_RESET] = {
84778545
.call = nf_tables_getobj,
84788546
.type = NFNL_CB_RCU,
@@ -8497,6 +8565,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
84978565
.attr_count = NFTA_FLOWTABLE_MAX,
84988566
.policy = nft_flowtable_policy,
84998567
},
8568+
[NFT_MSG_DESTROYFLOWTABLE] = {
8569+
.call = nf_tables_delflowtable,
8570+
.type = NFNL_CB_BATCH,
8571+
.attr_count = NFTA_FLOWTABLE_MAX,
8572+
.policy = nft_flowtable_policy,
8573+
},
85008574
};
85018575

85028576
static int nf_tables_validate(struct net *net)
@@ -8590,30 +8664,37 @@ static void nft_commit_release(struct nft_trans *trans)
85908664
{
85918665
switch (trans->msg_type) {
85928666
case NFT_MSG_DELTABLE:
8667+
case NFT_MSG_DESTROYTABLE:
85938668
nf_tables_table_destroy(&trans->ctx);
85948669
break;
85958670
case NFT_MSG_NEWCHAIN:
85968671
free_percpu(nft_trans_chain_stats(trans));
85978672
kfree(nft_trans_chain_name(trans));
85988673
break;
85998674
case NFT_MSG_DELCHAIN:
8675+
case NFT_MSG_DESTROYCHAIN:
86008676
nf_tables_chain_destroy(&trans->ctx);
86018677
break;
86028678
case NFT_MSG_DELRULE:
8679+
case NFT_MSG_DESTROYRULE:
86038680
nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
86048681
break;
86058682
case NFT_MSG_DELSET:
8683+
case NFT_MSG_DESTROYSET:
86068684
nft_set_destroy(&trans->ctx, nft_trans_set(trans));
86078685
break;
86088686
case NFT_MSG_DELSETELEM:
8687+
case NFT_MSG_DESTROYSETELEM:
86098688
nf_tables_set_elem_destroy(&trans->ctx,
86108689
nft_trans_elem_set(trans),
86118690
nft_trans_elem(trans).priv);
86128691
break;
86138692
case NFT_MSG_DELOBJ:
8693+
case NFT_MSG_DESTROYOBJ:
86148694
nft_obj_destroy(&trans->ctx, nft_trans_obj(trans));
86158695
break;
86168696
case NFT_MSG_DELFLOWTABLE:
8697+
case NFT_MSG_DESTROYFLOWTABLE:
86178698
if (nft_trans_flowtable_update(trans))
86188699
nft_flowtable_hooks_destroy(&nft_trans_flowtable_hooks(trans));
86198700
else
@@ -9065,8 +9146,9 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
90659146
nft_trans_destroy(trans);
90669147
break;
90679148
case NFT_MSG_DELTABLE:
9149+
case NFT_MSG_DESTROYTABLE:
90689150
list_del_rcu(&trans->ctx.table->list);
9069-
nf_tables_table_notify(&trans->ctx, NFT_MSG_DELTABLE);
9151+
nf_tables_table_notify(&trans->ctx, trans->msg_type);
90709152
break;
90719153
case NFT_MSG_NEWCHAIN:
90729154
if (nft_trans_chain_update(trans)) {
@@ -9081,8 +9163,9 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
90819163
}
90829164
break;
90839165
case NFT_MSG_DELCHAIN:
9166+
case NFT_MSG_DESTROYCHAIN:
90849167
nft_chain_del(trans->ctx.chain);
9085-
nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
9168+
nf_tables_chain_notify(&trans->ctx, trans->msg_type);
90869169
nf_tables_unregister_hook(trans->ctx.net,
90879170
trans->ctx.table,
90889171
trans->ctx.chain);
@@ -9098,10 +9181,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
90989181
nft_trans_destroy(trans);
90999182
break;
91009183
case NFT_MSG_DELRULE:
9184+
case NFT_MSG_DESTROYRULE:
91019185
list_del_rcu(&nft_trans_rule(trans)->list);
91029186
nf_tables_rule_notify(&trans->ctx,
91039187
nft_trans_rule(trans),
9104-
NFT_MSG_DELRULE);
9188+
trans->msg_type);
91059189
nft_rule_expr_deactivate(&trans->ctx,
91069190
nft_trans_rule(trans),
91079191
NFT_TRANS_COMMIT);
@@ -9129,9 +9213,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
91299213
nft_trans_destroy(trans);
91309214
break;
91319215
case NFT_MSG_DELSET:
9216+
case NFT_MSG_DESTROYSET:
91329217
list_del_rcu(&nft_trans_set(trans)->list);
91339218
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
9134-
NFT_MSG_DELSET, GFP_KERNEL);
9219+
trans->msg_type, GFP_KERNEL);
91359220
break;
91369221
case NFT_MSG_NEWSETELEM:
91379222
te = (struct nft_trans_elem *)trans->data;
@@ -9143,11 +9228,12 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
91439228
nft_trans_destroy(trans);
91449229
break;
91459230
case NFT_MSG_DELSETELEM:
9231+
case NFT_MSG_DESTROYSETELEM:
91469232
te = (struct nft_trans_elem *)trans->data;
91479233

91489234
nf_tables_setelem_notify(&trans->ctx, te->set,
91499235
&te->elem,
9150-
NFT_MSG_DELSETELEM);
9236+
trans->msg_type);
91519237
nft_setelem_remove(net, te->set, &te->elem);
91529238
if (!nft_setelem_is_catchall(te->set, &te->elem)) {
91539239
atomic_dec(&te->set->nelems);
@@ -9169,9 +9255,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
91699255
}
91709256
break;
91719257
case NFT_MSG_DELOBJ:
9258+
case NFT_MSG_DESTROYOBJ:
91729259
nft_obj_del(nft_trans_obj(trans));
91739260
nf_tables_obj_notify(&trans->ctx, nft_trans_obj(trans),
9174-
NFT_MSG_DELOBJ);
9261+
trans->msg_type);
91759262
break;
91769263
case NFT_MSG_NEWFLOWTABLE:
91779264
if (nft_trans_flowtable_update(trans)) {
@@ -9193,19 +9280,20 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
91939280
nft_trans_destroy(trans);
91949281
break;
91959282
case NFT_MSG_DELFLOWTABLE:
9283+
case NFT_MSG_DESTROYFLOWTABLE:
91969284
if (nft_trans_flowtable_update(trans)) {
91979285
nf_tables_flowtable_notify(&trans->ctx,
91989286
nft_trans_flowtable(trans),
91999287
&nft_trans_flowtable_hooks(trans),
9200-
NFT_MSG_DELFLOWTABLE);
9288+
trans->msg_type);
92019289
nft_unregister_flowtable_net_hooks(net,
92029290
&nft_trans_flowtable_hooks(trans));
92039291
} else {
92049292
list_del_rcu(&nft_trans_flowtable(trans)->list);
92059293
nf_tables_flowtable_notify(&trans->ctx,
92069294
nft_trans_flowtable(trans),
92079295
&nft_trans_flowtable(trans)->hook_list,
9208-
NFT_MSG_DELFLOWTABLE);
9296+
trans->msg_type);
92099297
nft_unregister_flowtable_net_hooks(net,
92109298
&nft_trans_flowtable(trans)->hook_list);
92119299
}
@@ -9301,6 +9389,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
93019389
}
93029390
break;
93039391
case NFT_MSG_DELTABLE:
9392+
case NFT_MSG_DESTROYTABLE:
93049393
nft_clear(trans->ctx.net, trans->ctx.table);
93059394
nft_trans_destroy(trans);
93069395
break;
@@ -9322,6 +9411,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
93229411
}
93239412
break;
93249413
case NFT_MSG_DELCHAIN:
9414+
case NFT_MSG_DESTROYCHAIN:
93259415
trans->ctx.table->use++;
93269416
nft_clear(trans->ctx.net, trans->ctx.chain);
93279417
nft_trans_destroy(trans);
@@ -9336,6 +9426,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
93369426
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
93379427
break;
93389428
case NFT_MSG_DELRULE:
9429+
case NFT_MSG_DESTROYRULE:
93399430
trans->ctx.chain->use++;
93409431
nft_clear(trans->ctx.net, nft_trans_rule(trans));
93419432
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)
93579448
list_del_rcu(&nft_trans_set(trans)->list);
93589449
break;
93599450
case NFT_MSG_DELSET:
9451+
case NFT_MSG_DESTROYSET:
93609452
trans->ctx.table->use++;
93619453
nft_clear(trans->ctx.net, nft_trans_set(trans));
93629454
nft_trans_destroy(trans);
@@ -9372,6 +9464,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
93729464
atomic_dec(&te->set->nelems);
93739465
break;
93749466
case NFT_MSG_DELSETELEM:
9467+
case NFT_MSG_DESTROYSETELEM:
93759468
te = (struct nft_trans_elem *)trans->data;
93769469

93779470
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)
93919484
}
93929485
break;
93939486
case NFT_MSG_DELOBJ:
9487+
case NFT_MSG_DESTROYOBJ:
93949488
trans->ctx.table->use++;
93959489
nft_clear(trans->ctx.net, nft_trans_obj(trans));
93969490
nft_trans_destroy(trans);
@@ -9407,6 +9501,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
94079501
}
94089502
break;
94099503
case NFT_MSG_DELFLOWTABLE:
9504+
case NFT_MSG_DESTROYFLOWTABLE:
94109505
if (nft_trans_flowtable_update(trans)) {
94119506
list_splice(&nft_trans_flowtable_hooks(trans),
94129507
&nft_trans_flowtable(trans)->hook_list);

0 commit comments

Comments
 (0)