summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@aristanetworks.com>2008-12-29 18:21:48 -0800
committerDavid S. Miller <davem@davemloft.net>2008-12-29 18:21:48 -0800
commit8eb79863962bbf18ebf648335e329bfd468432fa (patch)
treebd700ccdbed8aee9c36d9a20d139fe577cda766a
parent91b208c7c1db4cefa2247f8243fbda75b0472d24 (diff)
downloadlinux-8eb79863962bbf18ebf648335e329bfd468432fa.tar.gz
linux-8eb79863962bbf18ebf648335e329bfd468432fa.tar.bz2
linux-8eb79863962bbf18ebf648335e329bfd468432fa.zip
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: Eric W. Biederman <ebiederm@aristanetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/core/dev.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 446424027d24..09c66a449da6 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5066,13 +5066,14 @@ static struct pernet_operations __net_initdata netdev_net_ops = {
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
* initial network namespace
*/
rtnl_lock();
- for_each_netdev_safe(net, dev, next) {
+restart:
+ for_each_netdev(net, dev) {
int err;
char fb_name[IFNAMSIZ];
@@ -5083,7 +5084,7 @@ static void __net_exit default_device_exit(struct net *net)
/* Delete virtual devices */
if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) {
dev->rtnl_link_ops->dellink(dev);
- continue;
+ goto restart;
}
/* Push remaing network devices to init_net */
@@ -5094,6 +5095,7 @@ static void __net_exit default_device_exit(struct net *net)
__func__, dev->name, err);
BUG();
}
+ goto restart;
}
rtnl_unlock();
}