aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipip.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-10-23 01:42:02 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-24 09:07:57 -0400
commit8f95dd63a2ab6fe7243c4f0bd2c3266e3a5525ab (patch)
treea9bc2c34c612d8fc2fa70e107e87283b53ecf4ed /net/ipv4/ipip.c
parent91cc3bb0b04ffef49bb044e06b221ea5de053e91 (diff)
ipip: convert hash tables locking to RCU
IPIP 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/ipip.c')
-rw-r--r--net/ipv4/ipip.c49
1 files changed, 28 insertions, 21 deletions
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 6a5539236ab3..3bd69988bccf 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -134,7 +134,13 @@ static void ipip_fb_tunnel_init(struct net_device *dev);
134static void ipip_tunnel_init(struct net_device *dev); 134static void ipip_tunnel_init(struct net_device *dev);
135static void ipip_tunnel_setup(struct net_device *dev); 135static void ipip_tunnel_setup(struct net_device *dev);
136 136
137static DEFINE_RWLOCK(ipip_lock); 137/*
138 * Locking : hash tables are protected by RCU and a spinlock
139 */
140static DEFINE_SPINLOCK(ipip_lock);
141
142#define for_each_ip_tunnel_rcu(start) \
143 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
138 144
139static struct ip_tunnel * ipip_tunnel_lookup(struct net *net, 145static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
140 __be32 remote, __be32 local) 146 __be32 remote, __be32 local)
@@ -144,20 +150,21 @@ static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
144 struct ip_tunnel *t; 150 struct ip_tunnel *t;
145 struct ipip_net *ipn = net_generic(net, ipip_net_id); 151 struct ipip_net *ipn = net_generic(net, ipip_net_id);
146 152
147 for (t = ipn->tunnels_r_l[h0^h1]; t; t = t->next) { 153 for_each_ip_tunnel_rcu(ipn->tunnels_r_l[h0 ^ h1])
148 if (local == t->parms.iph.saddr && 154 if (local == t->parms.iph.saddr &&
149 remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) 155 remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
150 return t; 156 return t;
151 } 157
152 for (t = ipn->tunnels_r[h0]; t; t = t->next) { 158 for_each_ip_tunnel_rcu(ipn->tunnels_r[h0])
153 if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) 159 if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
154 return t; 160 return t;
155 } 161
156 for (t = ipn->tunnels_l[h1]; t; t = t->next) { 162 for_each_ip_tunnel_rcu(ipn->tunnels_l[h1])
157 if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) 163 if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
158 return t; 164 return t;
159 } 165
160 if ((t = ipn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) 166 t = rcu_dereference(ipn->tunnels_wc[0]);
167 if (t && (t->dev->flags&IFF_UP))
161 return t; 168 return t;
162 return NULL; 169 return NULL;
163} 170}
@@ -193,9 +200,9 @@ static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
193 200
194 for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) { 201 for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) {
195 if (t == *tp) { 202 if (t == *tp) {
196 write_lock_bh(&ipip_lock); 203 spin_lock_bh(&ipip_lock);
197 *tp = t->next; 204 *tp = t->next;
198 write_unlock_bh(&ipip_lock); 205 spin_unlock_bh(&ipip_lock);
199 break; 206 break;
200 } 207 }
201 } 208 }
@@ -205,10 +212,10 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
205{ 212{
206 struct ip_tunnel **tp = ipip_bucket(ipn, t); 213 struct ip_tunnel **tp = ipip_bucket(ipn, t);
207 214
215 spin_lock_bh(&ipip_lock);
208 t->next = *tp; 216 t->next = *tp;
209 write_lock_bh(&ipip_lock); 217 rcu_assign_pointer(*tp, t);
210 *tp = t; 218 spin_unlock_bh(&ipip_lock);
211 write_unlock_bh(&ipip_lock);
212} 219}
213 220
214static struct ip_tunnel * ipip_tunnel_locate(struct net *net, 221static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
@@ -267,9 +274,9 @@ static void ipip_tunnel_uninit(struct net_device *dev)
267 struct ipip_net *ipn = net_generic(net, ipip_net_id); 274 struct ipip_net *ipn = net_generic(net, ipip_net_id);
268 275
269 if (dev == ipn->fb_tunnel_dev) { 276 if (dev == ipn->fb_tunnel_dev) {
270 write_lock_bh(&ipip_lock); 277 spin_lock_bh(&ipip_lock);
271 ipn->tunnels_wc[0] = NULL; 278 ipn->tunnels_wc[0] = NULL;
272 write_unlock_bh(&ipip_lock); 279 spin_unlock_bh(&ipip_lock);
273 } else 280 } else
274 ipip_tunnel_unlink(ipn, netdev_priv(dev)); 281 ipip_tunnel_unlink(ipn, netdev_priv(dev));
275 dev_put(dev); 282 dev_put(dev);
@@ -318,7 +325,7 @@ static int ipip_err(struct sk_buff *skb, u32 info)
318 325
319 err = -ENOENT; 326 err = -ENOENT;
320 327
321 read_lock(&ipip_lock); 328 rcu_read_lock();
322 t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); 329 t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr);
323 if (t == NULL || t->parms.iph.daddr == 0) 330 if (t == NULL || t->parms.iph.daddr == 0)
324 goto out; 331 goto out;
@@ -333,7 +340,7 @@ static int ipip_err(struct sk_buff *skb, u32 info)
333 t->err_count = 1; 340 t->err_count = 1;
334 t->err_time = jiffies; 341 t->err_time = jiffies;
335out: 342out:
336 read_unlock(&ipip_lock); 343 rcu_read_unlock();
337 return err; 344 return err;
338} 345}
339 346
@@ -351,11 +358,11 @@ static int ipip_rcv(struct sk_buff *skb)
351 struct ip_tunnel *tunnel; 358 struct ip_tunnel *tunnel;
352 const struct iphdr *iph = ip_hdr(skb); 359 const struct iphdr *iph = ip_hdr(skb);
353 360
354 read_lock(&ipip_lock); 361 rcu_read_lock();
355 if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev), 362 if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev),
356 iph->saddr, iph->daddr)) != NULL) { 363 iph->saddr, iph->daddr)) != NULL) {
357 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { 364 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
358 read_unlock(&ipip_lock); 365 rcu_read_unlock();
359 kfree_skb(skb); 366 kfree_skb(skb);
360 return 0; 367 return 0;
361 } 368 }
@@ -374,10 +381,10 @@ static int ipip_rcv(struct sk_buff *skb)
374 nf_reset(skb); 381 nf_reset(skb);
375 ipip_ecn_decapsulate(iph, skb); 382 ipip_ecn_decapsulate(iph, skb);
376 netif_rx(skb); 383 netif_rx(skb);
377 read_unlock(&ipip_lock); 384 rcu_read_unlock();
378 return 0; 385 return 0;
379 } 386 }
380 read_unlock(&ipip_lock); 387 rcu_read_unlock();
381 388
382 return -1; 389 return -1;
383} 390}