aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_gre.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-10-23 02:14:38 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-24 09:07:59 -0400
commit8d5b2c084d2e71587e30a6ef528a8a8051e59dcd (patch)
treea66dd86d178eb5ce50a1704e085542ae3516e398 /net/ipv4/ip_gre.c
parent2922bc8aedfcd41ca6171cfe1a79ff111ad72019 (diff)
gre: convert hash tables locking to RCU
GRE tunnels use one rwlock to protect their hash tables. This locking scheme can be converted to RCU for free, since netdevice already must wait for a RCU grace period at dismantle time. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ip_gre.c')
-rw-r--r--net/ipv4/ip_gre.c40
1 files changed, 23 insertions, 17 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 89ff9d5b1500..40f043915235 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -156,8 +156,13 @@ struct ipgre_net {
156#define tunnels_r tunnels[2] 156#define tunnels_r tunnels[2]
157#define tunnels_l tunnels[1] 157#define tunnels_l tunnels[1]
158#define tunnels_wc tunnels[0] 158#define tunnels_wc tunnels[0]
159/*
160 * Locking : hash tables are protected by RCU and a spinlock
161 */
162static DEFINE_SPINLOCK(ipgre_lock);
159 163
160static DEFINE_RWLOCK(ipgre_lock); 164#define for_each_ip_tunnel_rcu(start) \
165 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
161 166
162/* Given src, dst and key, find appropriate for input tunnel. */ 167/* Given src, dst and key, find appropriate for input tunnel. */
163 168
@@ -175,7 +180,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
175 ARPHRD_ETHER : ARPHRD_IPGRE; 180 ARPHRD_ETHER : ARPHRD_IPGRE;
176 int score, cand_score = 4; 181 int score, cand_score = 4;
177 182
178 for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) { 183 for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) {
179 if (local != t->parms.iph.saddr || 184 if (local != t->parms.iph.saddr ||
180 remote != t->parms.iph.daddr || 185 remote != t->parms.iph.daddr ||
181 key != t->parms.i_key || 186 key != t->parms.i_key ||
@@ -200,7 +205,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
200 } 205 }
201 } 206 }
202 207
203 for (t = ign->tunnels_r[h0^h1]; t; t = t->next) { 208 for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) {
204 if (remote != t->parms.iph.daddr || 209 if (remote != t->parms.iph.daddr ||
205 key != t->parms.i_key || 210 key != t->parms.i_key ||
206 !(t->dev->flags & IFF_UP)) 211 !(t->dev->flags & IFF_UP))
@@ -224,7 +229,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
224 } 229 }
225 } 230 }
226 231
227 for (t = ign->tunnels_l[h1]; t; t = t->next) { 232 for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) {
228 if ((local != t->parms.iph.saddr && 233 if ((local != t->parms.iph.saddr &&
229 (local != t->parms.iph.daddr || 234 (local != t->parms.iph.daddr ||
230 !ipv4_is_multicast(local))) || 235 !ipv4_is_multicast(local))) ||
@@ -250,7 +255,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
250 } 255 }
251 } 256 }
252 257
253 for (t = ign->tunnels_wc[h1]; t; t = t->next) { 258 for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) {
254 if (t->parms.i_key != key || 259 if (t->parms.i_key != key ||
255 !(t->dev->flags & IFF_UP)) 260 !(t->dev->flags & IFF_UP))
256 continue; 261 continue;
@@ -276,8 +281,9 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
276 if (cand != NULL) 281 if (cand != NULL)
277 return cand; 282 return cand;
278 283
279 if (ign->fb_tunnel_dev->flags & IFF_UP) 284 dev = ign->fb_tunnel_dev;
280 return netdev_priv(ign->fb_tunnel_dev); 285 if (dev->flags & IFF_UP)
286 return netdev_priv(dev);
281 287
282 return NULL; 288 return NULL;
283} 289}
@@ -311,10 +317,10 @@ static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t)
311{ 317{
312 struct ip_tunnel **tp = ipgre_bucket(ign, t); 318 struct ip_tunnel **tp = ipgre_bucket(ign, t);
313 319
320 spin_lock_bh(&ipgre_lock);
314 t->next = *tp; 321 t->next = *tp;
315 write_lock_bh(&ipgre_lock); 322 rcu_assign_pointer(*tp, t);
316 *tp = t; 323 spin_unlock_bh(&ipgre_lock);
317 write_unlock_bh(&ipgre_lock);
318} 324}
319 325
320static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t) 326static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
@@ -323,9 +329,9 @@ static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
323 329
324 for (tp = ipgre_bucket(ign, t); *tp; tp = &(*tp)->next) { 330 for (tp = ipgre_bucket(ign, t); *tp; tp = &(*tp)->next) {
325 if (t == *tp) { 331 if (t == *tp) {
326 write_lock_bh(&ipgre_lock); 332 spin_lock_bh(&ipgre_lock);
327 *tp = t->next; 333 *tp = t->next;
328 write_unlock_bh(&ipgre_lock); 334 spin_unlock_bh(&ipgre_lock);
329 break; 335 break;
330 } 336 }
331 } 337 }
@@ -476,7 +482,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
476 break; 482 break;
477 } 483 }
478 484
479 read_lock(&ipgre_lock); 485 rcu_read_lock();
480 t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr, 486 t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr,
481 flags & GRE_KEY ? 487 flags & GRE_KEY ?
482 *(((__be32 *)p) + (grehlen / 4) - 1) : 0, 488 *(((__be32 *)p) + (grehlen / 4) - 1) : 0,
@@ -494,7 +500,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
494 t->err_count = 1; 500 t->err_count = 1;
495 t->err_time = jiffies; 501 t->err_time = jiffies;
496out: 502out:
497 read_unlock(&ipgre_lock); 503 rcu_read_unlock();
498 return; 504 return;
499} 505}
500 506
@@ -573,7 +579,7 @@ static int ipgre_rcv(struct sk_buff *skb)
573 579
574 gre_proto = *(__be16 *)(h + 2); 580 gre_proto = *(__be16 *)(h + 2);
575 581
576 read_lock(&ipgre_lock); 582 rcu_read_lock();
577 if ((tunnel = ipgre_tunnel_lookup(skb->dev, 583 if ((tunnel = ipgre_tunnel_lookup(skb->dev,
578 iph->saddr, iph->daddr, key, 584 iph->saddr, iph->daddr, key,
579 gre_proto))) { 585 gre_proto))) {
@@ -647,13 +653,13 @@ static int ipgre_rcv(struct sk_buff *skb)
647 ipgre_ecn_decapsulate(iph, skb); 653 ipgre_ecn_decapsulate(iph, skb);
648 654
649 netif_rx(skb); 655 netif_rx(skb);
650 read_unlock(&ipgre_lock); 656 rcu_read_unlock();
651 return(0); 657 return(0);
652 } 658 }
653 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 659 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
654 660
655drop: 661drop:
656 read_unlock(&ipgre_lock); 662 rcu_read_unlock();
657drop_nolock: 663drop_nolock:
658 kfree_skb(skb); 664 kfree_skb(skb);
659 return(0); 665 return(0);