Skip to content

Commit 8f95dd6

Browse files
Eric Dumazetdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 91cc3bb commit 8f95dd6

File tree

1 file changed

+28
-21
lines changed

1 file changed

+28
-21
lines changed

net/ipv4/ipip.c

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,13 @@ static void ipip_fb_tunnel_init(struct net_device *dev);
134134
static void ipip_tunnel_init(struct net_device *dev);
135135
static void ipip_tunnel_setup(struct net_device *dev);
136136

137-
static DEFINE_RWLOCK(ipip_lock);
137+
/*
138+
* Locking : hash tables are protected by RCU and a spinlock
139+
*/
140+
static 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))
138144

139145
static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
140146
__be32 remote, __be32 local)
@@ -144,20 +150,21 @@ static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
144150
struct ip_tunnel *t;
145151
struct ipip_net *ipn = net_generic(net, ipip_net_id);
146152

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])
148154
if (local == t->parms.iph.saddr &&
149155
remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
150156
return t;
151-
}
152-
for (t = ipn->tunnels_r[h0]; t; t = t->next) {
157+
158+
for_each_ip_tunnel_rcu(ipn->tunnels_r[h0])
153159
if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
154160
return t;
155-
}
156-
for (t = ipn->tunnels_l[h1]; t; t = t->next) {
161+
162+
for_each_ip_tunnel_rcu(ipn->tunnels_l[h1])
157163
if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
158164
return t;
159-
}
160-
if ((t = ipn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP))
165+
166+
t = rcu_dereference(ipn->tunnels_wc[0]);
167+
if (t && (t->dev->flags&IFF_UP))
161168
return t;
162169
return NULL;
163170
}
@@ -193,9 +200,9 @@ static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
193200

194201
for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) {
195202
if (t == *tp) {
196-
write_lock_bh(&ipip_lock);
203+
spin_lock_bh(&ipip_lock);
197204
*tp = t->next;
198-
write_unlock_bh(&ipip_lock);
205+
spin_unlock_bh(&ipip_lock);
199206
break;
200207
}
201208
}
@@ -205,10 +212,10 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
205212
{
206213
struct ip_tunnel **tp = ipip_bucket(ipn, t);
207214

215+
spin_lock_bh(&ipip_lock);
208216
t->next = *tp;
209-
write_lock_bh(&ipip_lock);
210-
*tp = t;
211-
write_unlock_bh(&ipip_lock);
217+
rcu_assign_pointer(*tp, t);
218+
spin_unlock_bh(&ipip_lock);
212219
}
213220

214221
static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
@@ -267,9 +274,9 @@ static void ipip_tunnel_uninit(struct net_device *dev)
267274
struct ipip_net *ipn = net_generic(net, ipip_net_id);
268275

269276
if (dev == ipn->fb_tunnel_dev) {
270-
write_lock_bh(&ipip_lock);
277+
spin_lock_bh(&ipip_lock);
271278
ipn->tunnels_wc[0] = NULL;
272-
write_unlock_bh(&ipip_lock);
279+
spin_unlock_bh(&ipip_lock);
273280
} else
274281
ipip_tunnel_unlink(ipn, netdev_priv(dev));
275282
dev_put(dev);
@@ -318,7 +325,7 @@ static int ipip_err(struct sk_buff *skb, u32 info)
318325

319326
err = -ENOENT;
320327

321-
read_lock(&ipip_lock);
328+
rcu_read_lock();
322329
t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr);
323330
if (t == NULL || t->parms.iph.daddr == 0)
324331
goto out;
@@ -333,7 +340,7 @@ static int ipip_err(struct sk_buff *skb, u32 info)
333340
t->err_count = 1;
334341
t->err_time = jiffies;
335342
out:
336-
read_unlock(&ipip_lock);
343+
rcu_read_unlock();
337344
return err;
338345
}
339346

@@ -351,11 +358,11 @@ static int ipip_rcv(struct sk_buff *skb)
351358
struct ip_tunnel *tunnel;
352359
const struct iphdr *iph = ip_hdr(skb);
353360

354-
read_lock(&ipip_lock);
361+
rcu_read_lock();
355362
if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev),
356363
iph->saddr, iph->daddr)) != NULL) {
357364
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
358-
read_unlock(&ipip_lock);
365+
rcu_read_unlock();
359366
kfree_skb(skb);
360367
return 0;
361368
}
@@ -374,10 +381,10 @@ static int ipip_rcv(struct sk_buff *skb)
374381
nf_reset(skb);
375382
ipip_ecn_decapsulate(iph, skb);
376383
netif_rx(skb);
377-
read_unlock(&ipip_lock);
384+
rcu_read_unlock();
378385
return 0;
379386
}
380-
read_unlock(&ipip_lock);
387+
rcu_read_unlock();
381388

382389
return -1;
383390
}

0 commit comments

Comments
 (0)