netfilter: nf_conntrack: move initialization out of pernet operations

nf_conntrack initialization and cleanup codes happens in pernet
operations function. This task should be done in module_init/exit.
We can't use init_net to identify if it's the right time to initialize
or cleanup since we cannot make assumption on the order netns are
created/destroyed.

Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Gao feng 2013-01-21 22:10:24 +00:00 committed by Pablo Neira Ayuso
parent 8a454ab95e
commit f94161c1bb
3 changed files with 77 additions and 83 deletions

View File

@ -25,12 +25,16 @@ extern unsigned int nf_conntrack_in(struct net *net,
unsigned int hooknum,
struct sk_buff *skb);
extern int nf_conntrack_init(struct net *net);
extern void nf_conntrack_cleanup(struct net *net);
extern int nf_conntrack_init_net(struct net *net);
extern void nf_conntrack_cleanup_net(struct net *net);
extern int nf_conntrack_proto_init(struct net *net);
extern void nf_conntrack_proto_fini(struct net *net);
extern int nf_conntrack_init_start(void);
extern void nf_conntrack_cleanup_start(void);
extern void nf_conntrack_init_end(void);
extern void nf_conntrack_cleanup_end(void);
extern bool

View File

@ -1334,8 +1334,14 @@ static int untrack_refs(void)
return cnt;
}
static void nf_conntrack_cleanup_init_net(void)
void nf_conntrack_cleanup_start(void)
{
RCU_INIT_POINTER(ip_ct_attach, NULL);
}
void nf_conntrack_cleanup_end(void)
{
RCU_INIT_POINTER(nf_ct_destroy, NULL);
while (untrack_refs() > 0)
schedule();
@ -1344,8 +1350,18 @@ static void nf_conntrack_cleanup_init_net(void)
#endif
}
static void nf_conntrack_cleanup_net(struct net *net)
/*
* Mishearing the voices in his head, our hero wonders how he's
* supposed to kill the mall.
*/
void nf_conntrack_cleanup_net(struct net *net)
{
/*
* This makes sure all current packets have passed through
* netfilter framework. Roll on, two-stage module
* delete...
*/
synchronize_net();
i_see_dead_people:
nf_ct_iterate_cleanup(net, kill_all, NULL);
nf_ct_release_dying_list(net);
@ -1355,6 +1371,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
}
nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
nf_conntrack_proto_fini(net);
nf_conntrack_labels_fini(net);
nf_conntrack_helper_fini(net);
nf_conntrack_timeout_fini(net);
@ -1367,27 +1384,6 @@ static void nf_conntrack_cleanup_net(struct net *net)
free_percpu(net->ct.stat);
}
/* Mishearing the voices in his head, our hero wonders how he's
supposed to kill the mall. */
void nf_conntrack_cleanup(struct net *net)
{
if (net_eq(net, &init_net))
RCU_INIT_POINTER(ip_ct_attach, NULL);
/* This makes sure all current packets have passed through
netfilter framework. Roll on, two-stage module
delete... */
synchronize_net();
nf_conntrack_proto_fini(net);
nf_conntrack_cleanup_net(net);
}
void nf_conntrack_cleanup_end(void)
{
RCU_INIT_POINTER(nf_ct_destroy, NULL);
nf_conntrack_cleanup_init_net();
}
void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
{
struct hlist_nulls_head *hash;
@ -1478,7 +1474,7 @@ void nf_ct_untracked_status_or(unsigned long bits)
}
EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or);
static int nf_conntrack_init_init_net(void)
int nf_conntrack_init_start(void)
{
int max_factor = 8;
int ret, cpu;
@ -1526,6 +1522,16 @@ err_extend:
return ret;
}
void nf_conntrack_init_end(void)
{
/* For use by REJECT target */
RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach);
RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack);
/* Howto get NAT offsets */
RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
}
/*
* We need to use special "null" values, not used in hash table
*/
@ -1533,7 +1539,7 @@ err_extend:
#define DYING_NULLS_VAL ((1<<30)+1)
#define TEMPLATE_NULLS_VAL ((1<<30)+2)
static int nf_conntrack_init_net(struct net *net)
int nf_conntrack_init_net(struct net *net)
{
int ret;
@ -1592,8 +1598,13 @@ static int nf_conntrack_init_net(struct net *net)
if (ret < 0)
goto err_labels;
ret = nf_conntrack_proto_init(net);
if (ret < 0)
goto err_proto;
return 0;
err_proto:
nf_conntrack_labels_fini(net);
err_labels:
nf_conntrack_helper_fini(net);
err_helper:
@ -1622,38 +1633,3 @@ s16 (*nf_ct_nat_offset)(const struct nf_conn *ct,
enum ip_conntrack_dir dir,
u32 seq);
EXPORT_SYMBOL_GPL(nf_ct_nat_offset);
int nf_conntrack_init(struct net *net)
{
int ret;
if (net_eq(net, &init_net)) {
ret = nf_conntrack_init_init_net();
if (ret < 0)
goto out_init_net;
}
ret = nf_conntrack_proto_init(net);
if (ret < 0)
goto out_proto;
ret = nf_conntrack_init_net(net);
if (ret < 0)
goto out_net;
if (net_eq(net, &init_net)) {
/* For use by REJECT target */
RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach);
RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack);
/* Howto get NAT offsets */
RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
}
return 0;
out_net:
nf_conntrack_proto_fini(net);
out_proto:
if (net_eq(net, &init_net))
nf_conntrack_cleanup_init_net();
out_init_net:
return ret;
}

View File

@ -472,13 +472,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
{
struct ctl_table *table;
if (net_eq(net, &init_net)) {
nf_ct_netfilter_header =
register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
if (!nf_ct_netfilter_header)
goto out;
}
table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table),
GFP_KERNEL);
if (!table)
@ -502,10 +495,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
out_unregister_netfilter:
kfree(table);
out_kmemdup:
if (net_eq(net, &init_net))
unregister_net_sysctl_table(nf_ct_netfilter_header);
out:
printk(KERN_ERR "nf_conntrack: can't register to sysctl.\n");
return -ENOMEM;
}
@ -513,8 +502,6 @@ static void nf_conntrack_standalone_fini_sysctl(struct net *net)
{
struct ctl_table *table;
if (net_eq(net, &init_net))
unregister_net_sysctl_table(nf_ct_netfilter_header);
table = net->ct.sysctl_header->ctl_table_arg;
unregister_net_sysctl_table(net->ct.sysctl_header);
kfree(table);
@ -530,51 +517,78 @@ static void nf_conntrack_standalone_fini_sysctl(struct net *net)
}
#endif /* CONFIG_SYSCTL */
static int nf_conntrack_net_init(struct net *net)
static int nf_conntrack_pernet_init(struct net *net)
{
int ret;
ret = nf_conntrack_init(net);
ret = nf_conntrack_init_net(net);
if (ret < 0)
goto out_init;
ret = nf_conntrack_standalone_init_proc(net);
if (ret < 0)
goto out_proc;
net->ct.sysctl_checksum = 1;
net->ct.sysctl_log_invalid = 0;
ret = nf_conntrack_standalone_init_sysctl(net);
if (ret < 0)
goto out_sysctl;
return 0;
out_sysctl:
nf_conntrack_standalone_fini_proc(net);
out_proc:
nf_conntrack_cleanup(net);
nf_conntrack_cleanup_net(net);
out_init:
return ret;
}
static void nf_conntrack_net_exit(struct net *net)
static void nf_conntrack_pernet_exit(struct net *net)
{
nf_conntrack_standalone_fini_sysctl(net);
nf_conntrack_standalone_fini_proc(net);
nf_conntrack_cleanup(net);
nf_conntrack_cleanup_net(net);
}
static struct pernet_operations nf_conntrack_net_ops = {
.init = nf_conntrack_net_init,
.exit = nf_conntrack_net_exit,
.init = nf_conntrack_pernet_init,
.exit = nf_conntrack_pernet_exit,
};
static int __init nf_conntrack_standalone_init(void)
{
return register_pernet_subsys(&nf_conntrack_net_ops);
int ret = nf_conntrack_init_start();
if (ret < 0)
goto out_start;
nf_ct_netfilter_header =
register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
if (!nf_ct_netfilter_header)
goto out_sysctl;
ret = register_pernet_subsys(&nf_conntrack_net_ops);
if (ret < 0)
goto out_pernet;
nf_conntrack_init_end();
return 0;
out_pernet:
unregister_net_sysctl_table(nf_ct_netfilter_header);
out_sysctl:
pr_err("nf_conntrack: can't register to sysctl.\n");
nf_conntrack_cleanup_end();
out_start:
return ret;
}
static void __exit nf_conntrack_standalone_fini(void)
{
nf_conntrack_cleanup_start();
unregister_pernet_subsys(&nf_conntrack_net_ops);
unregister_net_sysctl_table(nf_ct_netfilter_header);
nf_conntrack_cleanup_end();
}