diff options
author | Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp> | 2007-07-07 22:24:28 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-10 22:17:20 -0700 |
commit | 2d59e5ca8c7113ad91452f0f9259a4b55ee90323 (patch) | |
tree | 16ffd5284bb5462eaa3af285977389afefca54ca /net/ipv4 | |
parent | e54cbc1f91dea4f98b6209e693d3b5eae46321bd (diff) | |
download | linux-2d59e5ca8c7113ad91452f0f9259a4b55ee90323.tar.gz linux-2d59e5ca8c7113ad91452f0f9259a4b55ee90323.tar.bz2 linux-2d59e5ca8c7113ad91452f0f9259a4b55ee90323.zip |
[NETFILTER]: nf_nat: use extension infrastructure
Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 3 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_core.c | 60 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_standalone.c | 21 |
3 files changed, 65 insertions, 19 deletions
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 6dc72a815f77..96f641d07a40 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -108,9 +108,6 @@ EXPORT_SYMBOL_GPL(nf_nat_module_is_loaded); static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) { - if (nf_nat_module_is_loaded) - return NF_CT_F_NAT; - return NF_CT_F_BASIC; } diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index ac7e8abbbdeb..4ce82d7014ff 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -297,11 +297,21 @@ nf_nat_setup_info(struct nf_conn *ct, unsigned int hooknum) { struct nf_conntrack_tuple curr_tuple, new_tuple; - struct nf_conn_nat *nat = nfct_nat(ct); - struct nf_nat_info *info = &nat->info; + struct nf_conn_nat *nat; + struct nf_nat_info *info; int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); + /* nat helper or nfctnetlink also setup binding */ + nat = nfct_nat(ct); + if (!nat) { + nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); + if (nat == NULL) { + DEBUGP("failed to add NAT extension\n"); + return NF_ACCEPT; + } + } + NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_POST_ROUTING || hooknum == NF_IP_LOCAL_IN || @@ -338,6 +348,8 @@ nf_nat_setup_info(struct nf_conn *ct, srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); write_lock_bh(&nf_nat_lock); + /* nf_conntrack_alter_reply might re-allocate exntension aera */ + info = &nfct_nat(ct)->info; info->ct = ct; list_add(&info->bysource, &bysource[srchash]); write_unlock_bh(&nf_nat_lock); @@ -592,17 +604,52 @@ nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_nat_range *range) EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr); #endif +static void nf_nat_move_storage(struct nf_conn *conntrack, void *old) +{ + struct nf_conn_nat *new_nat = nf_ct_ext_find(conntrack, NF_CT_EXT_NAT); + struct nf_conn_nat *old_nat = (struct nf_conn_nat *)old; + struct nf_conn *ct = old_nat->info.ct; + unsigned int srchash; + + if (!(ct->status & IPS_NAT_DONE_MASK)) + return; + + srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + + write_lock_bh(&nf_nat_lock); + list_replace(&old_nat->info.bysource, &new_nat->info.bysource); + new_nat->info.ct = ct; + write_unlock_bh(&nf_nat_lock); +} + +struct nf_ct_ext_type nat_extend = { + .len = sizeof(struct nf_conn_nat), + .align = __alignof__(struct nf_conn_nat), + .move = nf_nat_move_storage, + .id = NF_CT_EXT_NAT, + .flags = NF_CT_EXT_F_PREALLOC, +}; + static int __init nf_nat_init(void) { size_t i; + int ret; + + ret = nf_ct_extend_register(&nat_extend); + if (ret < 0) { + printk(KERN_ERR "nf_nat_core: Unable to register extension\n"); + return ret; + } /* Leave them the same for the moment. */ nf_nat_htable_size = nf_conntrack_htable_size; /* One vmalloc for both hash tables */ bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size); - if (!bysource) - return -ENOMEM; + if (!bysource) { + ret = -ENOMEM; + goto cleanup_extend; + } /* Sew in builtin protocols. */ write_lock_bh(&nf_nat_lock); @@ -626,6 +673,10 @@ static int __init nf_nat_init(void) l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); return 0; + + cleanup_extend: + nf_ct_extend_unregister(&nat_extend); + return ret; } /* Clear NAT section of all conntracks, in case we're loaded again. */ @@ -647,6 +698,7 @@ static void __exit nf_nat_cleanup(void) synchronize_rcu(); vfree(bysource); nf_ct_l3proto_put(l3proto); + nf_ct_extend_unregister(&nat_extend); } MODULE_LICENSE("GPL"); diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index 0b2f0c33f7cd..51a2708f7bf0 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -19,6 +19,7 @@ #include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack_core.h> +#include <net/netfilter/nf_conntrack_extend.h> #include <net/netfilter/nf_nat.h> #include <net/netfilter/nf_nat_rule.h> #include <net/netfilter/nf_nat_protocol.h> @@ -113,8 +114,13 @@ nf_nat_fn(unsigned int hooknum, return NF_ACCEPT; nat = nfct_nat(ct); - if (!nat) - return NF_ACCEPT; + if (!nat) { + nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); + if (nat == NULL) { + DEBUGP("failed to add NAT extension\n"); + return NF_ACCEPT; + } + } switch (ctinfo) { case IP_CT_RELATED: @@ -326,18 +332,10 @@ static struct nf_hook_ops nf_nat_ops[] = { static int __init nf_nat_standalone_init(void) { - int size, ret = 0; + int ret = 0; need_conntrack(); - size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_nat)) + - sizeof(struct nf_conn_nat); - ret = nf_conntrack_register_cache(NF_CT_F_NAT, "nf_nat:base", size); - if (ret < 0) { - printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); - return ret; - } - #ifdef CONFIG_XFRM BUG_ON(ip_nat_decode_session != NULL); ip_nat_decode_session = nat_decode_session; @@ -362,7 +360,6 @@ static int __init nf_nat_standalone_init(void) ip_nat_decode_session = NULL; synchronize_net(); #endif - nf_conntrack_unregister_cache(NF_CT_F_NAT); return ret; } |