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 );
34
-
35
33
static DEFINE_MUTEX (nf_nat_proto_mutex );
36
34
static const struct nf_nat_l3proto __rcu * nf_nat_l3protos [NFPROTO_NUMPROTO ]
37
35
__read_mostly ;
38
36
static const struct nf_nat_l4proto __rcu * * nf_nat_l4protos [NFPROTO_NUMPROTO ]
39
37
__read_mostly ;
40
38
41
- static struct hlist_head * nf_nat_bysource __read_mostly ;
42
- static unsigned int nf_nat_htable_size __read_mostly ;
43
- static unsigned int nf_nat_hash_rnd __read_mostly ;
39
+ struct nf_nat_conn_key {
40
+ const struct net * net ;
41
+ const struct nf_conntrack_tuple * tuple ;
42
+ const struct nf_conntrack_zone * zone ;
43
+ };
44
+
45
+ static struct rhashtable nf_nat_bysource_table ;
44
46
45
47
inline const struct nf_nat_l3proto *
46
48
__nf_nat_l3proto_find (u8 family )
@@ -119,19 +121,17 @@ int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
119
121
EXPORT_SYMBOL (nf_xfrm_me_harder );
120
122
#endif /* CONFIG_XFRM */
121
123
122
- /* We keep an extra hash for each conntrack, for fast searching. */
123
- static inline unsigned int
124
- hash_by_src (const struct net * n , const struct nf_conntrack_tuple * tuple )
124
+ static u32 nf_nat_bysource_hash (const void * data , u32 len , u32 seed )
125
125
{
126
- unsigned int hash ;
127
-
128
- get_random_once (& nf_nat_hash_rnd , sizeof (nf_nat_hash_rnd ));
126
+ const struct nf_conntrack_tuple * t ;
127
+ const struct nf_conn * ct = data ;
129
128
129
+ t = & ct -> tuplehash [IP_CT_DIR_ORIGINAL ].tuple ;
130
130
/* Original src, to ensure we map it consistently if poss. */
131
- hash = jhash2 ((u32 * )& tuple -> src , sizeof (tuple -> src ) / sizeof (u32 ),
132
- tuple -> dst .protonum ^ nf_nat_hash_rnd ^ net_hash_mix (n ));
133
131
134
- return reciprocal_scale (hash , nf_nat_htable_size );
132
+ seed ^= net_hash_mix (nf_ct_net (ct ));
133
+ return jhash2 ((const u32 * )& t -> src , sizeof (t -> src ) / sizeof (u32 ),
134
+ t -> dst .protonum ^ seed );
135
135
}
136
136
137
137
/* Is this tuple already taken? (not by us) */
@@ -187,6 +187,26 @@ same_src(const struct nf_conn *ct,
187
187
t -> src .u .all == tuple -> src .u .all );
188
188
}
189
189
190
+ static int nf_nat_bysource_cmp (struct rhashtable_compare_arg * arg ,
191
+ const void * obj )
192
+ {
193
+ const struct nf_nat_conn_key * key = arg -> key ;
194
+ const struct nf_conn * ct = obj ;
195
+
196
+ return same_src (ct , key -> tuple ) &&
197
+ net_eq (nf_ct_net (ct ), key -> net ) &&
198
+ nf_ct_zone_equal (ct , key -> zone , IP_CT_DIR_ORIGINAL );
199
+ }
200
+
201
+ static struct rhashtable_params nf_nat_bysource_params = {
202
+ .head_offset = offsetof(struct nf_conn , nat_bysource ),
203
+ .obj_hashfn = nf_nat_bysource_hash ,
204
+ .obj_cmpfn = nf_nat_bysource_cmp ,
205
+ .nelem_hint = 256 ,
206
+ .min_size = 1024 ,
207
+ .nulls_base = (1U << RHT_BASE_SHIFT ),
208
+ };
209
+
190
210
/* Only called for SRC manip */
191
211
static int
192
212
find_appropriate_src (struct net * net ,
@@ -197,23 +217,23 @@ find_appropriate_src(struct net *net,
197
217
struct nf_conntrack_tuple * result ,
198
218
const struct nf_nat_range * range )
199
219
{
200
- unsigned int h = hash_by_src (net , tuple );
201
220
const struct nf_conn * ct ;
221
+ struct nf_nat_conn_key key = {
222
+ .net = net ,
223
+ .tuple = tuple ,
224
+ .zone = zone
225
+ };
202
226
203
- hlist_for_each_entry_rcu (ct , & nf_nat_bysource [h ], nat_bysource ) {
204
- if (same_src (ct , tuple ) &&
205
- net_eq (net , nf_ct_net (ct )) &&
206
- nf_ct_zone_equal (ct , zone , IP_CT_DIR_ORIGINAL )) {
207
- /* Copy source part from reply tuple. */
208
- nf_ct_invert_tuplepr (result ,
209
- & ct -> tuplehash [IP_CT_DIR_REPLY ].tuple );
210
- result -> dst = tuple -> dst ;
211
-
212
- if (in_range (l3proto , l4proto , result , range ))
213
- return 1 ;
214
- }
215
- }
216
- return 0 ;
227
+ ct = rhashtable_lookup_fast (& nf_nat_bysource_table , & key ,
228
+ nf_nat_bysource_params );
229
+ if (!ct )
230
+ return 0 ;
231
+
232
+ nf_ct_invert_tuplepr (result ,
233
+ & ct -> tuplehash [IP_CT_DIR_REPLY ].tuple );
234
+ result -> dst = tuple -> dst ;
235
+
236
+ return in_range (l3proto , l4proto , result , range );
217
237
}
218
238
219
239
/* For [FUTURE] fragmentation handling, we want the least-used
@@ -385,7 +405,6 @@ nf_nat_setup_info(struct nf_conn *ct,
385
405
const struct nf_nat_range * range ,
386
406
enum nf_nat_manip_type maniptype )
387
407
{
388
- struct net * net = nf_ct_net (ct );
389
408
struct nf_conntrack_tuple curr_tuple , new_tuple ;
390
409
struct nf_conn_nat * nat ;
391
410
@@ -426,16 +445,13 @@ nf_nat_setup_info(struct nf_conn *ct,
426
445
}
427
446
428
447
if (maniptype == NF_NAT_MANIP_SRC ) {
429
- unsigned int srchash ;
430
-
431
- srchash = hash_by_src (net ,
432
- & ct -> tuplehash [IP_CT_DIR_ORIGINAL ].tuple );
433
- spin_lock_bh (& nf_nat_lock );
434
- /* nf_conntrack_alter_reply might re-allocate extension aera */
435
- nat = nfct_nat (ct );
436
- hlist_add_head_rcu (& ct -> nat_bysource ,
437
- & nf_nat_bysource [srchash ]);
438
- spin_unlock_bh (& nf_nat_lock );
448
+ int err ;
449
+
450
+ err = rhashtable_insert_fast (& nf_nat_bysource_table ,
451
+ & ct -> nat_bysource ,
452
+ nf_nat_bysource_params );
453
+ if (err )
454
+ return NF_DROP ;
439
455
}
440
456
441
457
/* It's done. */
@@ -552,10 +568,10 @@ static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
552
568
if (!del_timer (& ct -> timeout ))
553
569
return 1 ;
554
570
555
- spin_lock_bh (& nf_nat_lock );
556
- hlist_del_rcu (& ct -> nat_bysource );
557
571
ct -> status &= ~IPS_NAT_DONE_MASK ;
558
- spin_unlock_bh (& nf_nat_lock );
572
+
573
+ rhashtable_remove_fast (& nf_nat_bysource_table , & ct -> nat_bysource ,
574
+ nf_nat_bysource_params );
559
575
560
576
add_timer (& ct -> timeout );
561
577
@@ -687,11 +703,8 @@ static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
687
703
if (!nat )
688
704
return ;
689
705
690
- NF_CT_ASSERT (ct -> status & IPS_SRC_NAT_DONE );
691
-
692
- spin_lock_bh (& nf_nat_lock );
693
- hlist_del_rcu (& ct -> nat_bysource );
694
- spin_unlock_bh (& nf_nat_lock );
706
+ rhashtable_remove_fast (& nf_nat_bysource_table , & ct -> nat_bysource ,
707
+ nf_nat_bysource_params );
695
708
}
696
709
697
710
static struct nf_ct_ext_type nat_extend __read_mostly = {
@@ -826,16 +839,13 @@ static int __init nf_nat_init(void)
826
839
{
827
840
int ret ;
828
841
829
- /* Leave them the same for the moment. */
830
- nf_nat_htable_size = nf_conntrack_htable_size ;
831
-
832
- nf_nat_bysource = nf_ct_alloc_hashtable (& nf_nat_htable_size , 0 );
833
- if (!nf_nat_bysource )
834
- return - ENOMEM ;
842
+ ret = rhashtable_init (& nf_nat_bysource_table , & nf_nat_bysource_params );
843
+ if (ret )
844
+ return ret ;
835
845
836
846
ret = nf_ct_extend_register (& nat_extend );
837
847
if (ret < 0 ) {
838
- nf_ct_free_hashtable ( nf_nat_bysource , nf_nat_htable_size );
848
+ rhashtable_destroy ( & nf_nat_bysource_table );
839
849
printk (KERN_ERR "nf_nat_core: Unable to register extension\n" );
840
850
return ret ;
841
851
}
@@ -859,7 +869,7 @@ static int __init nf_nat_init(void)
859
869
return 0 ;
860
870
861
871
cleanup_extend :
862
- nf_ct_free_hashtable ( nf_nat_bysource , nf_nat_htable_size );
872
+ rhashtable_destroy ( & nf_nat_bysource_table );
863
873
nf_ct_extend_unregister (& nat_extend );
864
874
return ret ;
865
875
}
@@ -877,8 +887,8 @@ static void __exit nf_nat_cleanup(void)
877
887
#endif
878
888
for (i = 0 ; i < NFPROTO_NUMPROTO ; i ++ )
879
889
kfree (nf_nat_l4protos [i ]);
880
- synchronize_net ();
881
- nf_ct_free_hashtable ( nf_nat_bysource , nf_nat_htable_size );
890
+
891
+ rhashtable_destroy ( & nf_nat_bysource_table );
882
892
}
883
893
884
894
MODULE_LICENSE ("GPL" );
0 commit comments