diff options
Diffstat (limited to 'net/ipv6')
-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 | ||