diff options
author | Eric W. Biederman <ebiederm@aristanetworks.com> | 2009-01-21 19:02:16 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-01-21 19:02:16 -0500 |
commit | f019a7a594d951f085eb3878c3d825556d447efe (patch) | |
tree | 9abbe6c51ef39a4b9ab3b06dbc71c415ca443b4e /drivers | |
parent | aec191aa2a04b082238156dc9690fff8ce95dd6b (diff) |
tun: Implement ip link del tunXXX
This greatly simplifies testing to verify I have fixed the problems
with a tun device disappearing when the tun file descriptor is still
held open.
Further it allows removal network namespace operations for the tun
driver. Reducing the network namespace handling in the driver to the
minimum. i.e. When we are creating a tun device.
Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/tun.c | 56 |
1 files changed, 25 insertions, 31 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 97b050015f5e..e9bcbdfe015a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -63,6 +63,7 @@ | |||
63 | #include <linux/virtio_net.h> | 63 | #include <linux/virtio_net.h> |
64 | #include <net/net_namespace.h> | 64 | #include <net/net_namespace.h> |
65 | #include <net/netns/generic.h> | 65 | #include <net/netns/generic.h> |
66 | #include <net/rtnetlink.h> | ||
66 | 67 | ||
67 | #include <asm/system.h> | 68 | #include <asm/system.h> |
68 | #include <asm/uaccess.h> | 69 | #include <asm/uaccess.h> |
@@ -812,6 +813,22 @@ static void tun_setup(struct net_device *dev) | |||
812 | dev->destructor = free_netdev; | 813 | dev->destructor = free_netdev; |
813 | } | 814 | } |
814 | 815 | ||
816 | /* Trivial set of netlink ops to allow deleting tun or tap | ||
817 | * device with netlink. | ||
818 | */ | ||
819 | static int tun_validate(struct nlattr *tb[], struct nlattr *data[]) | ||
820 | { | ||
821 | return -EINVAL; | ||
822 | } | ||
823 | |||
824 | static struct rtnl_link_ops tun_link_ops __read_mostly = { | ||
825 | .kind = DRV_NAME, | ||
826 | .priv_size = sizeof(struct tun_struct), | ||
827 | .setup = tun_setup, | ||
828 | .validate = tun_validate, | ||
829 | }; | ||
830 | |||
831 | |||
815 | static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | 832 | static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) |
816 | { | 833 | { |
817 | struct tun_struct *tun; | 834 | struct tun_struct *tun; |
@@ -861,6 +878,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
861 | return -ENOMEM; | 878 | return -ENOMEM; |
862 | 879 | ||
863 | dev_net_set(dev, net); | 880 | dev_net_set(dev, net); |
881 | dev->rtnl_link_ops = &tun_link_ops; | ||
864 | 882 | ||
865 | tun = netdev_priv(dev); | 883 | tun = netdev_priv(dev); |
866 | tun->dev = dev; | 884 | tun->dev = dev; |
@@ -1317,29 +1335,6 @@ static const struct ethtool_ops tun_ethtool_ops = { | |||
1317 | .set_rx_csum = tun_set_rx_csum | 1335 | .set_rx_csum = tun_set_rx_csum |
1318 | }; | 1336 | }; |
1319 | 1337 | ||
1320 | static int tun_init_net(struct net *net) | ||
1321 | { | ||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1325 | static void tun_exit_net(struct net *net) | ||
1326 | { | ||
1327 | struct net_device *dev, *next; | ||
1328 | |||
1329 | rtnl_lock(); | ||
1330 | for_each_netdev_safe(net, dev, next) { | ||
1331 | if (dev->ethtool_ops != &tun_ethtool_ops) | ||
1332 | continue; | ||
1333 | DBG(KERN_INFO "%s cleaned up\n", dev->name); | ||
1334 | unregister_netdevice(dev); | ||
1335 | } | ||
1336 | rtnl_unlock(); | ||
1337 | } | ||
1338 | |||
1339 | static struct pernet_operations tun_net_ops = { | ||
1340 | .init = tun_init_net, | ||
1341 | .exit = tun_exit_net, | ||
1342 | }; | ||
1343 | 1338 | ||
1344 | static int __init tun_init(void) | 1339 | static int __init tun_init(void) |
1345 | { | 1340 | { |
@@ -1348,10 +1343,10 @@ static int __init tun_init(void) | |||
1348 | printk(KERN_INFO "tun: %s, %s\n", DRV_DESCRIPTION, DRV_VERSION); | 1343 | printk(KERN_INFO "tun: %s, %s\n", DRV_DESCRIPTION, DRV_VERSION); |
1349 | printk(KERN_INFO "tun: %s\n", DRV_COPYRIGHT); | 1344 | printk(KERN_INFO "tun: %s\n", DRV_COPYRIGHT); |
1350 | 1345 | ||
1351 | ret = register_pernet_device(&tun_net_ops); | 1346 | ret = rtnl_link_register(&tun_link_ops); |
1352 | if (ret) { | 1347 | if (ret) { |
1353 | printk(KERN_ERR "tun: Can't register pernet ops\n"); | 1348 | printk(KERN_ERR "tun: Can't register link_ops\n"); |
1354 | goto err_pernet; | 1349 | goto err_linkops; |
1355 | } | 1350 | } |
1356 | 1351 | ||
1357 | ret = misc_register(&tun_miscdev); | 1352 | ret = misc_register(&tun_miscdev); |
@@ -1359,18 +1354,17 @@ static int __init tun_init(void) | |||
1359 | printk(KERN_ERR "tun: Can't register misc device %d\n", TUN_MINOR); | 1354 | printk(KERN_ERR "tun: Can't register misc device %d\n", TUN_MINOR); |
1360 | goto err_misc; | 1355 | goto err_misc; |
1361 | } | 1356 | } |
1362 | return 0; | 1357 | return 0; |
1363 | |||
1364 | err_misc: | 1358 | err_misc: |
1365 | unregister_pernet_device(&tun_net_ops); | 1359 | rtnl_link_unregister(&tun_link_ops); |
1366 | err_pernet: | 1360 | err_linkops: |
1367 | return ret; | 1361 | return ret; |
1368 | } | 1362 | } |
1369 | 1363 | ||
1370 | static void tun_cleanup(void) | 1364 | static void tun_cleanup(void) |
1371 | { | 1365 | { |
1372 | misc_deregister(&tun_miscdev); | 1366 | misc_deregister(&tun_miscdev); |
1373 | unregister_pernet_device(&tun_net_ops); | 1367 | rtnl_link_unregister(&tun_link_ops); |
1374 | } | 1368 | } |
1375 | 1369 | ||
1376 | module_init(tun_init); | 1370 | module_init(tun_init); |