diff options
| -rw-r--r-- | drivers/net/loopback.c | 3 | ||||
| -rw-r--r-- | include/linux/netdevice.h | 3 | ||||
| -rw-r--r-- | net/core/dev.c | 189 |
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 *); | |||
| 1016 | extern unsigned dev_get_flags(const struct net_device *); | 1017 | extern unsigned dev_get_flags(const struct net_device *); |
| 1017 | extern int dev_change_flags(struct net_device *, unsigned); | 1018 | extern int dev_change_flags(struct net_device *, unsigned); |
| 1018 | extern int dev_change_name(struct net_device *, char *); | 1019 | extern int dev_change_name(struct net_device *, char *); |
| 1020 | extern int dev_change_net_namespace(struct net_device *, | ||
| 1021 | struct net *, const char *); | ||
| 1019 | extern int dev_set_mtu(struct net_device *, int); | 1022 | extern int dev_set_mtu(struct net_device *, int); |
| 1020 | extern int dev_set_mac_address(struct net_device *, | 1023 | extern 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 */ | ||
| 212 | static 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 */ | ||
| 227 | static 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 | ||
| 3946 | EXPORT_SYMBOL(unregister_netdev); | 3966 | EXPORT_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 | |||
| 3982 | int 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; | ||
| 4080 | out: | ||
| 4081 | return err; | ||
| 4082 | } | ||
| 4083 | |||
| 3948 | static int dev_cpu_callback(struct notifier_block *nfb, | 4084 | static 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 | ||
| 4316 | static 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 | |||
| 4342 | static 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 | */ |
