aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@aristanetworks.com>2008-12-29 21:21:48 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-29 21:21:48 -0500
commit8eb79863962bbf18ebf648335e329bfd468432fa (patch)
treebd700ccdbed8aee9c36d9a20d139fe577cda766a
parent91b208c7c1db4cefa2247f8243fbda75b0472d24 (diff)
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 = {
5066 5066
5067static void __net_exit default_device_exit(struct net *net) 5067static void __net_exit default_device_exit(struct net *net)
5068{ 5068{
5069 struct net_device *dev, *next; 5069 struct net_device *dev;
5070 /* 5070 /*
5071 * Push all migratable of the network devices back to the 5071 * Push all migratable of the network devices back to the
5072 * initial network namespace 5072 * initial network namespace
5073 */ 5073 */
5074 rtnl_lock(); 5074 rtnl_lock();
5075 for_each_netdev_safe(net, dev, next) { 5075restart:
5076 for_each_netdev(net, dev) {
5076 int err; 5077 int err;
5077 char fb_name[IFNAMSIZ]; 5078 char fb_name[IFNAMSIZ];
5078 5079
@@ -5083,7 +5084,7 @@ static void __net_exit default_device_exit(struct net *net)
5083 /* Delete virtual devices */ 5084 /* Delete virtual devices */
5084 if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) { 5085 if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) {
5085 dev->rtnl_link_ops->dellink(dev); 5086 dev->rtnl_link_ops->dellink(dev);
5086 continue; 5087 goto restart;
5087 } 5088 }
5088 5089
5089 /* Push remaing network devices to init_net */ 5090 /* Push remaing network devices to init_net */
@@ -5094,6 +5095,7 @@ static void __net_exit default_device_exit(struct net *net)
5094 __func__, dev->name, err); 5095 __func__, dev->name, err);
5095 BUG(); 5096 BUG();
5096 } 5097 }
5098 goto restart;
5097 } 5099 }
5098 rtnl_unlock(); 5100 rtnl_unlock();
5099} 5101}