Commit 0c4c9288ada0e6642d511ef872f10a4781a896ff
Committed by
Patrick McHardy
1 parent
e099a17357
netfilter: netns nat: per-netns bysource hash
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Patrick McHardy <kaber@trash.net>
Showing 2 changed files with 47 additions and 27 deletions Side-by-side Diff
include/net/netns/ipv4.h
net/ipv4/netfilter/nf_nat_core.c
... | ... | @@ -37,10 +37,7 @@ |
37 | 37 | |
38 | 38 | /* Calculated at init based on memory size */ |
39 | 39 | static unsigned int nf_nat_htable_size __read_mostly; |
40 | -static int nf_nat_vmalloced; | |
41 | 40 | |
42 | -static struct hlist_head *bysource __read_mostly; | |
43 | - | |
44 | 41 | #define MAX_IP_NAT_PROTO 256 |
45 | 42 | static const struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO] |
46 | 43 | __read_mostly; |
... | ... | @@ -145,7 +142,8 @@ |
145 | 142 | |
146 | 143 | /* Only called for SRC manip */ |
147 | 144 | static int |
148 | -find_appropriate_src(const struct nf_conntrack_tuple *tuple, | |
145 | +find_appropriate_src(struct net *net, | |
146 | + const struct nf_conntrack_tuple *tuple, | |
149 | 147 | struct nf_conntrack_tuple *result, |
150 | 148 | const struct nf_nat_range *range) |
151 | 149 | { |
... | ... | @@ -155,7 +153,7 @@ |
155 | 153 | const struct hlist_node *n; |
156 | 154 | |
157 | 155 | rcu_read_lock(); |
158 | - hlist_for_each_entry_rcu(nat, n, &bysource[h], bysource) { | |
156 | + hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) { | |
159 | 157 | ct = nat->ct; |
160 | 158 | if (same_src(ct, tuple)) { |
161 | 159 | /* Copy source part from reply tuple. */ |
... | ... | @@ -231,6 +229,7 @@ |
231 | 229 | struct nf_conn *ct, |
232 | 230 | enum nf_nat_manip_type maniptype) |
233 | 231 | { |
232 | + struct net *net = nf_ct_net(ct); | |
234 | 233 | const struct nf_nat_protocol *proto; |
235 | 234 | |
236 | 235 | /* 1) If this srcip/proto/src-proto-part is currently mapped, |
... | ... | @@ -242,7 +241,7 @@ |
242 | 241 | manips not an issue. */ |
243 | 242 | if (maniptype == IP_NAT_MANIP_SRC && |
244 | 243 | !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) { |
245 | - if (find_appropriate_src(orig_tuple, tuple, range)) { | |
244 | + if (find_appropriate_src(net, orig_tuple, tuple, range)) { | |
246 | 245 | pr_debug("get_unique_tuple: Found current src map\n"); |
247 | 246 | if (!nf_nat_used_tuple(tuple, ct)) |
248 | 247 | return; |
... | ... | @@ -283,6 +282,7 @@ |
283 | 282 | const struct nf_nat_range *range, |
284 | 283 | enum nf_nat_manip_type maniptype) |
285 | 284 | { |
285 | + struct net *net = nf_ct_net(ct); | |
286 | 286 | struct nf_conntrack_tuple curr_tuple, new_tuple; |
287 | 287 | struct nf_conn_nat *nat; |
288 | 288 | int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); |
... | ... | @@ -334,7 +334,8 @@ |
334 | 334 | /* nf_conntrack_alter_reply might re-allocate exntension aera */ |
335 | 335 | nat = nfct_nat(ct); |
336 | 336 | nat->ct = ct; |
337 | - hlist_add_head_rcu(&nat->bysource, &bysource[srchash]); | |
337 | + hlist_add_head_rcu(&nat->bysource, | |
338 | + &net->ipv4.nat_bysource[srchash]); | |
338 | 339 | spin_unlock_bh(&nf_nat_lock); |
339 | 340 | } |
340 | 341 | |
... | ... | @@ -583,6 +584,40 @@ |
583 | 584 | .flags = NF_CT_EXT_F_PREALLOC, |
584 | 585 | }; |
585 | 586 | |
587 | +static int __net_init nf_nat_net_init(struct net *net) | |
588 | +{ | |
589 | + net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, | |
590 | + &net->ipv4.nat_vmalloced); | |
591 | + if (!net->ipv4.nat_bysource) | |
592 | + return -ENOMEM; | |
593 | + return 0; | |
594 | +} | |
595 | + | |
596 | +/* Clear NAT section of all conntracks, in case we're loaded again. */ | |
597 | +static int clean_nat(struct nf_conn *i, void *data) | |
598 | +{ | |
599 | + struct nf_conn_nat *nat = nfct_nat(i); | |
600 | + | |
601 | + if (!nat) | |
602 | + return 0; | |
603 | + memset(nat, 0, sizeof(*nat)); | |
604 | + i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST); | |
605 | + return 0; | |
606 | +} | |
607 | + | |
608 | +static void __net_exit nf_nat_net_exit(struct net *net) | |
609 | +{ | |
610 | + nf_ct_iterate_cleanup(net, &clean_nat, NULL); | |
611 | + synchronize_rcu(); | |
612 | + nf_ct_free_hashtable(net->ipv4.nat_bysource, net->ipv4.nat_vmalloced, | |
613 | + nf_nat_htable_size); | |
614 | +} | |
615 | + | |
616 | +static struct pernet_operations nf_nat_net_ops = { | |
617 | + .init = nf_nat_net_init, | |
618 | + .exit = nf_nat_net_exit, | |
619 | +}; | |
620 | + | |
586 | 621 | static int __init nf_nat_init(void) |
587 | 622 | { |
588 | 623 | size_t i; |
589 | 624 | |
... | ... | @@ -599,12 +634,9 @@ |
599 | 634 | /* Leave them the same for the moment. */ |
600 | 635 | nf_nat_htable_size = nf_conntrack_htable_size; |
601 | 636 | |
602 | - bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, | |
603 | - &nf_nat_vmalloced); | |
604 | - if (!bysource) { | |
605 | - ret = -ENOMEM; | |
637 | + ret = register_pernet_subsys(&nf_nat_net_ops); | |
638 | + if (ret < 0) | |
606 | 639 | goto cleanup_extend; |
607 | - } | |
608 | 640 | |
609 | 641 | /* Sew in builtin protocols. */ |
610 | 642 | spin_lock_bh(&nf_nat_lock); |
611 | 643 | |
... | ... | @@ -629,23 +661,9 @@ |
629 | 661 | return ret; |
630 | 662 | } |
631 | 663 | |
632 | -/* Clear NAT section of all conntracks, in case we're loaded again. */ | |
633 | -static int clean_nat(struct nf_conn *i, void *data) | |
634 | -{ | |
635 | - struct nf_conn_nat *nat = nfct_nat(i); | |
636 | - | |
637 | - if (!nat) | |
638 | - return 0; | |
639 | - memset(nat, 0, sizeof(*nat)); | |
640 | - i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST); | |
641 | - return 0; | |
642 | -} | |
643 | - | |
644 | 664 | static void __exit nf_nat_cleanup(void) |
645 | 665 | { |
646 | - nf_ct_iterate_cleanup(&init_net, &clean_nat, NULL); | |
647 | - synchronize_rcu(); | |
648 | - nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size); | |
666 | + unregister_pernet_subsys(&nf_nat_net_ops); | |
649 | 667 | nf_ct_l3proto_put(l3proto); |
650 | 668 | nf_ct_extend_unregister(&nat_extend); |
651 | 669 | rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL); |