Commit 8eb79863 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by David S. Miller

netns: foreach_netdev_safe is insufficient in default_device_exit

During network namespace teardown we either move or delete
all of the network devices associated with a network namespace.
In the case of veth devices deleting one will also delete it's
pair device.  If both devices are in the same network namespace
then for_each_netdev_safe is insufficient as next may point
to the second veth device we have deleted.

To avoid problems I do what we do in __rtnl_kill_links and
restart the scan of the device list, after we have deleted
a device.

Currently dev_change_netnamespace does not appear to suffer from
this problem, but wireless devices are also paired and likely
should be moved between network namespaces together.  So I have
errored on the side of caution and restart the scan of the network
devices in that case as well.
Signed-off-by: default avatarEric W. Biederman <ebiederm@aristanetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 91b208c7
...@@ -5066,13 +5066,14 @@ static struct pernet_operations __net_initdata netdev_net_ops = { ...@@ -5066,13 +5066,14 @@ static struct pernet_operations __net_initdata netdev_net_ops = {
static void __net_exit default_device_exit(struct net *net) static void __net_exit default_device_exit(struct net *net)
{ {
struct net_device *dev, *next; struct net_device *dev;
/* /*
* Push all migratable of the network devices back to the * Push all migratable of the network devices back to the
* initial network namespace * initial network namespace
*/ */
rtnl_lock(); rtnl_lock();
for_each_netdev_safe(net, dev, next) { restart:
for_each_netdev(net, dev) {
int err; int err;
char fb_name[IFNAMSIZ]; char fb_name[IFNAMSIZ];
...@@ -5083,7 +5084,7 @@ static void __net_exit default_device_exit(struct net *net) ...@@ -5083,7 +5084,7 @@ static void __net_exit default_device_exit(struct net *net)
/* Delete virtual devices */ /* Delete virtual devices */
if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) { if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) {
dev->rtnl_link_ops->dellink(dev); dev->rtnl_link_ops->dellink(dev);
continue; goto restart;
} }
/* Push remaing network devices to init_net */ /* Push remaing network devices to init_net */
...@@ -5094,6 +5095,7 @@ static void __net_exit default_device_exit(struct net *net) ...@@ -5094,6 +5095,7 @@ static void __net_exit default_device_exit(struct net *net)
__func__, dev->name, err); __func__, dev->name, err);
BUG(); BUG();
} }
goto restart;
} }
rtnl_unlock(); rtnl_unlock();
} }
......
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