@@ -6349,6 +6349,62 @@ static void nft_flowtable_hooks_destroy(struct list_head *hook_list)
6349
6349
}
6350
6350
}
6351
6351
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
+
6352
6408
static int nf_tables_newflowtable (struct net * net , struct sock * nlsk ,
6353
6409
struct sk_buff * skb ,
6354
6410
const struct nlmsghdr * nlh ,
@@ -6392,7 +6448,9 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
6392
6448
return - EEXIST ;
6393
6449
}
6394
6450
6395
- return 0 ;
6451
+ nft_ctx_init (& ctx , net , skb , nlh , family , table , NULL , nla );
6452
+
6453
+ return nft_flowtable_update (& ctx , nlh , flowtable );
6396
6454
}
6397
6455
6398
6456
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)
7495
7553
NFT_MSG_DELOBJ );
7496
7554
break ;
7497
7555
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
+ }
7503
7570
nft_trans_destroy (trans );
7504
7571
break ;
7505
7572
case NFT_MSG_DELFLOWTABLE :
@@ -7558,7 +7625,10 @@ static void nf_tables_abort_release(struct nft_trans *trans)
7558
7625
nft_obj_destroy (& trans -> ctx , nft_trans_obj (trans ));
7559
7626
break ;
7560
7627
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 ));
7562
7632
break ;
7563
7633
}
7564
7634
kfree (trans );
@@ -7665,10 +7735,15 @@ static int __nf_tables_abort(struct net *net, bool autoload)
7665
7735
nft_trans_destroy (trans );
7666
7736
break ;
7667
7737
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
+ }
7672
7747
break ;
7673
7748
case NFT_MSG_DELFLOWTABLE :
7674
7749
trans -> ctx .table -> use ++ ;
0 commit comments