@@ -684,15 +684,16 @@ static int nft_delobj(struct nft_ctx *ctx, struct nft_object *obj)
684
684
return err ;
685
685
}
686
686
687
- static int nft_trans_flowtable_add (struct nft_ctx * ctx , int msg_type ,
688
- struct nft_flowtable * flowtable )
687
+ static struct nft_trans *
688
+ nft_trans_flowtable_add (struct nft_ctx * ctx , int msg_type ,
689
+ struct nft_flowtable * flowtable )
689
690
{
690
691
struct nft_trans * trans ;
691
692
692
693
trans = nft_trans_alloc (ctx , msg_type ,
693
694
sizeof (struct nft_trans_flowtable ));
694
695
if (trans == NULL )
695
- return - ENOMEM ;
696
+ return ERR_PTR ( - ENOMEM ) ;
696
697
697
698
if (msg_type == NFT_MSG_NEWFLOWTABLE )
698
699
nft_activate_next (ctx -> net , flowtable );
@@ -701,22 +702,22 @@ static int nft_trans_flowtable_add(struct nft_ctx *ctx, int msg_type,
701
702
nft_trans_flowtable (trans ) = flowtable ;
702
703
nft_trans_commit_list_add_tail (ctx -> net , trans );
703
704
704
- return 0 ;
705
+ return trans ;
705
706
}
706
707
707
708
static int nft_delflowtable (struct nft_ctx * ctx ,
708
709
struct nft_flowtable * flowtable )
709
710
{
710
- int err ;
711
+ struct nft_trans * trans ;
711
712
712
- err = nft_trans_flowtable_add (ctx , NFT_MSG_DELFLOWTABLE , flowtable );
713
- if (err < 0 )
714
- return err ;
713
+ trans = nft_trans_flowtable_add (ctx , NFT_MSG_DELFLOWTABLE , flowtable );
714
+ if (IS_ERR ( trans ) )
715
+ return PTR_ERR ( trans ) ;
715
716
716
717
nft_deactivate_next (ctx -> net , flowtable );
717
718
nft_use_dec (& ctx -> table -> use );
718
719
719
- return err ;
720
+ return 0 ;
720
721
}
721
722
722
723
static void __nft_reg_track_clobber (struct nft_regs_track * track , u8 dreg )
@@ -2504,37 +2505,38 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
2504
2505
RCU_INIT_POINTER (chain -> blob_gen_0 , blob );
2505
2506
RCU_INIT_POINTER (chain -> blob_gen_1 , blob );
2506
2507
2507
- err = nf_tables_register_hook (net , table , chain );
2508
- if (err < 0 )
2509
- goto err_destroy_chain ;
2510
-
2511
2508
if (!nft_use_inc (& table -> use )) {
2512
2509
err = - EMFILE ;
2513
- goto err_use ;
2510
+ goto err_destroy_chain ;
2514
2511
}
2515
2512
2516
2513
trans = nft_trans_chain_add (ctx , NFT_MSG_NEWCHAIN );
2517
2514
if (IS_ERR (trans )) {
2518
2515
err = PTR_ERR (trans );
2519
- goto err_unregister_hook ;
2516
+ goto err_trans ;
2520
2517
}
2521
2518
2522
2519
nft_trans_chain_policy (trans ) = NFT_CHAIN_POLICY_UNSET ;
2523
2520
if (nft_is_base_chain (chain ))
2524
2521
nft_trans_chain_policy (trans ) = policy ;
2525
2522
2526
2523
err = nft_chain_add (table , chain );
2527
- if (err < 0 ) {
2528
- nft_trans_destroy (trans );
2529
- goto err_unregister_hook ;
2530
- }
2524
+ if (err < 0 )
2525
+ goto err_chain_add ;
2526
+
2527
+ /* This must be LAST to ensure no packets are walking over this chain. */
2528
+ err = nf_tables_register_hook (net , table , chain );
2529
+ if (err < 0 )
2530
+ goto err_register_hook ;
2531
2531
2532
2532
return 0 ;
2533
2533
2534
- err_unregister_hook :
2534
+ err_register_hook :
2535
+ nft_chain_del (chain );
2536
+ err_chain_add :
2537
+ nft_trans_destroy (trans );
2538
+ err_trans :
2535
2539
nft_use_dec_restore (& table -> use );
2536
- err_use :
2537
- nf_tables_unregister_hook (net , table , chain );
2538
2540
err_destroy_chain :
2539
2541
nf_tables_chain_destroy (ctx );
2540
2542
@@ -8456,9 +8458,9 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
8456
8458
u8 family = info -> nfmsg -> nfgen_family ;
8457
8459
const struct nf_flowtable_type * type ;
8458
8460
struct nft_flowtable * flowtable ;
8459
- struct nft_hook * hook , * next ;
8460
8461
struct net * net = info -> net ;
8461
8462
struct nft_table * table ;
8463
+ struct nft_trans * trans ;
8462
8464
struct nft_ctx ctx ;
8463
8465
int err ;
8464
8466
@@ -8538,34 +8540,34 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
8538
8540
err = nft_flowtable_parse_hook (& ctx , nla , & flowtable_hook , flowtable ,
8539
8541
extack , true);
8540
8542
if (err < 0 )
8541
- goto err4 ;
8543
+ goto err_flowtable_parse_hooks ;
8542
8544
8543
8545
list_splice (& flowtable_hook .list , & flowtable -> hook_list );
8544
8546
flowtable -> data .priority = flowtable_hook .priority ;
8545
8547
flowtable -> hooknum = flowtable_hook .num ;
8546
8548
8549
+ trans = nft_trans_flowtable_add (& ctx , NFT_MSG_NEWFLOWTABLE , flowtable );
8550
+ if (IS_ERR (trans )) {
8551
+ err = PTR_ERR (trans );
8552
+ goto err_flowtable_trans ;
8553
+ }
8554
+
8555
+ /* This must be LAST to ensure no packets are walking over this flowtable. */
8547
8556
err = nft_register_flowtable_net_hooks (ctx .net , table ,
8548
8557
& flowtable -> hook_list ,
8549
8558
flowtable );
8550
- if (err < 0 ) {
8551
- nft_hooks_destroy (& flowtable -> hook_list );
8552
- goto err4 ;
8553
- }
8554
-
8555
- err = nft_trans_flowtable_add (& ctx , NFT_MSG_NEWFLOWTABLE , flowtable );
8556
8559
if (err < 0 )
8557
- goto err5 ;
8560
+ goto err_flowtable_hooks ;
8558
8561
8559
8562
list_add_tail_rcu (& flowtable -> list , & table -> flowtables );
8560
8563
8561
8564
return 0 ;
8562
- err5 :
8563
- list_for_each_entry_safe (hook , next , & flowtable -> hook_list , list ) {
8564
- nft_unregister_flowtable_hook (net , flowtable , hook );
8565
- list_del_rcu (& hook -> list );
8566
- kfree_rcu (hook , rcu );
8567
- }
8568
- err4 :
8565
+
8566
+ err_flowtable_hooks :
8567
+ nft_trans_destroy (trans );
8568
+ err_flowtable_trans :
8569
+ nft_hooks_destroy (& flowtable -> hook_list );
8570
+ err_flowtable_parse_hooks :
8569
8571
flowtable -> data .type -> free (& flowtable -> data );
8570
8572
err3 :
8571
8573
module_put (type -> owner );
0 commit comments