aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2014-05-23 06:39:26 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2014-06-02 04:54:35 -0400
commit4fefee570d8e35d950e6b7294618e2035e669308 (patch)
tree6fb7445e5ec3f6caf139515c4d2f48ca56078c88 /net
parent7632667d26a99d3b33ec8dd522c4086653ff9388 (diff)
netfilter: nf_tables: allow to delete several objects from a batch
Three changes to allow the deletion of several objects with dependencies in one transaction, they are: 1) Introduce speculative counter increment/decrement that is undone in the abort path if required, thus we avoid hitting -EBUSY when deleting the chain. The counter updates are reverted in the abort path. 2) Increment/decrement table/chain use counter for each set/rule. We need this to fully rely on the use counters instead of the list content, eg. !list_empty(&chain->rules) which evaluate true in the middle of the transaction. 3) Decrement table use counter when an anonymous set is bound to the rule in the commit path. This avoids hitting -EBUSY when deleting the table that contains anonymous sets. The anonymous sets are released in the nf_tables_rule_destroy path. This should not be a problem since the rule already bumped the use counter of the chain, so the bound anonymous set reflects dependencies through the rule object, which already increases the chain use counter. So the general assumption after this patch is that the use counters are bumped by direct object dependencies. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nf_tables_api.c40
1 files changed, 31 insertions, 9 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 4fffa3680d42..dbf823634669 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -538,8 +538,7 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
538 return PTR_ERR(table); 538 return PTR_ERR(table);
539 if (table->flags & NFT_TABLE_INACTIVE) 539 if (table->flags & NFT_TABLE_INACTIVE)
540 return -ENOENT; 540 return -ENOENT;
541 541 if (table->use > 0)
542 if (!list_empty(&table->chains) || !list_empty(&table->sets))
543 return -EBUSY; 542 return -EBUSY;
544 543
545 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla); 544 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
@@ -553,6 +552,8 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
553 552
554static void nf_tables_table_destroy(struct nft_ctx *ctx) 553static void nf_tables_table_destroy(struct nft_ctx *ctx)
555{ 554{
555 BUG_ON(ctx->table->use > 0);
556
556 kfree(ctx->table); 557 kfree(ctx->table);
557 module_put(ctx->afi->owner); 558 module_put(ctx->afi->owner);
558} 559}
@@ -1128,6 +1129,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
1128 if (err < 0) 1129 if (err < 0)
1129 goto err2; 1130 goto err2;
1130 1131
1132 table->use++;
1131 list_add_tail(&chain->list, &table->chains); 1133 list_add_tail(&chain->list, &table->chains);
1132 return 0; 1134 return 0;
1133err2: 1135err2:
@@ -1169,7 +1171,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
1169 return PTR_ERR(chain); 1171 return PTR_ERR(chain);
1170 if (chain->flags & NFT_CHAIN_INACTIVE) 1172 if (chain->flags & NFT_CHAIN_INACTIVE)
1171 return -ENOENT; 1173 return -ENOENT;
1172 if (!list_empty(&chain->rules) || chain->use > 0) 1174 if (chain->use > 0)
1173 return -EBUSY; 1175 return -EBUSY;
1174 1176
1175 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla); 1177 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
@@ -1177,6 +1179,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
1177 if (err < 0) 1179 if (err < 0)
1178 return err; 1180 return err;
1179 1181
1182 table->use--;
1180 list_del(&chain->list); 1183 list_del(&chain->list);
1181 return 0; 1184 return 0;
1182} 1185}
@@ -1814,6 +1817,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
1814 err = -ENOMEM; 1817 err = -ENOMEM;
1815 goto err3; 1818 goto err3;
1816 } 1819 }
1820 chain->use++;
1817 return 0; 1821 return 0;
1818 1822
1819err3: 1823err3:
@@ -1841,6 +1845,7 @@ nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule)
1841 if (nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule) == NULL) 1845 if (nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule) == NULL)
1842 return -ENOMEM; 1846 return -ENOMEM;
1843 nft_rule_disactivate_next(ctx->net, rule); 1847 nft_rule_disactivate_next(ctx->net, rule);
1848 ctx->chain->use--;
1844 return 0; 1849 return 0;
1845 } 1850 }
1846 return -ENOENT; 1851 return -ENOENT;
@@ -2588,6 +2593,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
2588 goto err2; 2593 goto err2;
2589 2594
2590 list_add_tail(&set->list, &table->sets); 2595 list_add_tail(&set->list, &table->sets);
2596 table->use++;
2591 return 0; 2597 return 0;
2592 2598
2593err2: 2599err2:
@@ -2642,6 +2648,7 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
2642 return err; 2648 return err;
2643 2649
2644 list_del(&set->list); 2650 list_del(&set->list);
2651 ctx.table->use--;
2645 return 0; 2652 return 0;
2646} 2653}
2647 2654
@@ -3122,6 +3129,8 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
3122 err = nft_add_set_elem(&ctx, set, attr); 3129 err = nft_add_set_elem(&ctx, set, attr);
3123 if (err < 0) 3130 if (err < 0)
3124 break; 3131 break;
3132
3133 set->nelems++;
3125 } 3134 }
3126 return err; 3135 return err;
3127} 3136}
@@ -3196,6 +3205,8 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
3196 err = nft_del_setelem(&ctx, set, attr); 3205 err = nft_del_setelem(&ctx, set, attr);
3197 if (err < 0) 3206 if (err < 0)
3198 break; 3207 break;
3208
3209 set->nelems--;
3199 } 3210 }
3200 return err; 3211 return err;
3201} 3212}
@@ -3361,15 +3372,13 @@ static int nf_tables_commit(struct sk_buff *skb)
3361 case NFT_MSG_NEWCHAIN: 3372 case NFT_MSG_NEWCHAIN:
3362 if (nft_trans_chain_update(trans)) 3373 if (nft_trans_chain_update(trans))
3363 nft_chain_commit_update(trans); 3374 nft_chain_commit_update(trans);
3364 else { 3375 else
3365 trans->ctx.chain->flags &= ~NFT_CHAIN_INACTIVE; 3376 trans->ctx.chain->flags &= ~NFT_CHAIN_INACTIVE;
3366 trans->ctx.table->use++; 3377
3367 }
3368 nf_tables_chain_notify(&trans->ctx, NFT_MSG_NEWCHAIN); 3378 nf_tables_chain_notify(&trans->ctx, NFT_MSG_NEWCHAIN);
3369 nft_trans_destroy(trans); 3379 nft_trans_destroy(trans);
3370 break; 3380 break;
3371 case NFT_MSG_DELCHAIN: 3381 case NFT_MSG_DELCHAIN:
3372 trans->ctx.table->use--;
3373 nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN); 3382 nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
3374 if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && 3383 if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) &&
3375 trans->ctx.chain->flags & NFT_BASE_CHAIN) { 3384 trans->ctx.chain->flags & NFT_BASE_CHAIN) {
@@ -3392,6 +3401,13 @@ static int nf_tables_commit(struct sk_buff *skb)
3392 break; 3401 break;
3393 case NFT_MSG_NEWSET: 3402 case NFT_MSG_NEWSET:
3394 nft_trans_set(trans)->flags &= ~NFT_SET_INACTIVE; 3403 nft_trans_set(trans)->flags &= ~NFT_SET_INACTIVE;
3404 /* This avoids hitting -EBUSY when deleting the table
3405 * from the transaction.
3406 */
3407 if (nft_trans_set(trans)->flags & NFT_SET_ANONYMOUS &&
3408 !list_empty(&nft_trans_set(trans)->bindings))
3409 trans->ctx.table->use--;
3410
3395 nf_tables_set_notify(&trans->ctx, nft_trans_set(trans), 3411 nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
3396 NFT_MSG_NEWSET); 3412 NFT_MSG_NEWSET);
3397 nft_trans_destroy(trans); 3413 nft_trans_destroy(trans);
@@ -3401,7 +3417,6 @@ static int nf_tables_commit(struct sk_buff *skb)
3401 NFT_MSG_DELSET); 3417 NFT_MSG_DELSET);
3402 break; 3418 break;
3403 case NFT_MSG_NEWSETELEM: 3419 case NFT_MSG_NEWSETELEM:
3404 nft_trans_elem_set(trans)->nelems++;
3405 nf_tables_setelem_notify(&trans->ctx, 3420 nf_tables_setelem_notify(&trans->ctx,
3406 nft_trans_elem_set(trans), 3421 nft_trans_elem_set(trans),
3407 &nft_trans_elem(trans), 3422 &nft_trans_elem(trans),
@@ -3409,7 +3424,6 @@ static int nf_tables_commit(struct sk_buff *skb)
3409 nft_trans_destroy(trans); 3424 nft_trans_destroy(trans);
3410 break; 3425 break;
3411 case NFT_MSG_DELSETELEM: 3426 case NFT_MSG_DELSETELEM:
3412 nft_trans_elem_set(trans)->nelems--;
3413 nf_tables_setelem_notify(&trans->ctx, 3427 nf_tables_setelem_notify(&trans->ctx,
3414 nft_trans_elem_set(trans), 3428 nft_trans_elem_set(trans),
3415 &nft_trans_elem(trans), 3429 &nft_trans_elem(trans),
@@ -3487,6 +3501,7 @@ static int nf_tables_abort(struct sk_buff *skb)
3487 3501
3488 nft_trans_destroy(trans); 3502 nft_trans_destroy(trans);
3489 } else { 3503 } else {
3504 trans->ctx.table->use--;
3490 list_del(&trans->ctx.chain->list); 3505 list_del(&trans->ctx.chain->list);
3491 if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && 3506 if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) &&
3492 trans->ctx.chain->flags & NFT_BASE_CHAIN) { 3507 trans->ctx.chain->flags & NFT_BASE_CHAIN) {
@@ -3496,32 +3511,39 @@ static int nf_tables_abort(struct sk_buff *skb)
3496 } 3511 }
3497 break; 3512 break;
3498 case NFT_MSG_DELCHAIN: 3513 case NFT_MSG_DELCHAIN:
3514 trans->ctx.table->use++;
3499 list_add_tail(&trans->ctx.chain->list, 3515 list_add_tail(&trans->ctx.chain->list,
3500 &trans->ctx.table->chains); 3516 &trans->ctx.table->chains);
3501 nft_trans_destroy(trans); 3517 nft_trans_destroy(trans);
3502 break; 3518 break;
3503 case NFT_MSG_NEWRULE: 3519 case NFT_MSG_NEWRULE:
3520 trans->ctx.chain->use--;
3504 list_del_rcu(&nft_trans_rule(trans)->list); 3521 list_del_rcu(&nft_trans_rule(trans)->list);
3505 break; 3522 break;
3506 case NFT_MSG_DELRULE: 3523 case NFT_MSG_DELRULE:
3524 trans->ctx.chain->use++;
3507 nft_rule_clear(trans->ctx.net, nft_trans_rule(trans)); 3525 nft_rule_clear(trans->ctx.net, nft_trans_rule(trans));
3508 nft_trans_destroy(trans); 3526 nft_trans_destroy(trans);
3509 break; 3527 break;
3510 case NFT_MSG_NEWSET: 3528 case NFT_MSG_NEWSET:
3529 trans->ctx.table->use--;
3511 list_del(&nft_trans_set(trans)->list); 3530 list_del(&nft_trans_set(trans)->list);
3512 break; 3531 break;
3513 case NFT_MSG_DELSET: 3532 case NFT_MSG_DELSET:
3533 trans->ctx.table->use++;
3514 list_add_tail(&nft_trans_set(trans)->list, 3534 list_add_tail(&nft_trans_set(trans)->list,
3515 &trans->ctx.table->sets); 3535 &trans->ctx.table->sets);
3516 nft_trans_destroy(trans); 3536 nft_trans_destroy(trans);
3517 break; 3537 break;
3518 case NFT_MSG_NEWSETELEM: 3538 case NFT_MSG_NEWSETELEM:
3539 nft_trans_elem_set(trans)->nelems--;
3519 set = nft_trans_elem_set(trans); 3540 set = nft_trans_elem_set(trans);
3520 set->ops->get(set, &nft_trans_elem(trans)); 3541 set->ops->get(set, &nft_trans_elem(trans));
3521 set->ops->remove(set, &nft_trans_elem(trans)); 3542 set->ops->remove(set, &nft_trans_elem(trans));
3522 nft_trans_destroy(trans); 3543 nft_trans_destroy(trans);
3523 break; 3544 break;
3524 case NFT_MSG_DELSETELEM: 3545 case NFT_MSG_DELSETELEM:
3546 nft_trans_elem_set(trans)->nelems++;
3525 nft_trans_destroy(trans); 3547 nft_trans_destroy(trans);
3526 break; 3548 break;
3527 } 3549 }