diff options
Diffstat (limited to 'net/ipv6/ip6_tunnel.c')
| -rw-r--r-- | net/ipv6/ip6_tunnel.c | 63 |
1 files changed, 34 insertions, 29 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 511a6c416887..7d2aa6e772ac 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
| @@ -84,13 +84,12 @@ static int ip6_tnl_net_id; | |||
| 84 | struct ip6_tnl_net { | 84 | struct ip6_tnl_net { |
| 85 | /* the IPv6 tunnel fallback device */ | 85 | /* the IPv6 tunnel fallback device */ |
| 86 | struct net_device *fb_tnl_dev; | 86 | struct net_device *fb_tnl_dev; |
| 87 | /* lists for storing tunnels in use */ | ||
| 88 | struct ip6_tnl *tnls_r_l[HASH_SIZE]; | ||
| 89 | struct ip6_tnl *tnls_wc[1]; | ||
| 90 | struct ip6_tnl **tnls[2]; | ||
| 87 | }; | 91 | }; |
| 88 | 92 | ||
| 89 | /* lists for storing tunnels in use */ | ||
| 90 | static struct ip6_tnl *tnls_r_l[HASH_SIZE]; | ||
| 91 | static struct ip6_tnl *tnls_wc[1]; | ||
| 92 | static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l }; | ||
| 93 | |||
| 94 | /* lock for the tunnel lists */ | 93 | /* lock for the tunnel lists */ |
| 95 | static DEFINE_RWLOCK(ip6_tnl_lock); | 94 | static DEFINE_RWLOCK(ip6_tnl_lock); |
| 96 | 95 | ||
| @@ -139,14 +138,15 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) | |||
| 139 | unsigned h0 = HASH(remote); | 138 | unsigned h0 = HASH(remote); |
| 140 | unsigned h1 = HASH(local); | 139 | unsigned h1 = HASH(local); |
| 141 | struct ip6_tnl *t; | 140 | struct ip6_tnl *t; |
| 141 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | ||
| 142 | 142 | ||
| 143 | for (t = tnls_r_l[h0 ^ h1]; t; t = t->next) { | 143 | for (t = ip6n->tnls_r_l[h0 ^ h1]; t; t = t->next) { |
| 144 | if (ipv6_addr_equal(local, &t->parms.laddr) && | 144 | if (ipv6_addr_equal(local, &t->parms.laddr) && |
| 145 | ipv6_addr_equal(remote, &t->parms.raddr) && | 145 | ipv6_addr_equal(remote, &t->parms.raddr) && |
| 146 | (t->dev->flags & IFF_UP)) | 146 | (t->dev->flags & IFF_UP)) |
| 147 | return t; | 147 | return t; |
| 148 | } | 148 | } |
| 149 | if ((t = tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP)) | 149 | if ((t = ip6n->tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP)) |
| 150 | return t; | 150 | return t; |
| 151 | 151 | ||
| 152 | return NULL; | 152 | return NULL; |
| @@ -175,7 +175,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) | |||
| 175 | prio = 1; | 175 | prio = 1; |
| 176 | h = HASH(remote) ^ HASH(local); | 176 | h = HASH(remote) ^ HASH(local); |
| 177 | } | 177 | } |
| 178 | return &tnls[prio][h]; | 178 | return &ip6n->tnls[prio][h]; |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | /** | 181 | /** |
| @@ -314,7 +314,7 @@ ip6_tnl_dev_uninit(struct net_device *dev) | |||
| 314 | 314 | ||
| 315 | if (dev == ip6n->fb_tnl_dev) { | 315 | if (dev == ip6n->fb_tnl_dev) { |
| 316 | write_lock_bh(&ip6_tnl_lock); | 316 | write_lock_bh(&ip6_tnl_lock); |
| 317 | tnls_wc[0] = NULL; | 317 | ip6n->tnls_wc[0] = NULL; |
| 318 | write_unlock_bh(&ip6_tnl_lock); | 318 | write_unlock_bh(&ip6_tnl_lock); |
| 319 | } else { | 319 | } else { |
| 320 | ip6_tnl_unlink(ip6n, t); | 320 | ip6_tnl_unlink(ip6n, t); |
| @@ -1378,10 +1378,13 @@ static int | |||
| 1378 | ip6_fb_tnl_dev_init(struct net_device *dev) | 1378 | ip6_fb_tnl_dev_init(struct net_device *dev) |
| 1379 | { | 1379 | { |
| 1380 | struct ip6_tnl *t = netdev_priv(dev); | 1380 | struct ip6_tnl *t = netdev_priv(dev); |
| 1381 | struct net *net = dev_net(dev); | ||
| 1382 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | ||
| 1383 | |||
| 1381 | ip6_tnl_dev_init_gen(dev); | 1384 | ip6_tnl_dev_init_gen(dev); |
| 1382 | t->parms.proto = IPPROTO_IPV6; | 1385 | t->parms.proto = IPPROTO_IPV6; |
| 1383 | dev_hold(dev); | 1386 | dev_hold(dev); |
| 1384 | tnls_wc[0] = t; | 1387 | ip6n->tnls_wc[0] = t; |
| 1385 | return 0; | 1388 | return 0; |
| 1386 | } | 1389 | } |
| 1387 | 1390 | ||
| @@ -1397,13 +1400,27 @@ static struct xfrm6_tunnel ip6ip6_handler = { | |||
| 1397 | .priority = 1, | 1400 | .priority = 1, |
| 1398 | }; | 1401 | }; |
| 1399 | 1402 | ||
| 1403 | static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) | ||
| 1404 | { | ||
| 1405 | int h; | ||
| 1406 | struct ip6_tnl *t; | ||
| 1407 | |||
| 1408 | for (h = 0; h < HASH_SIZE; h++) { | ||
| 1409 | while ((t = ip6n->tnls_r_l[h]) != NULL) | ||
| 1410 | unregister_netdevice(t->dev); | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | t = ip6n->tnls_wc[0]; | ||
| 1414 | unregister_netdevice(t->dev); | ||
| 1415 | } | ||
| 1416 | |||
| 1400 | static int ip6_tnl_init_net(struct net *net) | 1417 | static int ip6_tnl_init_net(struct net *net) |
| 1401 | { | 1418 | { |
| 1402 | int err; | 1419 | int err; |
| 1403 | struct ip6_tnl_net *ip6n; | 1420 | struct ip6_tnl_net *ip6n; |
| 1404 | 1421 | ||
| 1405 | err = -ENOMEM; | 1422 | err = -ENOMEM; |
| 1406 | ip6n = kmalloc(sizeof(struct ip6_tnl_net), GFP_KERNEL); | 1423 | ip6n = kzalloc(sizeof(struct ip6_tnl_net), GFP_KERNEL); |
| 1407 | if (ip6n == NULL) | 1424 | if (ip6n == NULL) |
| 1408 | goto err_alloc; | 1425 | goto err_alloc; |
| 1409 | 1426 | ||
| @@ -1411,6 +1428,9 @@ static int ip6_tnl_init_net(struct net *net) | |||
| 1411 | if (err < 0) | 1428 | if (err < 0) |
| 1412 | goto err_assign; | 1429 | goto err_assign; |
| 1413 | 1430 | ||
| 1431 | ip6n->tnls[0] = ip6n->tnls_wc; | ||
| 1432 | ip6n->tnls[1] = ip6n->tnls_r_l; | ||
| 1433 | |||
| 1414 | err = -ENOMEM; | 1434 | err = -ENOMEM; |
| 1415 | ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", | 1435 | ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", |
| 1416 | ip6_tnl_dev_setup); | 1436 | ip6_tnl_dev_setup); |
| @@ -1441,6 +1461,9 @@ static void ip6_tnl_exit_net(struct net *net) | |||
| 1441 | struct ip6_tnl_net *ip6n; | 1461 | struct ip6_tnl_net *ip6n; |
| 1442 | 1462 | ||
| 1443 | ip6n = net_generic(net, ip6_tnl_net_id); | 1463 | ip6n = net_generic(net, ip6_tnl_net_id); |
| 1464 | rtnl_lock(); | ||
| 1465 | ip6_tnl_destroy_tunnels(ip6n); | ||
| 1466 | rtnl_unlock(); | ||
| 1444 | kfree(ip6n); | 1467 | kfree(ip6n); |
| 1445 | } | 1468 | } |
| 1446 | 1469 | ||
| @@ -1483,20 +1506,6 @@ out: | |||
| 1483 | return err; | 1506 | return err; |
| 1484 | } | 1507 | } |
| 1485 | 1508 | ||
| 1486 | static void __exit ip6_tnl_destroy_tunnels(void) | ||
| 1487 | { | ||
| 1488 | int h; | ||
| 1489 | struct ip6_tnl *t; | ||
| 1490 | |||
| 1491 | for (h = 0; h < HASH_SIZE; h++) { | ||
| 1492 | while ((t = tnls_r_l[h]) != NULL) | ||
| 1493 | unregister_netdevice(t->dev); | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | t = tnls_wc[0]; | ||
| 1497 | unregister_netdevice(t->dev); | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | /** | 1509 | /** |
| 1501 | * ip6_tunnel_cleanup - free resources and unregister protocol | 1510 | * ip6_tunnel_cleanup - free resources and unregister protocol |
| 1502 | **/ | 1511 | **/ |
| @@ -1509,10 +1518,6 @@ static void __exit ip6_tunnel_cleanup(void) | |||
| 1509 | if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) | 1518 | if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) |
| 1510 | printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n"); | 1519 | printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n"); |
| 1511 | 1520 | ||
| 1512 | rtnl_lock(); | ||
| 1513 | ip6_tnl_destroy_tunnels(); | ||
| 1514 | rtnl_unlock(); | ||
| 1515 | |||
| 1516 | unregister_pernet_gen_device(ip6_tnl_net_id, &ip6_tnl_net_ops); | 1521 | unregister_pernet_gen_device(ip6_tnl_net_id, &ip6_tnl_net_ops); |
| 1517 | } | 1522 | } |
| 1518 | 1523 | ||
