Commit 64bc1781 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

ipv4: speedup ipv6 tunnels dismantle

Implement exit_batch() method to dismantle more devices
per round.

(rtnl_lock() ...
 unregister_netdevice_many() ...
 rtnl_unlock())

Tested:
$ cat add_del_unshare.sh
for i in `seq 1 40`
do
 (for j in `seq 1 100` ; do unshare -n /bin/true >/dev/null ; done) &
done
wait ; grep net_namespace /proc/slabinfo

Before patch :
$ time ./add_del_unshare.sh
net_namespace        126    282   5504    1    2 : tunables    8    4    0 : slabdata    126    282      0

real    1m38.965s
user    0m0.688s
sys     0m37.017s

After patch:
$ time ./add_del_unshare.sh
net_namespace        135    291   5504    1    2 : tunables    8    4    0 : slabdata    135    291      0

real	0m22.117s
user	0m0.728s
sys	0m35.328s
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bb401cae
...@@ -258,7 +258,8 @@ int ip_tunnel_get_iflink(const struct net_device *dev); ...@@ -258,7 +258,8 @@ int ip_tunnel_get_iflink(const struct net_device *dev);
int ip_tunnel_init_net(struct net *net, unsigned int ip_tnl_net_id, int ip_tunnel_init_net(struct net *net, unsigned int ip_tnl_net_id,
struct rtnl_link_ops *ops, char *devname); struct rtnl_link_ops *ops, char *devname);
void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops); void ip_tunnel_delete_nets(struct list_head *list_net, unsigned int id,
struct rtnl_link_ops *ops);
void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
const struct iphdr *tnl_params, const u8 protocol); const struct iphdr *tnl_params, const u8 protocol);
......
...@@ -1013,15 +1013,14 @@ static int __net_init ipgre_init_net(struct net *net) ...@@ -1013,15 +1013,14 @@ static int __net_init ipgre_init_net(struct net *net)
return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL); return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL);
} }
static void __net_exit ipgre_exit_net(struct net *net) static void __net_exit ipgre_exit_batch_net(struct list_head *list_net)
{ {
struct ip_tunnel_net *itn = net_generic(net, ipgre_net_id); ip_tunnel_delete_nets(list_net, ipgre_net_id, &ipgre_link_ops);
ip_tunnel_delete_net(itn, &ipgre_link_ops);
} }
static struct pernet_operations ipgre_net_ops = { static struct pernet_operations ipgre_net_ops = {
.init = ipgre_init_net, .init = ipgre_init_net,
.exit = ipgre_exit_net, .exit_batch = ipgre_exit_batch_net,
.id = &ipgre_net_id, .id = &ipgre_net_id,
.size = sizeof(struct ip_tunnel_net), .size = sizeof(struct ip_tunnel_net),
}; };
...@@ -1540,15 +1539,14 @@ static int __net_init ipgre_tap_init_net(struct net *net) ...@@ -1540,15 +1539,14 @@ static int __net_init ipgre_tap_init_net(struct net *net)
return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0"); return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0");
} }
static void __net_exit ipgre_tap_exit_net(struct net *net) static void __net_exit ipgre_tap_exit_batch_net(struct list_head *list_net)
{ {
struct ip_tunnel_net *itn = net_generic(net, gre_tap_net_id); ip_tunnel_delete_nets(list_net, gre_tap_net_id, &ipgre_tap_ops);
ip_tunnel_delete_net(itn, &ipgre_tap_ops);
} }
static struct pernet_operations ipgre_tap_net_ops = { static struct pernet_operations ipgre_tap_net_ops = {
.init = ipgre_tap_init_net, .init = ipgre_tap_init_net,
.exit = ipgre_tap_exit_net, .exit_batch = ipgre_tap_exit_batch_net,
.id = &gre_tap_net_id, .id = &gre_tap_net_id,
.size = sizeof(struct ip_tunnel_net), .size = sizeof(struct ip_tunnel_net),
}; };
...@@ -1559,16 +1557,14 @@ static int __net_init erspan_init_net(struct net *net) ...@@ -1559,16 +1557,14 @@ static int __net_init erspan_init_net(struct net *net)
&erspan_link_ops, "erspan0"); &erspan_link_ops, "erspan0");
} }
static void __net_exit erspan_exit_net(struct net *net) static void __net_exit erspan_exit_batch_net(struct list_head *net_list)
{ {
struct ip_tunnel_net *itn = net_generic(net, erspan_net_id); ip_tunnel_delete_nets(net_list, erspan_net_id, &erspan_link_ops);
ip_tunnel_delete_net(itn, &erspan_link_ops);
} }
static struct pernet_operations erspan_net_ops = { static struct pernet_operations erspan_net_ops = {
.init = erspan_init_net, .init = erspan_init_net,
.exit = erspan_exit_net, .exit_batch = erspan_exit_batch_net,
.id = &erspan_net_id, .id = &erspan_net_id,
.size = sizeof(struct ip_tunnel_net), .size = sizeof(struct ip_tunnel_net),
}; };
......
...@@ -1061,16 +1061,22 @@ static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head, ...@@ -1061,16 +1061,22 @@ static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head,
} }
} }
void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops) void ip_tunnel_delete_nets(struct list_head *net_list, unsigned int id,
struct rtnl_link_ops *ops)
{ {
struct ip_tunnel_net *itn;
struct net *net;
LIST_HEAD(list); LIST_HEAD(list);
rtnl_lock(); rtnl_lock();
ip_tunnel_destroy(itn, &list, ops); list_for_each_entry(net, net_list, exit_list) {
itn = net_generic(net, id);
ip_tunnel_destroy(itn, &list, ops);
}
unregister_netdevice_many(&list); unregister_netdevice_many(&list);
rtnl_unlock(); rtnl_unlock();
} }
EXPORT_SYMBOL_GPL(ip_tunnel_delete_net); EXPORT_SYMBOL_GPL(ip_tunnel_delete_nets);
int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
struct ip_tunnel_parm *p, __u32 fwmark) struct ip_tunnel_parm *p, __u32 fwmark)
......
...@@ -452,15 +452,14 @@ static int __net_init vti_init_net(struct net *net) ...@@ -452,15 +452,14 @@ static int __net_init vti_init_net(struct net *net)
return 0; return 0;
} }
static void __net_exit vti_exit_net(struct net *net) static void __net_exit vti_exit_batch_net(struct list_head *list_net)
{ {
struct ip_tunnel_net *itn = net_generic(net, vti_net_id); ip_tunnel_delete_nets(list_net, vti_net_id, &vti_link_ops);
ip_tunnel_delete_net(itn, &vti_link_ops);
} }
static struct pernet_operations vti_net_ops = { static struct pernet_operations vti_net_ops = {
.init = vti_init_net, .init = vti_init_net,
.exit = vti_exit_net, .exit_batch = vti_exit_batch_net,
.id = &vti_net_id, .id = &vti_net_id,
.size = sizeof(struct ip_tunnel_net), .size = sizeof(struct ip_tunnel_net),
}; };
......
...@@ -634,15 +634,14 @@ static int __net_init ipip_init_net(struct net *net) ...@@ -634,15 +634,14 @@ static int __net_init ipip_init_net(struct net *net)
return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0"); return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0");
} }
static void __net_exit ipip_exit_net(struct net *net) static void __net_exit ipip_exit_batch_net(struct list_head *list_net)
{ {
struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); ip_tunnel_delete_nets(list_net, ipip_net_id, &ipip_link_ops);
ip_tunnel_delete_net(itn, &ipip_link_ops);
} }
static struct pernet_operations ipip_net_ops = { static struct pernet_operations ipip_net_ops = {
.init = ipip_init_net, .init = ipip_init_net,
.exit = ipip_exit_net, .exit_batch = ipip_exit_batch_net,
.id = &ipip_net_id, .id = &ipip_net_id,
.size = sizeof(struct ip_tunnel_net), .size = sizeof(struct ip_tunnel_net),
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment