aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/sit.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/sit.c')
-rw-r--r--net/ipv6/sit.c45
1 files changed, 27 insertions, 18 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 8cdcc2ad048c..b6b16264b305 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -77,8 +77,17 @@ struct sit_net {
77 struct net_device *fb_tunnel_dev; 77 struct net_device *fb_tunnel_dev;
78}; 78};
79 79
80static DEFINE_RWLOCK(ipip6_lock); 80/*
81 * Locking : hash tables are protected by RCU and a spinlock
82 */
83static DEFINE_SPINLOCK(ipip6_lock);
84
85#define for_each_ip_tunnel_rcu(start) \
86 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
81 87
88/*
89 * Must be invoked with rcu_read_lock
90 */
82static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, 91static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
83 struct net_device *dev, __be32 remote, __be32 local) 92 struct net_device *dev, __be32 remote, __be32 local)
84{ 93{
@@ -87,26 +96,26 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
87 struct ip_tunnel *t; 96 struct ip_tunnel *t;
88 struct sit_net *sitn = net_generic(net, sit_net_id); 97 struct sit_net *sitn = net_generic(net, sit_net_id);
89 98
90 for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) { 99 for_each_ip_tunnel_rcu(sitn->tunnels_r_l[h0 ^ h1]) {
91 if (local == t->parms.iph.saddr && 100 if (local == t->parms.iph.saddr &&
92 remote == t->parms.iph.daddr && 101 remote == t->parms.iph.daddr &&
93 (!dev || !t->parms.link || dev->iflink == t->parms.link) && 102 (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
94 (t->dev->flags & IFF_UP)) 103 (t->dev->flags & IFF_UP))
95 return t; 104 return t;
96 } 105 }
97 for (t = sitn->tunnels_r[h0]; t; t = t->next) { 106 for_each_ip_tunnel_rcu(sitn->tunnels_r[h0]) {
98 if (remote == t->parms.iph.daddr && 107 if (remote == t->parms.iph.daddr &&
99 (!dev || !t->parms.link || dev->iflink == t->parms.link) && 108 (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
100 (t->dev->flags & IFF_UP)) 109 (t->dev->flags & IFF_UP))
101 return t; 110 return t;
102 } 111 }
103 for (t = sitn->tunnels_l[h1]; t; t = t->next) { 112 for_each_ip_tunnel_rcu(sitn->tunnels_l[h1]) {
104 if (local == t->parms.iph.saddr && 113 if (local == t->parms.iph.saddr &&
105 (!dev || !t->parms.link || dev->iflink == t->parms.link) && 114 (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
106 (t->dev->flags & IFF_UP)) 115 (t->dev->flags & IFF_UP))
107 return t; 116 return t;
108 } 117 }
109 t = sitn->tunnels_wc[0]; 118 t = rcu_dereference(sitn->tunnels_wc[0]);
110 if ((t != NULL) && (t->dev->flags & IFF_UP)) 119 if ((t != NULL) && (t->dev->flags & IFF_UP))
111 return t; 120 return t;
112 return NULL; 121 return NULL;
@@ -143,9 +152,9 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
143 152
144 for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { 153 for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) {
145 if (t == *tp) { 154 if (t == *tp) {
146 write_lock_bh(&ipip6_lock); 155 spin_lock_bh(&ipip6_lock);
147 *tp = t->next; 156 *tp = t->next;
148 write_unlock_bh(&ipip6_lock); 157 spin_unlock_bh(&ipip6_lock);
149 break; 158 break;
150 } 159 }
151 } 160 }
@@ -155,10 +164,10 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
155{ 164{
156 struct ip_tunnel **tp = ipip6_bucket(sitn, t); 165 struct ip_tunnel **tp = ipip6_bucket(sitn, t);
157 166
167 spin_lock_bh(&ipip6_lock);
158 t->next = *tp; 168 t->next = *tp;
159 write_lock_bh(&ipip6_lock); 169 rcu_assign_pointer(*tp, t);
160 *tp = t; 170 spin_unlock_bh(&ipip6_lock);
161 write_unlock_bh(&ipip6_lock);
162} 171}
163 172
164static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) 173static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
@@ -447,9 +456,9 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
447 struct sit_net *sitn = net_generic(net, sit_net_id); 456 struct sit_net *sitn = net_generic(net, sit_net_id);
448 457
449 if (dev == sitn->fb_tunnel_dev) { 458 if (dev == sitn->fb_tunnel_dev) {
450 write_lock_bh(&ipip6_lock); 459 spin_lock_bh(&ipip6_lock);
451 sitn->tunnels_wc[0] = NULL; 460 sitn->tunnels_wc[0] = NULL;
452 write_unlock_bh(&ipip6_lock); 461 spin_unlock_bh(&ipip6_lock);
453 dev_put(dev); 462 dev_put(dev);
454 } else { 463 } else {
455 ipip6_tunnel_unlink(sitn, netdev_priv(dev)); 464 ipip6_tunnel_unlink(sitn, netdev_priv(dev));
@@ -502,7 +511,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
502 511
503 err = -ENOENT; 512 err = -ENOENT;
504 513
505 read_lock(&ipip6_lock); 514 rcu_read_lock();
506 t = ipip6_tunnel_lookup(dev_net(skb->dev), 515 t = ipip6_tunnel_lookup(dev_net(skb->dev),
507 skb->dev, 516 skb->dev,
508 iph->daddr, 517 iph->daddr,
@@ -520,7 +529,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
520 t->err_count = 1; 529 t->err_count = 1;
521 t->err_time = jiffies; 530 t->err_time = jiffies;
522out: 531out:
523 read_unlock(&ipip6_lock); 532 rcu_read_unlock();
524 return err; 533 return err;
525} 534}
526 535
@@ -540,7 +549,7 @@ static int ipip6_rcv(struct sk_buff *skb)
540 549
541 iph = ip_hdr(skb); 550 iph = ip_hdr(skb);
542 551
543 read_lock(&ipip6_lock); 552 rcu_read_lock();
544 tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, 553 tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
545 iph->saddr, iph->daddr); 554 iph->saddr, iph->daddr);
546 if (tunnel != NULL) { 555 if (tunnel != NULL) {
@@ -554,7 +563,7 @@ static int ipip6_rcv(struct sk_buff *skb)
554 if ((tunnel->dev->priv_flags & IFF_ISATAP) && 563 if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
555 !isatap_chksrc(skb, iph, tunnel)) { 564 !isatap_chksrc(skb, iph, tunnel)) {
556 tunnel->dev->stats.rx_errors++; 565 tunnel->dev->stats.rx_errors++;
557 read_unlock(&ipip6_lock); 566 rcu_read_unlock();
558 kfree_skb(skb); 567 kfree_skb(skb);
559 return 0; 568 return 0;
560 } 569 }
@@ -565,12 +574,12 @@ static int ipip6_rcv(struct sk_buff *skb)
565 nf_reset(skb); 574 nf_reset(skb);
566 ipip6_ecn_decapsulate(iph, skb); 575 ipip6_ecn_decapsulate(iph, skb);
567 netif_rx(skb); 576 netif_rx(skb);
568 read_unlock(&ipip6_lock); 577 rcu_read_unlock();
569 return 0; 578 return 0;
570 } 579 }
571 580
572 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 581 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
573 read_unlock(&ipip6_lock); 582 rcu_read_unlock();
574out: 583out:
575 kfree_skb(skb); 584 kfree_skb(skb);
576 return 0; 585 return 0;