Commit 0c4c9288 authored by Alexey Dobriyan's avatar Alexey Dobriyan Committed by Patrick McHardy

netfilter: netns nat: per-netns bysource hash

Signed-off-by: default avatarAlexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
parent e099a173
...@@ -39,6 +39,8 @@ struct netns_ipv4 { ...@@ -39,6 +39,8 @@ struct netns_ipv4 {
struct xt_table *arptable_filter; struct xt_table *arptable_filter;
struct xt_table *iptable_security; struct xt_table *iptable_security;
struct xt_table *nat_table; struct xt_table *nat_table;
struct hlist_head *nat_bysource;
int nat_vmalloced;
#endif #endif
int sysctl_icmp_echo_ignore_all; int sysctl_icmp_echo_ignore_all;
......
...@@ -37,9 +37,6 @@ static struct nf_conntrack_l3proto *l3proto __read_mostly; ...@@ -37,9 +37,6 @@ static struct nf_conntrack_l3proto *l3proto __read_mostly;
/* Calculated at init based on memory size */ /* Calculated at init based on memory size */
static unsigned int nf_nat_htable_size __read_mostly; static unsigned int nf_nat_htable_size __read_mostly;
static int nf_nat_vmalloced;
static struct hlist_head *bysource __read_mostly;
#define MAX_IP_NAT_PROTO 256 #define MAX_IP_NAT_PROTO 256
static const struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO] static const struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO]
...@@ -145,7 +142,8 @@ same_src(const struct nf_conn *ct, ...@@ -145,7 +142,8 @@ same_src(const struct nf_conn *ct,
/* Only called for SRC manip */ /* Only called for SRC manip */
static int static int
find_appropriate_src(const struct nf_conntrack_tuple *tuple, find_appropriate_src(struct net *net,
const struct nf_conntrack_tuple *tuple,
struct nf_conntrack_tuple *result, struct nf_conntrack_tuple *result,
const struct nf_nat_range *range) const struct nf_nat_range *range)
{ {
...@@ -155,7 +153,7 @@ find_appropriate_src(const struct nf_conntrack_tuple *tuple, ...@@ -155,7 +153,7 @@ find_appropriate_src(const struct nf_conntrack_tuple *tuple,
const struct hlist_node *n; const struct hlist_node *n;
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(nat, n, &bysource[h], bysource) { hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) {
ct = nat->ct; ct = nat->ct;
if (same_src(ct, tuple)) { if (same_src(ct, tuple)) {
/* Copy source part from reply tuple. */ /* Copy source part from reply tuple. */
...@@ -231,6 +229,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, ...@@ -231,6 +229,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
struct nf_conn *ct, struct nf_conn *ct,
enum nf_nat_manip_type maniptype) enum nf_nat_manip_type maniptype)
{ {
struct net *net = nf_ct_net(ct);
const struct nf_nat_protocol *proto; const struct nf_nat_protocol *proto;
/* 1) If this srcip/proto/src-proto-part is currently mapped, /* 1) If this srcip/proto/src-proto-part is currently mapped,
...@@ -242,7 +241,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, ...@@ -242,7 +241,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
manips not an issue. */ manips not an issue. */
if (maniptype == IP_NAT_MANIP_SRC && if (maniptype == IP_NAT_MANIP_SRC &&
!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) { !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) {
if (find_appropriate_src(orig_tuple, tuple, range)) { if (find_appropriate_src(net, orig_tuple, tuple, range)) {
pr_debug("get_unique_tuple: Found current src map\n"); pr_debug("get_unique_tuple: Found current src map\n");
if (!nf_nat_used_tuple(tuple, ct)) if (!nf_nat_used_tuple(tuple, ct))
return; return;
...@@ -283,6 +282,7 @@ nf_nat_setup_info(struct nf_conn *ct, ...@@ -283,6 +282,7 @@ nf_nat_setup_info(struct nf_conn *ct,
const struct nf_nat_range *range, const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype) enum nf_nat_manip_type maniptype)
{ {
struct net *net = nf_ct_net(ct);
struct nf_conntrack_tuple curr_tuple, new_tuple; struct nf_conntrack_tuple curr_tuple, new_tuple;
struct nf_conn_nat *nat; struct nf_conn_nat *nat;
int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK);
...@@ -334,7 +334,8 @@ nf_nat_setup_info(struct nf_conn *ct, ...@@ -334,7 +334,8 @@ nf_nat_setup_info(struct nf_conn *ct,
/* nf_conntrack_alter_reply might re-allocate exntension aera */ /* nf_conntrack_alter_reply might re-allocate exntension aera */
nat = nfct_nat(ct); nat = nfct_nat(ct);
nat->ct = ct; nat->ct = ct;
hlist_add_head_rcu(&nat->bysource, &bysource[srchash]); hlist_add_head_rcu(&nat->bysource,
&net->ipv4.nat_bysource[srchash]);
spin_unlock_bh(&nf_nat_lock); spin_unlock_bh(&nf_nat_lock);
} }
...@@ -583,6 +584,40 @@ static struct nf_ct_ext_type nat_extend __read_mostly = { ...@@ -583,6 +584,40 @@ static struct nf_ct_ext_type nat_extend __read_mostly = {
.flags = NF_CT_EXT_F_PREALLOC, .flags = NF_CT_EXT_F_PREALLOC,
}; };
static int __net_init nf_nat_net_init(struct net *net)
{
net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size,
&net->ipv4.nat_vmalloced);
if (!net->ipv4.nat_bysource)
return -ENOMEM;
return 0;
}
/* Clear NAT section of all conntracks, in case we're loaded again. */
static int clean_nat(struct nf_conn *i, void *data)
{
struct nf_conn_nat *nat = nfct_nat(i);
if (!nat)
return 0;
memset(nat, 0, sizeof(*nat));
i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
return 0;
}
static void __net_exit nf_nat_net_exit(struct net *net)
{
nf_ct_iterate_cleanup(net, &clean_nat, NULL);
synchronize_rcu();
nf_ct_free_hashtable(net->ipv4.nat_bysource, net->ipv4.nat_vmalloced,
nf_nat_htable_size);
}
static struct pernet_operations nf_nat_net_ops = {
.init = nf_nat_net_init,
.exit = nf_nat_net_exit,
};
static int __init nf_nat_init(void) static int __init nf_nat_init(void)
{ {
size_t i; size_t i;
...@@ -599,12 +634,9 @@ static int __init nf_nat_init(void) ...@@ -599,12 +634,9 @@ static int __init nf_nat_init(void)
/* Leave them the same for the moment. */ /* Leave them the same for the moment. */
nf_nat_htable_size = nf_conntrack_htable_size; nf_nat_htable_size = nf_conntrack_htable_size;
bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, ret = register_pernet_subsys(&nf_nat_net_ops);
&nf_nat_vmalloced); if (ret < 0)
if (!bysource) {
ret = -ENOMEM;
goto cleanup_extend; goto cleanup_extend;
}
/* Sew in builtin protocols. */ /* Sew in builtin protocols. */
spin_lock_bh(&nf_nat_lock); spin_lock_bh(&nf_nat_lock);
...@@ -629,23 +661,9 @@ static int __init nf_nat_init(void) ...@@ -629,23 +661,9 @@ static int __init nf_nat_init(void)
return ret; return ret;
} }
/* Clear NAT section of all conntracks, in case we're loaded again. */
static int clean_nat(struct nf_conn *i, void *data)
{
struct nf_conn_nat *nat = nfct_nat(i);
if (!nat)
return 0;
memset(nat, 0, sizeof(*nat));
i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
return 0;
}
static void __exit nf_nat_cleanup(void) static void __exit nf_nat_cleanup(void)
{ {
nf_ct_iterate_cleanup(&init_net, &clean_nat, NULL); unregister_pernet_subsys(&nf_nat_net_ops);
synchronize_rcu();
nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size);
nf_ct_l3proto_put(l3proto); nf_ct_l3proto_put(l3proto);
nf_ct_extend_unregister(&nat_extend); nf_ct_extend_unregister(&nat_extend);
rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL); rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment