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

Commit dece40e8 authored by Vladimir Davydov's avatar Vladimir Davydov Committed by Pablo Neira Ayuso
Browse files

netfilter: nf_conntrack: speed up module removal path if netns in use



The patch introduces nf_conntrack_cleanup_net_list(), which cleanups
nf_conntrack for a list of netns and calls synchronize_net() only once
for them all. This should reduce netns destruction time.

I've measured cleanup time for 1k dummy net ns. Here are the results:

 <without the patch>
 # modprobe nf_conntrack
 # time modprobe -r nf_conntrack

 real	0m10.337s
 user	0m0.000s
 sys	0m0.376s

 <with the patch>
 # modprobe nf_conntrack
 # time modprobe -r nf_conntrack

 real    0m5.661s
 user    0m0.000s
 sys     0m0.216s

Signed-off-by: default avatarVladimir Davydov <vdavydov@parallels.com>
Cc: Patrick McHardy <kaber@trash.net>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Acked-by: default avatarGao feng <gaofeng@cn.fujitsu.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 49376368
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ extern unsigned int nf_conntrack_in(struct net *net,

extern int nf_conntrack_init_net(struct net *net);
extern void nf_conntrack_cleanup_net(struct net *net);
extern void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list);

extern int nf_conntrack_proto_pernet_init(struct net *net);
extern void nf_conntrack_proto_pernet_fini(struct net *net);
+32 −14
Original line number Diff line number Diff line
@@ -1365,6 +1365,17 @@ void nf_conntrack_cleanup_end(void)
 */
void nf_conntrack_cleanup_net(struct net *net)
{
	LIST_HEAD(single);

	list_add(&net->exit_list, &single);
	nf_conntrack_cleanup_net_list(&single);
}

void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list)
{
	int busy;
	struct net *net;

	/*
	 * This makes sure all current packets have passed through
	 *  netfilter framework.  Roll on, two-stage module
@@ -1372,13 +1383,19 @@ void nf_conntrack_cleanup_net(struct net *net)
	 */
	synchronize_net();
i_see_dead_people:
	busy = 0;
	list_for_each_entry(net, net_exit_list, exit_list) {
		nf_ct_iterate_cleanup(net, kill_all, NULL);
		nf_ct_release_dying_list(net);
	if (atomic_read(&net->ct.count) != 0) {
		if (atomic_read(&net->ct.count) != 0)
			busy = 1;
	}
	if (busy) {
		schedule();
		goto i_see_dead_people;
	}

	list_for_each_entry(net, net_exit_list, exit_list) {
		nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
		nf_conntrack_proto_pernet_fini(net);
		nf_conntrack_helper_pernet_fini(net);
@@ -1390,6 +1407,7 @@ void nf_conntrack_cleanup_net(struct net *net)
		kfree(net->ct.slabname);
		free_percpu(net->ct.stat);
	}
}

void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
{
+10 −6
Original line number Diff line number Diff line
@@ -545,16 +545,20 @@ static int nf_conntrack_pernet_init(struct net *net)
	return ret;
}

static void nf_conntrack_pernet_exit(struct net *net)
static void nf_conntrack_pernet_exit(struct list_head *net_exit_list)
{
	struct net *net;

	list_for_each_entry(net, net_exit_list, exit_list) {
		nf_conntrack_standalone_fini_sysctl(net);
		nf_conntrack_standalone_fini_proc(net);
	nf_conntrack_cleanup_net(net);
	}
	nf_conntrack_cleanup_net_list(net_exit_list);
}

static struct pernet_operations nf_conntrack_net_ops = {
	.init		= nf_conntrack_pernet_init,
	.exit = nf_conntrack_pernet_exit,
	.exit_batch	= nf_conntrack_pernet_exit,
};

static int __init nf_conntrack_standalone_init(void)