30
30
#include <net/netfilter/nf_conntrack_zones.h>
31
31
#include <linux/netfilter/nf_nat.h>
32
32
33
- static DEFINE_SPINLOCK ( nf_nat_lock ) ;
33
+ static spinlock_t nf_nat_locks [ CONNTRACK_LOCKS ] ;
34
34
35
35
static DEFINE_MUTEX (nf_nat_proto_mutex );
36
36
static const struct nf_nat_l3proto __rcu * nf_nat_l3protos [NFPROTO_NUMPROTO ]
@@ -425,13 +425,15 @@ nf_nat_setup_info(struct nf_conn *ct,
425
425
426
426
if (maniptype == NF_NAT_MANIP_SRC ) {
427
427
unsigned int srchash ;
428
+ spinlock_t * lock ;
428
429
429
430
srchash = hash_by_src (net ,
430
431
& ct -> tuplehash [IP_CT_DIR_ORIGINAL ].tuple );
431
- spin_lock_bh (& nf_nat_lock );
432
+ lock = & nf_nat_locks [srchash % ARRAY_SIZE (nf_nat_locks )];
433
+ spin_lock_bh (lock );
432
434
hlist_add_head_rcu (& ct -> nat_bysource ,
433
435
& nf_nat_bysource [srchash ]);
434
- spin_unlock_bh (& nf_nat_lock );
436
+ spin_unlock_bh (lock );
435
437
}
436
438
437
439
/* It's done. */
@@ -525,6 +527,16 @@ static int nf_nat_proto_remove(struct nf_conn *i, void *data)
525
527
return i -> status & IPS_NAT_MASK ? 1 : 0 ;
526
528
}
527
529
530
+ static void __nf_nat_cleanup_conntrack (struct nf_conn * ct )
531
+ {
532
+ unsigned int h ;
533
+
534
+ h = hash_by_src (nf_ct_net (ct ), & ct -> tuplehash [IP_CT_DIR_ORIGINAL ].tuple );
535
+ spin_lock_bh (& nf_nat_locks [h % ARRAY_SIZE (nf_nat_locks )]);
536
+ hlist_del_rcu (& ct -> nat_bysource );
537
+ spin_unlock_bh (& nf_nat_locks [h % ARRAY_SIZE (nf_nat_locks )]);
538
+ }
539
+
528
540
static int nf_nat_proto_clean (struct nf_conn * ct , void * data )
529
541
{
530
542
if (nf_nat_proto_remove (ct , data ))
@@ -540,9 +552,7 @@ static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
540
552
* will delete entry from already-freed table.
541
553
*/
542
554
clear_bit (IPS_SRC_NAT_DONE_BIT , & ct -> status );
543
- spin_lock_bh (& nf_nat_lock );
544
- hlist_del_rcu (& ct -> nat_bysource );
545
- spin_unlock_bh (& nf_nat_lock );
555
+ __nf_nat_cleanup_conntrack (ct );
546
556
547
557
/* don't delete conntrack. Although that would make things a lot
548
558
* simpler, we'd end up flushing all conntracks on nat rmmod.
@@ -670,11 +680,8 @@ EXPORT_SYMBOL_GPL(nf_nat_l3proto_unregister);
670
680
/* No one using conntrack by the time this called. */
671
681
static void nf_nat_cleanup_conntrack (struct nf_conn * ct )
672
682
{
673
- if (ct -> status & IPS_SRC_NAT_DONE ) {
674
- spin_lock_bh (& nf_nat_lock );
675
- hlist_del_rcu (& ct -> nat_bysource );
676
- spin_unlock_bh (& nf_nat_lock );
677
- }
683
+ if (ct -> status & IPS_SRC_NAT_DONE )
684
+ __nf_nat_cleanup_conntrack (ct );
678
685
}
679
686
680
687
static struct nf_ct_ext_type nat_extend __read_mostly = {
@@ -796,10 +803,12 @@ static struct nf_ct_helper_expectfn follow_master_nat = {
796
803
797
804
static int __init nf_nat_init (void )
798
805
{
799
- int ret ;
806
+ int ret , i ;
800
807
801
808
/* Leave them the same for the moment. */
802
809
nf_nat_htable_size = nf_conntrack_htable_size ;
810
+ if (nf_nat_htable_size < ARRAY_SIZE (nf_nat_locks ))
811
+ nf_nat_htable_size = ARRAY_SIZE (nf_nat_locks );
803
812
804
813
nf_nat_bysource = nf_ct_alloc_hashtable (& nf_nat_htable_size , 0 );
805
814
if (!nf_nat_bysource )
@@ -812,6 +821,9 @@ static int __init nf_nat_init(void)
812
821
return ret ;
813
822
}
814
823
824
+ for (i = 0 ; i < ARRAY_SIZE (nf_nat_locks ); i ++ )
825
+ spin_lock_init (& nf_nat_locks [i ]);
826
+
815
827
nf_ct_helper_expectfn_register (& follow_master_nat );
816
828
817
829
BUG_ON (nfnetlink_parse_nat_setup_hook != NULL );
0 commit comments