aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_tunnel.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_tunnel.c')
-rw-r--r--net/ipv6/ip6_tunnel.c93
1 files changed, 45 insertions, 48 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index c595bbe1ed99..d453d07b0dfe 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -78,7 +78,7 @@ static void ip6_fb_tnl_dev_init(struct net_device *dev);
78static void ip6_tnl_dev_init(struct net_device *dev); 78static void ip6_tnl_dev_init(struct net_device *dev);
79static void ip6_tnl_dev_setup(struct net_device *dev); 79static void ip6_tnl_dev_setup(struct net_device *dev);
80 80
81static int ip6_tnl_net_id; 81static int ip6_tnl_net_id __read_mostly;
82struct ip6_tnl_net { 82struct ip6_tnl_net {
83 /* the IPv6 tunnel fallback device */ 83 /* the IPv6 tunnel fallback device */
84 struct net_device *fb_tnl_dev; 84 struct net_device *fb_tnl_dev;
@@ -88,8 +88,10 @@ struct ip6_tnl_net {
88 struct ip6_tnl **tnls[2]; 88 struct ip6_tnl **tnls[2];
89}; 89};
90 90
91/* lock for the tunnel lists */ 91/*
92static DEFINE_RWLOCK(ip6_tnl_lock); 92 * Locking : hash tables are protected by RCU and a spinlock
93 */
94static DEFINE_SPINLOCK(ip6_tnl_lock);
93 95
94static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) 96static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
95{ 97{
@@ -130,6 +132,9 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
130 * else %NULL 132 * else %NULL
131 **/ 133 **/
132 134
135#define for_each_ip6_tunnel_rcu(start) \
136 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
137
133static struct ip6_tnl * 138static struct ip6_tnl *
134ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) 139ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local)
135{ 140{
@@ -138,13 +143,14 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local)
138 struct ip6_tnl *t; 143 struct ip6_tnl *t;
139 struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); 144 struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
140 145
141 for (t = ip6n->tnls_r_l[h0 ^ h1]; t; t = t->next) { 146 for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[h0 ^ h1]) {
142 if (ipv6_addr_equal(local, &t->parms.laddr) && 147 if (ipv6_addr_equal(local, &t->parms.laddr) &&
143 ipv6_addr_equal(remote, &t->parms.raddr) && 148 ipv6_addr_equal(remote, &t->parms.raddr) &&
144 (t->dev->flags & IFF_UP)) 149 (t->dev->flags & IFF_UP))
145 return t; 150 return t;
146 } 151 }
147 if ((t = ip6n->tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP)) 152 t = rcu_dereference(ip6n->tnls_wc[0]);
153 if (t && (t->dev->flags & IFF_UP))
148 return t; 154 return t;
149 155
150 return NULL; 156 return NULL;
@@ -186,10 +192,10 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
186{ 192{
187 struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms); 193 struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms);
188 194
195 spin_lock_bh(&ip6_tnl_lock);
189 t->next = *tp; 196 t->next = *tp;
190 write_lock_bh(&ip6_tnl_lock); 197 rcu_assign_pointer(*tp, t);
191 *tp = t; 198 spin_unlock_bh(&ip6_tnl_lock);
192 write_unlock_bh(&ip6_tnl_lock);
193} 199}
194 200
195/** 201/**
@@ -204,9 +210,9 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
204 210
205 for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) { 211 for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) {
206 if (t == *tp) { 212 if (t == *tp) {
207 write_lock_bh(&ip6_tnl_lock); 213 spin_lock_bh(&ip6_tnl_lock);
208 *tp = t->next; 214 *tp = t->next;
209 write_unlock_bh(&ip6_tnl_lock); 215 spin_unlock_bh(&ip6_tnl_lock);
210 break; 216 break;
211 } 217 }
212 } 218 }
@@ -313,9 +319,9 @@ ip6_tnl_dev_uninit(struct net_device *dev)
313 struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); 319 struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
314 320
315 if (dev == ip6n->fb_tnl_dev) { 321 if (dev == ip6n->fb_tnl_dev) {
316 write_lock_bh(&ip6_tnl_lock); 322 spin_lock_bh(&ip6_tnl_lock);
317 ip6n->tnls_wc[0] = NULL; 323 ip6n->tnls_wc[0] = NULL;
318 write_unlock_bh(&ip6_tnl_lock); 324 spin_unlock_bh(&ip6_tnl_lock);
319 } else { 325 } else {
320 ip6_tnl_unlink(ip6n, t); 326 ip6_tnl_unlink(ip6n, t);
321 } 327 }
@@ -409,7 +415,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
409 in trouble since we might need the source address for further 415 in trouble since we might need the source address for further
410 processing of the error. */ 416 processing of the error. */
411 417
412 read_lock(&ip6_tnl_lock); 418 rcu_read_lock();
413 if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr, 419 if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr,
414 &ipv6h->saddr)) == NULL) 420 &ipv6h->saddr)) == NULL)
415 goto out; 421 goto out;
@@ -482,7 +488,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
482 *msg = rel_msg; 488 *msg = rel_msg;
483 489
484out: 490out:
485 read_unlock(&ip6_tnl_lock); 491 rcu_read_unlock();
486 return err; 492 return err;
487} 493}
488 494
@@ -652,6 +658,7 @@ static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
652 IP6_ECN_set_ce(ipv6_hdr(skb)); 658 IP6_ECN_set_ce(ipv6_hdr(skb));
653} 659}
654 660
661/* called with rcu_read_lock() */
655static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) 662static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t)
656{ 663{
657 struct ip6_tnl_parm *p = &t->parms; 664 struct ip6_tnl_parm *p = &t->parms;
@@ -662,15 +669,13 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t)
662 struct net_device *ldev = NULL; 669 struct net_device *ldev = NULL;
663 670
664 if (p->link) 671 if (p->link)
665 ldev = dev_get_by_index(net, p->link); 672 ldev = dev_get_by_index_rcu(net, p->link);
666 673
667 if ((ipv6_addr_is_multicast(&p->laddr) || 674 if ((ipv6_addr_is_multicast(&p->laddr) ||
668 likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) && 675 likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) &&
669 likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0))) 676 likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0)))
670 ret = 1; 677 ret = 1;
671 678
672 if (ldev)
673 dev_put(ldev);
674 } 679 }
675 return ret; 680 return ret;
676} 681}
@@ -693,23 +698,23 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
693 struct ip6_tnl *t; 698 struct ip6_tnl *t;
694 struct ipv6hdr *ipv6h = ipv6_hdr(skb); 699 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
695 700
696 read_lock(&ip6_tnl_lock); 701 rcu_read_lock();
697 702
698 if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, 703 if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
699 &ipv6h->daddr)) != NULL) { 704 &ipv6h->daddr)) != NULL) {
700 if (t->parms.proto != ipproto && t->parms.proto != 0) { 705 if (t->parms.proto != ipproto && t->parms.proto != 0) {
701 read_unlock(&ip6_tnl_lock); 706 rcu_read_unlock();
702 goto discard; 707 goto discard;
703 } 708 }
704 709
705 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { 710 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
706 read_unlock(&ip6_tnl_lock); 711 rcu_read_unlock();
707 goto discard; 712 goto discard;
708 } 713 }
709 714
710 if (!ip6_tnl_rcv_ctl(t)) { 715 if (!ip6_tnl_rcv_ctl(t)) {
711 t->dev->stats.rx_dropped++; 716 t->dev->stats.rx_dropped++;
712 read_unlock(&ip6_tnl_lock); 717 rcu_read_unlock();
713 goto discard; 718 goto discard;
714 } 719 }
715 secpath_reset(skb); 720 secpath_reset(skb);
@@ -727,10 +732,10 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
727 t->dev->stats.rx_packets++; 732 t->dev->stats.rx_packets++;
728 t->dev->stats.rx_bytes += skb->len; 733 t->dev->stats.rx_bytes += skb->len;
729 netif_rx(skb); 734 netif_rx(skb);
730 read_unlock(&ip6_tnl_lock); 735 rcu_read_unlock();
731 return 0; 736 return 0;
732 } 737 }
733 read_unlock(&ip6_tnl_lock); 738 rcu_read_unlock();
734 return 1; 739 return 1;
735 740
736discard: 741discard:
@@ -798,8 +803,9 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
798 if (p->flags & IP6_TNL_F_CAP_XMIT) { 803 if (p->flags & IP6_TNL_F_CAP_XMIT) {
799 struct net_device *ldev = NULL; 804 struct net_device *ldev = NULL;
800 805
806 rcu_read_lock();
801 if (p->link) 807 if (p->link)
802 ldev = dev_get_by_index(net, p->link); 808 ldev = dev_get_by_index_rcu(net, p->link);
803 809
804 if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0))) 810 if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0)))
805 printk(KERN_WARNING 811 printk(KERN_WARNING
@@ -813,8 +819,7 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
813 p->name); 819 p->name);
814 else 820 else
815 ret = 1; 821 ret = 1;
816 if (ldev) 822 rcu_read_unlock();
817 dev_put(ldev);
818 } 823 }
819 return ret; 824 return ret;
820} 825}
@@ -1387,29 +1392,25 @@ static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
1387{ 1392{
1388 int h; 1393 int h;
1389 struct ip6_tnl *t; 1394 struct ip6_tnl *t;
1395 LIST_HEAD(list);
1390 1396
1391 for (h = 0; h < HASH_SIZE; h++) { 1397 for (h = 0; h < HASH_SIZE; h++) {
1392 while ((t = ip6n->tnls_r_l[h]) != NULL) 1398 t = ip6n->tnls_r_l[h];
1393 unregister_netdevice(t->dev); 1399 while (t != NULL) {
1400 unregister_netdevice_queue(t->dev, &list);
1401 t = t->next;
1402 }
1394 } 1403 }
1395 1404
1396 t = ip6n->tnls_wc[0]; 1405 t = ip6n->tnls_wc[0];
1397 unregister_netdevice(t->dev); 1406 unregister_netdevice_queue(t->dev, &list);
1407 unregister_netdevice_many(&list);
1398} 1408}
1399 1409
1400static int ip6_tnl_init_net(struct net *net) 1410static int ip6_tnl_init_net(struct net *net)
1401{ 1411{
1412 struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
1402 int err; 1413 int err;
1403 struct ip6_tnl_net *ip6n;
1404
1405 err = -ENOMEM;
1406 ip6n = kzalloc(sizeof(struct ip6_tnl_net), GFP_KERNEL);
1407 if (ip6n == NULL)
1408 goto err_alloc;
1409
1410 err = net_assign_generic(net, ip6_tnl_net_id, ip6n);
1411 if (err < 0)
1412 goto err_assign;
1413 1414
1414 ip6n->tnls[0] = ip6n->tnls_wc; 1415 ip6n->tnls[0] = ip6n->tnls_wc;
1415 ip6n->tnls[1] = ip6n->tnls_r_l; 1416 ip6n->tnls[1] = ip6n->tnls_r_l;
@@ -1432,27 +1433,23 @@ static int ip6_tnl_init_net(struct net *net)
1432err_register: 1433err_register:
1433 free_netdev(ip6n->fb_tnl_dev); 1434 free_netdev(ip6n->fb_tnl_dev);
1434err_alloc_dev: 1435err_alloc_dev:
1435 /* nothing */
1436err_assign:
1437 kfree(ip6n);
1438err_alloc:
1439 return err; 1436 return err;
1440} 1437}
1441 1438
1442static void ip6_tnl_exit_net(struct net *net) 1439static void ip6_tnl_exit_net(struct net *net)
1443{ 1440{
1444 struct ip6_tnl_net *ip6n; 1441 struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
1445 1442
1446 ip6n = net_generic(net, ip6_tnl_net_id);
1447 rtnl_lock(); 1443 rtnl_lock();
1448 ip6_tnl_destroy_tunnels(ip6n); 1444 ip6_tnl_destroy_tunnels(ip6n);
1449 rtnl_unlock(); 1445 rtnl_unlock();
1450 kfree(ip6n);
1451} 1446}
1452 1447
1453static struct pernet_operations ip6_tnl_net_ops = { 1448static struct pernet_operations ip6_tnl_net_ops = {
1454 .init = ip6_tnl_init_net, 1449 .init = ip6_tnl_init_net,
1455 .exit = ip6_tnl_exit_net, 1450 .exit = ip6_tnl_exit_net,
1451 .id = &ip6_tnl_net_id,
1452 .size = sizeof(struct ip6_tnl_net),
1456}; 1453};
1457 1454
1458/** 1455/**
@@ -1477,7 +1474,7 @@ static int __init ip6_tunnel_init(void)
1477 goto unreg_ip4ip6; 1474 goto unreg_ip4ip6;
1478 } 1475 }
1479 1476
1480 err = register_pernet_gen_device(&ip6_tnl_net_id, &ip6_tnl_net_ops); 1477 err = register_pernet_device(&ip6_tnl_net_ops);
1481 if (err < 0) 1478 if (err < 0)
1482 goto err_pernet; 1479 goto err_pernet;
1483 return 0; 1480 return 0;
@@ -1501,7 +1498,7 @@ static void __exit ip6_tunnel_cleanup(void)
1501 if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) 1498 if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6))
1502 printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n"); 1499 printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n");
1503 1500
1504 unregister_pernet_gen_device(ip6_tnl_net_id, &ip6_tnl_net_ops); 1501 unregister_pernet_device(&ip6_tnl_net_ops);
1505} 1502}
1506 1503
1507module_init(ip6_tunnel_init); 1504module_init(ip6_tunnel_init);