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
+
33
35
static DEFINE_MUTEX (nf_nat_proto_mutex );
34
36
static const struct nf_nat_l3proto __rcu * nf_nat_l3protos [NFPROTO_NUMPROTO ]
35
37
__read_mostly ;
36
38
static const struct nf_nat_l4proto __rcu * * nf_nat_l4protos [NFPROTO_NUMPROTO ]
37
39
__read_mostly ;
38
40
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 rhltable nf_nat_bysource_table ;
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 ;
46
44
47
45
inline const struct nf_nat_l3proto *
48
46
__nf_nat_l3proto_find (u8 family )
@@ -118,17 +116,19 @@ int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
118
116
EXPORT_SYMBOL (nf_xfrm_me_harder );
119
117
#endif /* CONFIG_XFRM */
120
118
121
- static u32 nf_nat_bysource_hash (const void * data , u32 len , u32 seed )
119
+ /* We keep an extra hash for each conntrack, for fast searching. */
120
+ static unsigned int
121
+ hash_by_src (const struct net * n , const struct nf_conntrack_tuple * tuple )
122
122
{
123
- const struct nf_conntrack_tuple * t ;
124
- const struct nf_conn * ct = data ;
123
+ unsigned int hash ;
124
+
125
+ get_random_once (& nf_nat_hash_rnd , sizeof (nf_nat_hash_rnd ));
125
126
126
- t = & ct -> tuplehash [IP_CT_DIR_ORIGINAL ].tuple ;
127
127
/* Original src, to ensure we map it consistently if poss. */
128
+ hash = jhash2 ((u32 * )& tuple -> src , sizeof (tuple -> src ) / sizeof (u32 ),
129
+ tuple -> dst .protonum ^ nf_nat_hash_rnd ^ net_hash_mix (n ));
128
130
129
- seed ^= net_hash_mix (nf_ct_net (ct ));
130
- return jhash2 ((const u32 * )& t -> src , sizeof (t -> src ) / sizeof (u32 ),
131
- t -> dst .protonum ^ seed );
131
+ return reciprocal_scale (hash , nf_nat_htable_size );
132
132
}
133
133
134
134
/* Is this tuple already taken? (not by us) */
@@ -184,28 +184,6 @@ same_src(const struct nf_conn *ct,
184
184
t -> src .u .all == tuple -> src .u .all );
185
185
}
186
186
187
- static int nf_nat_bysource_cmp (struct rhashtable_compare_arg * arg ,
188
- const void * obj )
189
- {
190
- const struct nf_nat_conn_key * key = arg -> key ;
191
- const struct nf_conn * ct = obj ;
192
-
193
- if (!same_src (ct , key -> tuple ) ||
194
- !net_eq (nf_ct_net (ct ), key -> net ) ||
195
- !nf_ct_zone_equal (ct , key -> zone , IP_CT_DIR_ORIGINAL ))
196
- return 1 ;
197
-
198
- return 0 ;
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
- };
208
-
209
187
/* Only called for SRC manip */
210
188
static int
211
189
find_appropriate_src (struct net * net ,
@@ -216,26 +194,22 @@ find_appropriate_src(struct net *net,
216
194
struct nf_conntrack_tuple * result ,
217
195
const struct nf_nat_range * range )
218
196
{
197
+ unsigned int h = hash_by_src (net , tuple );
219
198
const struct nf_conn * ct ;
220
- struct nf_nat_conn_key key = {
221
- .net = net ,
222
- .tuple = tuple ,
223
- .zone = zone
224
- };
225
- struct rhlist_head * hl , * h ;
226
-
227
- hl = rhltable_lookup (& nf_nat_bysource_table , & key ,
228
- nf_nat_bysource_params );
229
199
230
- rhl_for_each_entry_rcu (ct , h , hl , nat_bysource ) {
231
- nf_ct_invert_tuplepr (result ,
232
- & ct -> tuplehash [IP_CT_DIR_REPLY ].tuple );
233
- result -> dst = tuple -> dst ;
234
-
235
- if (in_range (l3proto , l4proto , result , range ))
236
- return 1 ;
200
+ hlist_for_each_entry_rcu (ct , & nf_nat_bysource [h ], nat_bysource ) {
201
+ if (same_src (ct , tuple ) &&
202
+ net_eq (net , nf_ct_net (ct )) &&
203
+ nf_ct_zone_equal (ct , zone , IP_CT_DIR_ORIGINAL )) {
204
+ /* Copy source part from reply tuple. */
205
+ nf_ct_invert_tuplepr (result ,
206
+ & ct -> tuplehash [IP_CT_DIR_REPLY ].tuple );
207
+ result -> dst = tuple -> dst ;
208
+
209
+ if (in_range (l3proto , l4proto , result , range ))
210
+ return 1 ;
211
+ }
237
212
}
238
-
239
213
return 0 ;
240
214
}
241
215
@@ -408,6 +382,7 @@ nf_nat_setup_info(struct nf_conn *ct,
408
382
const struct nf_nat_range * range ,
409
383
enum nf_nat_manip_type maniptype )
410
384
{
385
+ struct net * net = nf_ct_net (ct );
411
386
struct nf_conntrack_tuple curr_tuple , new_tuple ;
412
387
413
388
/* Can't setup nat info for confirmed ct. */
@@ -449,19 +424,14 @@ nf_nat_setup_info(struct nf_conn *ct,
449
424
}
450
425
451
426
if (maniptype == NF_NAT_MANIP_SRC ) {
452
- struct nf_nat_conn_key key = {
453
- .net = nf_ct_net (ct ),
454
- .tuple = & ct -> tuplehash [IP_CT_DIR_ORIGINAL ].tuple ,
455
- .zone = nf_ct_zone (ct ),
456
- };
457
- int err ;
458
-
459
- err = rhltable_insert_key (& nf_nat_bysource_table ,
460
- & key ,
461
- & ct -> nat_bysource ,
462
- nf_nat_bysource_params );
463
- if (err )
464
- return NF_DROP ;
427
+ unsigned int srchash ;
428
+
429
+ srchash = hash_by_src (net ,
430
+ & ct -> tuplehash [IP_CT_DIR_ORIGINAL ].tuple );
431
+ spin_lock_bh (& nf_nat_lock );
432
+ hlist_add_head_rcu (& ct -> nat_bysource ,
433
+ & nf_nat_bysource [srchash ]);
434
+ spin_unlock_bh (& nf_nat_lock );
465
435
}
466
436
467
437
/* It's done. */
@@ -570,8 +540,9 @@ static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
570
540
* will delete entry from already-freed table.
571
541
*/
572
542
clear_bit (IPS_SRC_NAT_DONE_BIT , & ct -> status );
573
- rhltable_remove (& nf_nat_bysource_table , & ct -> nat_bysource ,
574
- nf_nat_bysource_params );
543
+ spin_lock_bh (& nf_nat_lock );
544
+ hlist_del_rcu (& ct -> nat_bysource );
545
+ spin_unlock_bh (& nf_nat_lock );
575
546
576
547
/* don't delete conntrack. Although that would make things a lot
577
548
* simpler, we'd end up flushing all conntracks on nat rmmod.
@@ -699,9 +670,11 @@ EXPORT_SYMBOL_GPL(nf_nat_l3proto_unregister);
699
670
/* No one using conntrack by the time this called. */
700
671
static void nf_nat_cleanup_conntrack (struct nf_conn * ct )
701
672
{
702
- if (ct -> status & IPS_SRC_NAT_DONE )
703
- rhltable_remove (& nf_nat_bysource_table , & ct -> nat_bysource ,
704
- nf_nat_bysource_params );
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
+ }
705
678
}
706
679
707
680
static struct nf_ct_ext_type nat_extend __read_mostly = {
@@ -825,13 +798,16 @@ static int __init nf_nat_init(void)
825
798
{
826
799
int ret ;
827
800
828
- ret = rhltable_init (& nf_nat_bysource_table , & nf_nat_bysource_params );
829
- if (ret )
830
- return ret ;
801
+ /* Leave them the same for the moment. */
802
+ nf_nat_htable_size = nf_conntrack_htable_size ;
803
+
804
+ nf_nat_bysource = nf_ct_alloc_hashtable (& nf_nat_htable_size , 0 );
805
+ if (!nf_nat_bysource )
806
+ return - ENOMEM ;
831
807
832
808
ret = nf_ct_extend_register (& nat_extend );
833
809
if (ret < 0 ) {
834
- rhltable_destroy ( & nf_nat_bysource_table );
810
+ nf_ct_free_hashtable ( nf_nat_bysource , nf_nat_htable_size );
835
811
printk (KERN_ERR "nf_nat_core: Unable to register extension\n" );
836
812
return ret ;
837
813
}
@@ -865,8 +841,8 @@ static void __exit nf_nat_cleanup(void)
865
841
866
842
for (i = 0 ; i < NFPROTO_NUMPROTO ; i ++ )
867
843
kfree (nf_nat_l4protos [i ]);
868
-
869
- rhltable_destroy ( & nf_nat_bysource_table );
844
+ synchronize_net ();
845
+ nf_ct_free_hashtable ( nf_nat_bysource , nf_nat_htable_size );
870
846
}
871
847
872
848
MODULE_LICENSE ("GPL" );
0 commit comments