Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f94161c1 authored by Gao feng's avatar Gao feng Committed by Pablo Neira Ayuso
Browse files

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: default avatarGao feng <gaofeng@cn.fujitsu.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 8a454ab9
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -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
+36 −60
Original line number Diff line number Diff line
@@ -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;
}
+35 −21
Original line number Diff line number Diff line
@@ -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();
}