@@ -1669,6 +1669,7 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
16691669 goto err_hook_dev ;
16701670 }
16711671 hook -> ops .dev = dev ;
1672+ hook -> inactive = false;
16721673
16731674 return hook ;
16741675
@@ -1678,17 +1679,17 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
16781679 return ERR_PTR (err );
16791680}
16801681
1681- static bool nft_hook_list_find (struct list_head * hook_list ,
1682- const struct nft_hook * this )
1682+ static struct nft_hook * nft_hook_list_find (struct list_head * hook_list ,
1683+ const struct nft_hook * this )
16831684{
16841685 struct nft_hook * hook ;
16851686
16861687 list_for_each_entry (hook , hook_list , list ) {
16871688 if (this -> ops .dev == hook -> ops .dev )
1688- return true ;
1689+ return hook ;
16891690 }
16901691
1691- return false ;
1692+ return NULL ;
16921693}
16931694
16941695static int nf_tables_parse_netdev_hooks (struct net * net ,
@@ -6530,6 +6531,51 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
65306531 return err ;
65316532}
65326533
6534+ static int nft_delflowtable_hook (struct nft_ctx * ctx ,
6535+ struct nft_flowtable * flowtable )
6536+ {
6537+ const struct nlattr * const * nla = ctx -> nla ;
6538+ struct nft_flowtable_hook flowtable_hook ;
6539+ struct nft_hook * this , * next , * hook ;
6540+ struct nft_trans * trans ;
6541+ int err ;
6542+
6543+ err = nft_flowtable_parse_hook (ctx , nla [NFTA_FLOWTABLE_HOOK ],
6544+ & flowtable_hook , & flowtable -> data );
6545+ if (err < 0 )
6546+ return err ;
6547+
6548+ list_for_each_entry_safe (this , next , & flowtable_hook .list , list ) {
6549+ hook = nft_hook_list_find (& flowtable -> hook_list , this );
6550+ if (!hook ) {
6551+ err = - ENOENT ;
6552+ goto err_flowtable_del_hook ;
6553+ }
6554+ hook -> inactive = true;
6555+ list_del (& this -> list );
6556+ kfree (this );
6557+ }
6558+
6559+ trans = nft_trans_alloc (ctx , NFT_MSG_DELFLOWTABLE ,
6560+ sizeof (struct nft_trans_flowtable ));
6561+ if (!trans )
6562+ return - ENOMEM ;
6563+
6564+ nft_trans_flowtable (trans ) = flowtable ;
6565+ nft_trans_flowtable_update (trans ) = true;
6566+ INIT_LIST_HEAD (& nft_trans_flowtable_hooks (trans ));
6567+
6568+ list_add_tail (& trans -> list , & ctx -> net -> nft .commit_list );
6569+
6570+ return 0 ;
6571+
6572+ err_flowtable_del_hook :
6573+ list_for_each_entry (hook , & flowtable_hook .list , list )
6574+ hook -> inactive = false;
6575+
6576+ return err ;
6577+ }
6578+
65336579static int nf_tables_delflowtable (struct net * net , struct sock * nlsk ,
65346580 struct sk_buff * skb ,
65356581 const struct nlmsghdr * nlh ,
@@ -6568,13 +6614,17 @@ static int nf_tables_delflowtable(struct net *net, struct sock *nlsk,
65686614 NL_SET_BAD_ATTR (extack , attr );
65696615 return PTR_ERR (flowtable );
65706616 }
6617+
6618+ nft_ctx_init (& ctx , net , skb , nlh , family , table , NULL , nla );
6619+
6620+ if (nla [NFTA_FLOWTABLE_HOOK ])
6621+ return nft_delflowtable_hook (& ctx , flowtable );
6622+
65716623 if (flowtable -> use > 0 ) {
65726624 NL_SET_BAD_ATTR (extack , attr );
65736625 return - EBUSY ;
65746626 }
65756627
6576- nft_ctx_init (& ctx , net , skb , nlh , family , table , NULL , nla );
6577-
65786628 return nft_delflowtable (& ctx , flowtable );
65796629}
65806630
@@ -7184,7 +7234,10 @@ static void nft_commit_release(struct nft_trans *trans)
71847234 nft_obj_destroy (& trans -> ctx , nft_trans_obj (trans ));
71857235 break ;
71867236 case NFT_MSG_DELFLOWTABLE :
7187- nf_tables_flowtable_destroy (nft_trans_flowtable (trans ));
7237+ if (nft_trans_flowtable_update (trans ))
7238+ nft_flowtable_hooks_destroy (& nft_trans_flowtable_hooks (trans ));
7239+ else
7240+ nf_tables_flowtable_destroy (nft_trans_flowtable (trans ));
71887241 break ;
71897242 }
71907243
@@ -7345,6 +7398,17 @@ static void nft_chain_del(struct nft_chain *chain)
73457398 list_del_rcu (& chain -> list );
73467399}
73477400
7401+ static void nft_flowtable_hooks_del (struct nft_flowtable * flowtable ,
7402+ struct list_head * hook_list )
7403+ {
7404+ struct nft_hook * hook , * next ;
7405+
7406+ list_for_each_entry_safe (hook , next , & flowtable -> hook_list , list ) {
7407+ if (hook -> inactive )
7408+ list_move (& hook -> list , hook_list );
7409+ }
7410+ }
7411+
73487412static void nf_tables_module_autoload_cleanup (struct net * net )
73497413{
73507414 struct nft_module_request * req , * next ;
@@ -7570,13 +7634,24 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
75707634 nft_trans_destroy (trans );
75717635 break ;
75727636 case NFT_MSG_DELFLOWTABLE :
7573- list_del_rcu (& nft_trans_flowtable (trans )-> list );
7574- nf_tables_flowtable_notify (& trans -> ctx ,
7575- nft_trans_flowtable (trans ),
7576- & nft_trans_flowtable (trans )-> hook_list ,
7577- NFT_MSG_DELFLOWTABLE );
7578- nft_unregister_flowtable_net_hooks (net ,
7579- & nft_trans_flowtable (trans )-> hook_list );
7637+ if (nft_trans_flowtable_update (trans )) {
7638+ nft_flowtable_hooks_del (nft_trans_flowtable (trans ),
7639+ & nft_trans_flowtable_hooks (trans ));
7640+ nf_tables_flowtable_notify (& trans -> ctx ,
7641+ nft_trans_flowtable (trans ),
7642+ & nft_trans_flowtable_hooks (trans ),
7643+ NFT_MSG_DELFLOWTABLE );
7644+ nft_unregister_flowtable_net_hooks (net ,
7645+ & nft_trans_flowtable_hooks (trans ));
7646+ } else {
7647+ list_del_rcu (& nft_trans_flowtable (trans )-> list );
7648+ nf_tables_flowtable_notify (& trans -> ctx ,
7649+ nft_trans_flowtable (trans ),
7650+ & nft_trans_flowtable (trans )-> hook_list ,
7651+ NFT_MSG_DELFLOWTABLE );
7652+ nft_unregister_flowtable_net_hooks (net ,
7653+ & nft_trans_flowtable (trans )-> hook_list );
7654+ }
75807655 break ;
75817656 }
75827657 }
@@ -7638,6 +7713,7 @@ static int __nf_tables_abort(struct net *net, bool autoload)
76387713{
76397714 struct nft_trans * trans , * next ;
76407715 struct nft_trans_elem * te ;
7716+ struct nft_hook * hook ;
76417717
76427718 list_for_each_entry_safe_reverse (trans , next , & net -> nft .commit_list ,
76437719 list ) {
@@ -7746,8 +7822,13 @@ static int __nf_tables_abort(struct net *net, bool autoload)
77467822 }
77477823 break ;
77487824 case NFT_MSG_DELFLOWTABLE :
7749- trans -> ctx .table -> use ++ ;
7750- nft_clear (trans -> ctx .net , nft_trans_flowtable (trans ));
7825+ if (nft_trans_flowtable_update (trans )) {
7826+ list_for_each_entry (hook , & nft_trans_flowtable (trans )-> hook_list , list )
7827+ hook -> inactive = false;
7828+ } else {
7829+ trans -> ctx .table -> use ++ ;
7830+ nft_clear (trans -> ctx .net , nft_trans_flowtable (trans ));
7831+ }
77517832 nft_trans_destroy (trans );
77527833 break ;
77537834 }
0 commit comments