@@ -6349,6 +6349,62 @@ static void nft_flowtable_hooks_destroy(struct list_head *hook_list)
63496349 }
63506350}
63516351
6352+ static int nft_flowtable_update (struct nft_ctx * ctx , const struct nlmsghdr * nlh ,
6353+ struct nft_flowtable * flowtable )
6354+ {
6355+ const struct nlattr * const * nla = ctx -> nla ;
6356+ struct nft_flowtable_hook flowtable_hook ;
6357+ struct nft_hook * hook , * next ;
6358+ struct nft_trans * trans ;
6359+ bool unregister = false;
6360+ int err ;
6361+
6362+ err = nft_flowtable_parse_hook (ctx , nla [NFTA_FLOWTABLE_HOOK ],
6363+ & flowtable_hook , & flowtable -> data );
6364+ if (err < 0 )
6365+ return err ;
6366+
6367+ list_for_each_entry_safe (hook , next , & flowtable_hook .list , list ) {
6368+ if (nft_hook_list_find (& flowtable -> hook_list , hook )) {
6369+ list_del (& hook -> list );
6370+ kfree (hook );
6371+ }
6372+ }
6373+
6374+ err = nft_register_flowtable_net_hooks (ctx -> net , ctx -> table ,
6375+ & flowtable_hook .list , flowtable );
6376+ if (err < 0 )
6377+ goto err_flowtable_update_hook ;
6378+
6379+ trans = nft_trans_alloc (ctx , NFT_MSG_NEWFLOWTABLE ,
6380+ sizeof (struct nft_trans_flowtable ));
6381+ if (!trans ) {
6382+ unregister = true;
6383+ err = - ENOMEM ;
6384+ goto err_flowtable_update_hook ;
6385+ }
6386+
6387+ nft_trans_flowtable (trans ) = flowtable ;
6388+ nft_trans_flowtable_update (trans ) = true;
6389+ INIT_LIST_HEAD (& nft_trans_flowtable_hooks (trans ));
6390+ list_splice (& flowtable_hook .list , & nft_trans_flowtable_hooks (trans ));
6391+
6392+ list_add_tail (& trans -> list , & ctx -> net -> nft .commit_list );
6393+
6394+ return 0 ;
6395+
6396+ err_flowtable_update_hook :
6397+ list_for_each_entry_safe (hook , next , & flowtable_hook .list , list ) {
6398+ if (unregister )
6399+ nft_unregister_flowtable_hook (ctx -> net , flowtable , hook );
6400+ list_del_rcu (& hook -> list );
6401+ kfree_rcu (hook , rcu );
6402+ }
6403+
6404+ return err ;
6405+
6406+ }
6407+
63526408static int nf_tables_newflowtable (struct net * net , struct sock * nlsk ,
63536409 struct sk_buff * skb ,
63546410 const struct nlmsghdr * nlh ,
@@ -6392,7 +6448,9 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
63926448 return - EEXIST ;
63936449 }
63946450
6395- return 0 ;
6451+ nft_ctx_init (& ctx , net , skb , nlh , family , table , NULL , nla );
6452+
6453+ return nft_flowtable_update (& ctx , nlh , flowtable );
63966454 }
63976455
63986456 nft_ctx_init (& ctx , net , skb , nlh , family , table , NULL , nla );
@@ -7495,11 +7553,20 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
74957553 NFT_MSG_DELOBJ );
74967554 break ;
74977555 case NFT_MSG_NEWFLOWTABLE :
7498- nft_clear (net , nft_trans_flowtable (trans ));
7499- nf_tables_flowtable_notify (& trans -> ctx ,
7500- nft_trans_flowtable (trans ),
7501- & nft_trans_flowtable (trans )-> hook_list ,
7502- NFT_MSG_NEWFLOWTABLE );
7556+ if (nft_trans_flowtable_update (trans )) {
7557+ nf_tables_flowtable_notify (& trans -> ctx ,
7558+ nft_trans_flowtable (trans ),
7559+ & nft_trans_flowtable_hooks (trans ),
7560+ NFT_MSG_NEWFLOWTABLE );
7561+ list_splice (& nft_trans_flowtable_hooks (trans ),
7562+ & nft_trans_flowtable (trans )-> hook_list );
7563+ } else {
7564+ nft_clear (net , nft_trans_flowtable (trans ));
7565+ nf_tables_flowtable_notify (& trans -> ctx ,
7566+ nft_trans_flowtable (trans ),
7567+ & nft_trans_flowtable (trans )-> hook_list ,
7568+ NFT_MSG_NEWFLOWTABLE );
7569+ }
75037570 nft_trans_destroy (trans );
75047571 break ;
75057572 case NFT_MSG_DELFLOWTABLE :
@@ -7558,7 +7625,10 @@ static void nf_tables_abort_release(struct nft_trans *trans)
75587625 nft_obj_destroy (& trans -> ctx , nft_trans_obj (trans ));
75597626 break ;
75607627 case NFT_MSG_NEWFLOWTABLE :
7561- nf_tables_flowtable_destroy (nft_trans_flowtable (trans ));
7628+ if (nft_trans_flowtable_update (trans ))
7629+ nft_flowtable_hooks_destroy (& nft_trans_flowtable_hooks (trans ));
7630+ else
7631+ nf_tables_flowtable_destroy (nft_trans_flowtable (trans ));
75627632 break ;
75637633 }
75647634 kfree (trans );
@@ -7665,10 +7735,15 @@ static int __nf_tables_abort(struct net *net, bool autoload)
76657735 nft_trans_destroy (trans );
76667736 break ;
76677737 case NFT_MSG_NEWFLOWTABLE :
7668- trans -> ctx .table -> use -- ;
7669- list_del_rcu (& nft_trans_flowtable (trans )-> list );
7670- nft_unregister_flowtable_net_hooks (net ,
7671- & nft_trans_flowtable (trans )-> hook_list );
7738+ if (nft_trans_flowtable_update (trans )) {
7739+ nft_unregister_flowtable_net_hooks (net ,
7740+ & nft_trans_flowtable_hooks (trans ));
7741+ } else {
7742+ trans -> ctx .table -> use -- ;
7743+ list_del_rcu (& nft_trans_flowtable (trans )-> list );
7744+ nft_unregister_flowtable_net_hooks (net ,
7745+ & nft_trans_flowtable (trans )-> hook_list );
7746+ }
76727747 break ;
76737748 case NFT_MSG_DELFLOWTABLE :
76747749 trans -> ctx .table -> use ++ ;
0 commit comments