@@ -1646,7 +1646,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
16461646 NFTA_CHAIN_PAD ))
16471647 goto nla_put_failure ;
16481648
1649- if (event == NFT_MSG_DELCHAIN ) {
1649+ if (event == NFT_MSG_DELCHAIN && ! hook_list ) {
16501650 nlmsg_end (skb , nlh );
16511651 return 0 ;
16521652 }
@@ -2667,6 +2667,59 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
26672667 return nf_tables_addchain (& ctx , family , genmask , policy , flags , extack );
26682668}
26692669
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+
26702723static int nf_tables_delchain (struct sk_buff * skb , const struct nfnl_info * info ,
26712724 const struct nlattr * const nla [])
26722725{
@@ -2707,12 +2760,19 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
27072760 return PTR_ERR (chain );
27082761 }
27092762
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+
27102772 if (info -> nlh -> nlmsg_flags & NLM_F_NONREC &&
27112773 chain -> use > 0 )
27122774 return - EBUSY ;
27132775
2714- nft_ctx_init (& ctx , net , skb , info -> nlh , family , table , chain , nla );
2715-
27162776 use = chain -> use ;
27172777 list_for_each_entry (rule , & chain -> rules , list ) {
27182778 if (!nft_is_active_next (net , rule ))
@@ -8812,7 +8872,10 @@ static void nft_commit_release(struct nft_trans *trans)
88128872 break ;
88138873 case NFT_MSG_DELCHAIN :
88148874 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 );
88168879 break ;
88178880 case NFT_MSG_DELRULE :
88188881 case NFT_MSG_DESTROYRULE :
@@ -9304,11 +9367,20 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
93049367 break ;
93059368 case NFT_MSG_DELCHAIN :
93069369 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+ }
93129384 break ;
93139385 case NFT_MSG_NEWRULE :
93149386 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)
95589630 break ;
95599631 case NFT_MSG_DELCHAIN :
95609632 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+ }
95639640 nft_trans_destroy (trans );
95649641 break ;
95659642 case NFT_MSG_NEWRULE :
0 commit comments