diff options
author | Eric W. Biederman <ebiederm@aristanetworks.com> | 2008-12-29 18:21:48 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-29 18:21:48 -0800 |
commit | 8eb79863962bbf18ebf648335e329bfd468432fa (patch) | |
tree | bd700ccdbed8aee9c36d9a20d139fe577cda766a | |
parent | 91b208c7c1db4cefa2247f8243fbda75b0472d24 (diff) | |
download | linux-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.c | 8 |
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(); } |