Skip to content

Commit

Permalink
netfilter: nf_conntrack: move initialization out of pernet operations
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Gao feng authored and Pablo Neira Ayuso committed Jan 23, 2013
1 parent 8a454ab commit f94161c
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 83 deletions.
8 changes: 6 additions & 2 deletions include/net/netfilter/nf_conntrack_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
96 changes: 36 additions & 60 deletions net/netfilter/nf_conntrack_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1526,14 +1522,24 @@ static int nf_conntrack_init_init_net(void)
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
*/
#define UNCONFIRMED_NULLS_VAL ((1<<30)+0)
#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;

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
}
56 changes: 35 additions & 21 deletions net/netfilter/nf_conntrack_standalone.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -502,19 +495,13 @@ 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;
}

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);
Expand All @@ -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();
}

Expand Down

0 comments on commit f94161c

Please sign in to comment.