aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_tunnel.c63
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;
84struct ip6_tnl_net { 84struct 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 */
90static struct ip6_tnl *tnls_r_l[HASH_SIZE];
91static struct ip6_tnl *tnls_wc[1];
92static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l };
93
94/* lock for the tunnel lists */ 93/* lock for the tunnel lists */
95static DEFINE_RWLOCK(ip6_tnl_lock); 94static 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
1378ip6_fb_tnl_dev_init(struct net_device *dev) 1378ip6_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
1403static 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
1400static int ip6_tnl_init_net(struct net *net) 1417static 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
1486static 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