aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-09-12 07:53:49 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:49:12 -0400
commitce286d327341295f58d89864d746a524287cfdf9 (patch)
treeee7241e7504333cc4cf647ede551248268f865c4
parentb267b179648e46ea8e2a44f7314a23eb6aee1d6c (diff)
[NET]: Implement network device movement between namespaces
This patch introduces NETIF_F_NETNS_LOCAL a flag to indicate a network device is local to a single network namespace and should never be moved. Useful for pseudo devices that we need an instance in each network namespace (like the loopback device) and for any device we find that cannot handle multiple network namespaces so we may trap them in the initial network namespace. This patch introduces the function dev_change_net_namespace a function used to move a network device from one network namespace to another. To the network device nothing special appears to happen, to the components of the network stack it appears as if the network device was unregistered in the network namespace it is in, and a new device was registered in the network namespace the device was moved to. This patch sets up a namespace device destructor that upon the exit of a network namespace moves all of the movable network devices to the initial network namespace so they are not lost. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/loopback.c3
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--net/core/dev.c189
3 files changed, 184 insertions, 11 deletions
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 5106c2328d12..e399f7b201e3 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -222,7 +222,8 @@ struct net_device loopback_dev = {
222 | NETIF_F_TSO 222 | NETIF_F_TSO
223#endif 223#endif
224 | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA 224 | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA
225 | NETIF_F_LLTX, 225 | NETIF_F_LLTX
226 | NETIF_F_NETNS_LOCAL,
226 .ethtool_ops = &loopback_ethtool_ops, 227 .ethtool_ops = &loopback_ethtool_ops,
227}; 228};
228 229
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 7353b3e1f4fc..407658c64fb6 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -449,6 +449,7 @@ struct net_device
449#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ 449#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
450#define NETIF_F_GSO 2048 /* Enable software GSO. */ 450#define NETIF_F_GSO 2048 /* Enable software GSO. */
451#define NETIF_F_LLTX 4096 /* LockLess TX */ 451#define NETIF_F_LLTX 4096 /* LockLess TX */
452#define NETIF_F_NETNS_LOCAL 8192 /* Does not change network namespaces */
452#define NETIF_F_MULTI_QUEUE 16384 /* Has multiple TX/RX queues */ 453#define NETIF_F_MULTI_QUEUE 16384 /* Has multiple TX/RX queues */
453#define NETIF_F_LRO 32768 /* large receive offload */ 454#define NETIF_F_LRO 32768 /* large receive offload */
454 455
@@ -1016,6 +1017,8 @@ extern int dev_ethtool(struct net *net, struct ifreq *);
1016extern unsigned dev_get_flags(const struct net_device *); 1017extern unsigned dev_get_flags(const struct net_device *);
1017extern int dev_change_flags(struct net_device *, unsigned); 1018extern int dev_change_flags(struct net_device *, unsigned);
1018extern int dev_change_name(struct net_device *, char *); 1019extern int dev_change_name(struct net_device *, char *);
1020extern int dev_change_net_namespace(struct net_device *,
1021 struct net *, const char *);
1019extern int dev_set_mtu(struct net_device *, int); 1022extern int dev_set_mtu(struct net_device *, int);
1020extern int dev_set_mac_address(struct net_device *, 1023extern int dev_set_mac_address(struct net_device *,
1021 struct sockaddr *); 1024 struct sockaddr *);
diff --git a/net/core/dev.c b/net/core/dev.c
index 520ef7b20862..215b8e97690a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -208,6 +208,34 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
208 return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)]; 208 return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)];
209} 209}
210 210
211/* Device list insertion */
212static int list_netdevice(struct net_device *dev)
213{
214 struct net *net = dev->nd_net;
215
216 ASSERT_RTNL();
217
218 write_lock_bh(&dev_base_lock);
219 list_add_tail(&dev->dev_list, &net->dev_base_head);
220 hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name));
221 hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex));
222 write_unlock_bh(&dev_base_lock);
223 return 0;
224}
225
226/* Device list removal */
227static void unlist_netdevice(struct net_device *dev)
228{
229 ASSERT_RTNL();
230
231 /* Unlink dev from the device chain */
232 write_lock_bh(&dev_base_lock);
233 list_del(&dev->dev_list);
234 hlist_del(&dev->name_hlist);
235 hlist_del(&dev->index_hlist);
236 write_unlock_bh(&dev_base_lock);
237}
238
211/* 239/*
212 * Our notifier list 240 * Our notifier list
213 */ 241 */
@@ -3571,12 +3599,8 @@ int register_netdevice(struct net_device *dev)
3571 set_bit(__LINK_STATE_PRESENT, &dev->state); 3599 set_bit(__LINK_STATE_PRESENT, &dev->state);
3572 3600
3573 dev_init_scheduler(dev); 3601 dev_init_scheduler(dev);
3574 write_lock_bh(&dev_base_lock);
3575 list_add_tail(&dev->dev_list, &net->dev_base_head);
3576 hlist_add_head(&dev->name_hlist, head);
3577 hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex));
3578 dev_hold(dev); 3602 dev_hold(dev);
3579 write_unlock_bh(&dev_base_lock); 3603 list_netdevice(dev);
3580 3604
3581 /* Notify protocols, that a new device appeared. */ 3605 /* Notify protocols, that a new device appeared. */
3582 ret = raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); 3606 ret = raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
@@ -3883,11 +3907,7 @@ void unregister_netdevice(struct net_device *dev)
3883 dev_close(dev); 3907 dev_close(dev);
3884 3908
3885 /* And unlink it from device chain. */ 3909 /* And unlink it from device chain. */
3886 write_lock_bh(&dev_base_lock); 3910 unlist_netdevice(dev);
3887 list_del(&dev->dev_list);
3888 hlist_del(&dev->name_hlist);
3889 hlist_del(&dev->index_hlist);
3890 write_unlock_bh(&dev_base_lock);
3891 3911
3892 dev->reg_state = NETREG_UNREGISTERING; 3912 dev->reg_state = NETREG_UNREGISTERING;
3893 3913
@@ -3945,6 +3965,122 @@ void unregister_netdev(struct net_device *dev)
3945 3965
3946EXPORT_SYMBOL(unregister_netdev); 3966EXPORT_SYMBOL(unregister_netdev);
3947 3967
3968/**
3969 * dev_change_net_namespace - move device to different nethost namespace
3970 * @dev: device
3971 * @net: network namespace
3972 * @pat: If not NULL name pattern to try if the current device name
3973 * is already taken in the destination network namespace.
3974 *
3975 * This function shuts down a device interface and moves it
3976 * to a new network namespace. On success 0 is returned, on
3977 * a failure a netagive errno code is returned.
3978 *
3979 * Callers must hold the rtnl semaphore.
3980 */
3981
3982int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat)
3983{
3984 char buf[IFNAMSIZ];
3985 const char *destname;
3986 int err;
3987
3988 ASSERT_RTNL();
3989
3990 /* Don't allow namespace local devices to be moved. */
3991 err = -EINVAL;
3992 if (dev->features & NETIF_F_NETNS_LOCAL)
3993 goto out;
3994
3995 /* Ensure the device has been registrered */
3996 err = -EINVAL;
3997 if (dev->reg_state != NETREG_REGISTERED)
3998 goto out;
3999
4000 /* Get out if there is nothing todo */
4001 err = 0;
4002 if (dev->nd_net == net)
4003 goto out;
4004
4005 /* Pick the destination device name, and ensure
4006 * we can use it in the destination network namespace.
4007 */
4008 err = -EEXIST;
4009 destname = dev->name;
4010 if (__dev_get_by_name(net, destname)) {
4011 /* We get here if we can't use the current device name */
4012 if (!pat)
4013 goto out;
4014 if (!dev_valid_name(pat))
4015 goto out;
4016 if (strchr(pat, '%')) {
4017 if (__dev_alloc_name(net, pat, buf) < 0)
4018 goto out;
4019 destname = buf;
4020 } else
4021 destname = pat;
4022 if (__dev_get_by_name(net, destname))
4023 goto out;
4024 }
4025
4026 /*
4027 * And now a mini version of register_netdevice unregister_netdevice.
4028 */
4029
4030 /* If device is running close it first. */
4031 if (dev->flags & IFF_UP)
4032 dev_close(dev);
4033
4034 /* And unlink it from device chain */
4035 err = -ENODEV;
4036 unlist_netdevice(dev);
4037
4038 synchronize_net();
4039
4040 /* Shutdown queueing discipline. */
4041 dev_shutdown(dev);
4042
4043 /* Notify protocols, that we are about to destroy
4044 this device. They should clean all the things.
4045 */
4046 call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
4047
4048 /*
4049 * Flush the unicast and multicast chains
4050 */
4051 dev_addr_discard(dev);
4052
4053 /* Actually switch the network namespace */
4054 dev->nd_net = net;
4055
4056 /* Assign the new device name */
4057 if (destname != dev->name)
4058 strcpy(dev->name, destname);
4059
4060 /* If there is an ifindex conflict assign a new one */
4061 if (__dev_get_by_index(net, dev->ifindex)) {
4062 int iflink = (dev->iflink == dev->ifindex);
4063 dev->ifindex = dev_new_index(net);
4064 if (iflink)
4065 dev->iflink = dev->ifindex;
4066 }
4067
4068 /* Fixup sysfs */
4069 err = device_rename(&dev->dev, dev->name);
4070 BUG_ON(err);
4071
4072 /* Add the device back in the hashes */
4073 list_netdevice(dev);
4074
4075 /* Notify protocols, that a new device appeared. */
4076 call_netdevice_notifiers(NETDEV_REGISTER, dev);
4077
4078 synchronize_net();
4079 err = 0;
4080out:
4081 return err;
4082}
4083
3948static int dev_cpu_callback(struct notifier_block *nfb, 4084static int dev_cpu_callback(struct notifier_block *nfb,
3949 unsigned long action, 4085 unsigned long action,
3950 void *ocpu) 4086 void *ocpu)
@@ -4177,6 +4313,36 @@ static struct pernet_operations netdev_net_ops = {
4177 .exit = netdev_exit, 4313 .exit = netdev_exit,
4178}; 4314};
4179 4315
4316static void default_device_exit(struct net *net)
4317{
4318 struct net_device *dev, *next;
4319 /*
4320 * Push all migratable of the network devices back to the
4321 * initial network namespace
4322 */
4323 rtnl_lock();
4324 for_each_netdev_safe(net, dev, next) {
4325 int err;
4326
4327 /* Ignore unmoveable devices (i.e. loopback) */
4328 if (dev->features & NETIF_F_NETNS_LOCAL)
4329 continue;
4330
4331 /* Push remaing network devices to init_net */
4332 err = dev_change_net_namespace(dev, &init_net, "dev%d");
4333 if (err) {
4334 printk(KERN_WARNING "%s: failed to move %s to init_net: %d\n",
4335 __func__, dev->name, err);
4336 unregister_netdevice(dev);
4337 }
4338 }
4339 rtnl_unlock();
4340}
4341
4342static struct pernet_operations default_device_ops = {
4343 .exit = default_device_exit,
4344};
4345
4180/* 4346/*
4181 * Initialize the DEV module. At boot time this walks the device list and 4347 * Initialize the DEV module. At boot time this walks the device list and
4182 * unhooks any devices that fail to initialise (normally hardware not 4348 * unhooks any devices that fail to initialise (normally hardware not
@@ -4207,6 +4373,9 @@ static int __init net_dev_init(void)
4207 if (register_pernet_subsys(&netdev_net_ops)) 4373 if (register_pernet_subsys(&netdev_net_ops))
4208 goto out; 4374 goto out;
4209 4375
4376 if (register_pernet_device(&default_device_ops))
4377 goto out;
4378
4210 /* 4379 /*
4211 * Initialise the packet receive queues. 4380 * Initialise the packet receive queues.
4212 */ 4381 */