@@ -1646,7 +1646,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
1646
1646
NFTA_CHAIN_PAD ))
1647
1647
goto nla_put_failure ;
1648
1648
1649
- if (event == NFT_MSG_DELCHAIN ) {
1649
+ if (event == NFT_MSG_DELCHAIN && ! hook_list ) {
1650
1650
nlmsg_end (skb , nlh );
1651
1651
return 0 ;
1652
1652
}
@@ -2667,6 +2667,59 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
2667
2667
return nf_tables_addchain (& ctx , family , genmask , policy , flags , extack );
2668
2668
}
2669
2669
2670
+ static int nft_delchain_hook (struct nft_ctx * ctx , struct nft_chain * chain ,
2671
+ struct netlink_ext_ack * extack )
2672
+ {
2673
+ const struct nlattr * const * nla = ctx -> nla ;
2674
+ struct nft_chain_hook chain_hook = {};
2675
+ struct nft_base_chain * basechain ;
2676
+ struct nft_hook * this , * hook ;
2677
+ LIST_HEAD (chain_del_list );
2678
+ struct nft_trans * trans ;
2679
+ int err ;
2680
+
2681
+ if (!nft_is_base_chain (chain ))
2682
+ return - EOPNOTSUPP ;
2683
+
2684
+ basechain = nft_base_chain (chain );
2685
+ err = nft_chain_parse_hook (ctx -> net , basechain , nla , & chain_hook ,
2686
+ ctx -> family , extack );
2687
+ if (err < 0 )
2688
+ return err ;
2689
+
2690
+ list_for_each_entry (this , & chain_hook .list , list ) {
2691
+ hook = nft_hook_list_find (& basechain -> hook_list , this );
2692
+ if (!hook ) {
2693
+ err = - ENOENT ;
2694
+ goto err_chain_del_hook ;
2695
+ }
2696
+ list_move (& hook -> list , & chain_del_list );
2697
+ }
2698
+
2699
+ trans = nft_trans_alloc (ctx , NFT_MSG_DELCHAIN ,
2700
+ sizeof (struct nft_trans_chain ));
2701
+ if (!trans ) {
2702
+ err = - ENOMEM ;
2703
+ goto err_chain_del_hook ;
2704
+ }
2705
+
2706
+ nft_trans_basechain (trans ) = basechain ;
2707
+ nft_trans_chain_update (trans ) = true;
2708
+ INIT_LIST_HEAD (& nft_trans_chain_hooks (trans ));
2709
+ list_splice (& chain_del_list , & nft_trans_chain_hooks (trans ));
2710
+ nft_chain_release_hook (& chain_hook );
2711
+
2712
+ nft_trans_commit_list_add_tail (ctx -> net , trans );
2713
+
2714
+ return 0 ;
2715
+
2716
+ err_chain_del_hook :
2717
+ list_splice (& chain_del_list , & basechain -> hook_list );
2718
+ nft_chain_release_hook (& chain_hook );
2719
+
2720
+ return err ;
2721
+ }
2722
+
2670
2723
static int nf_tables_delchain (struct sk_buff * skb , const struct nfnl_info * info ,
2671
2724
const struct nlattr * const nla [])
2672
2725
{
@@ -2707,12 +2760,19 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
2707
2760
return PTR_ERR (chain );
2708
2761
}
2709
2762
2763
+ nft_ctx_init (& ctx , net , skb , info -> nlh , family , table , chain , nla );
2764
+
2765
+ if (nla [NFTA_CHAIN_HOOK ]) {
2766
+ if (chain -> flags & NFT_CHAIN_HW_OFFLOAD )
2767
+ return - EOPNOTSUPP ;
2768
+
2769
+ return nft_delchain_hook (& ctx , chain , extack );
2770
+ }
2771
+
2710
2772
if (info -> nlh -> nlmsg_flags & NLM_F_NONREC &&
2711
2773
chain -> use > 0 )
2712
2774
return - EBUSY ;
2713
2775
2714
- nft_ctx_init (& ctx , net , skb , info -> nlh , family , table , chain , nla );
2715
-
2716
2776
use = chain -> use ;
2717
2777
list_for_each_entry (rule , & chain -> rules , list ) {
2718
2778
if (!nft_is_active_next (net , rule ))
@@ -8812,7 +8872,10 @@ static void nft_commit_release(struct nft_trans *trans)
8812
8872
break ;
8813
8873
case NFT_MSG_DELCHAIN :
8814
8874
case NFT_MSG_DESTROYCHAIN :
8815
- nf_tables_chain_destroy (& trans -> ctx );
8875
+ if (nft_trans_chain_update (trans ))
8876
+ nft_hooks_destroy (& nft_trans_chain_hooks (trans ));
8877
+ else
8878
+ nf_tables_chain_destroy (& trans -> ctx );
8816
8879
break ;
8817
8880
case NFT_MSG_DELRULE :
8818
8881
case NFT_MSG_DESTROYRULE :
@@ -9304,11 +9367,20 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
9304
9367
break ;
9305
9368
case NFT_MSG_DELCHAIN :
9306
9369
case NFT_MSG_DESTROYCHAIN :
9307
- nft_chain_del (trans -> ctx .chain );
9308
- nf_tables_chain_notify (& trans -> ctx , trans -> msg_type , NULL );
9309
- nf_tables_unregister_hook (trans -> ctx .net ,
9310
- trans -> ctx .table ,
9311
- trans -> ctx .chain );
9370
+ if (nft_trans_chain_update (trans )) {
9371
+ nf_tables_chain_notify (& trans -> ctx , NFT_MSG_DELCHAIN ,
9372
+ & nft_trans_chain_hooks (trans ));
9373
+ nft_netdev_unregister_hooks (net ,
9374
+ & nft_trans_chain_hooks (trans ),
9375
+ true);
9376
+ } else {
9377
+ nft_chain_del (trans -> ctx .chain );
9378
+ nf_tables_chain_notify (& trans -> ctx , NFT_MSG_DELCHAIN ,
9379
+ NULL );
9380
+ nf_tables_unregister_hook (trans -> ctx .net ,
9381
+ trans -> ctx .table ,
9382
+ trans -> ctx .chain );
9383
+ }
9312
9384
break ;
9313
9385
case NFT_MSG_NEWRULE :
9314
9386
nft_clear (trans -> ctx .net , nft_trans_rule (trans ));
@@ -9558,8 +9630,13 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
9558
9630
break ;
9559
9631
case NFT_MSG_DELCHAIN :
9560
9632
case NFT_MSG_DESTROYCHAIN :
9561
- trans -> ctx .table -> use ++ ;
9562
- nft_clear (trans -> ctx .net , trans -> ctx .chain );
9633
+ if (nft_trans_chain_update (trans )) {
9634
+ list_splice (& nft_trans_chain_hooks (trans ),
9635
+ & nft_trans_basechain (trans )-> hook_list );
9636
+ } else {
9637
+ trans -> ctx .table -> use ++ ;
9638
+ nft_clear (trans -> ctx .net , trans -> ctx .chain );
9639
+ }
9563
9640
nft_trans_destroy (trans );
9564
9641
break ;
9565
9642
case NFT_MSG_NEWRULE :
0 commit comments