Skip to content

Commit

Permalink
ipv6 sit: RCU conversion phase II
Browse files Browse the repository at this point in the history
SIT 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>
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Oct 24, 2009
1 parent ef9a9d1 commit 4543c10
Showing 1 changed file with 27 additions and 18 deletions.
45 changes: 27 additions & 18 deletions net/ipv6/sit.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,17 @@ struct sit_net {
struct net_device *fb_tunnel_dev;
};

static DEFINE_RWLOCK(ipip6_lock);
/*
* Locking : hash tables are protected by RCU and a spinlock
*/
static DEFINE_SPINLOCK(ipip6_lock);

#define for_each_ip_tunnel_rcu(start) \
for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))

/*
* Must be invoked with rcu_read_lock
*/
static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
struct net_device *dev, __be32 remote, __be32 local)
{
Expand All @@ -87,26 +96,26 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
struct ip_tunnel *t;
struct sit_net *sitn = net_generic(net, sit_net_id);

for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) {
for_each_ip_tunnel_rcu(sitn->tunnels_r_l[h0 ^ h1]) {
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr &&
(!dev || !t->parms.link || dev->iflink == t->parms.link) &&
(t->dev->flags & IFF_UP))
return t;
}
for (t = sitn->tunnels_r[h0]; t; t = t->next) {
for_each_ip_tunnel_rcu(sitn->tunnels_r[h0]) {
if (remote == t->parms.iph.daddr &&
(!dev || !t->parms.link || dev->iflink == t->parms.link) &&
(t->dev->flags & IFF_UP))
return t;
}
for (t = sitn->tunnels_l[h1]; t; t = t->next) {
for_each_ip_tunnel_rcu(sitn->tunnels_l[h1]) {
if (local == t->parms.iph.saddr &&
(!dev || !t->parms.link || dev->iflink == t->parms.link) &&
(t->dev->flags & IFF_UP))
return t;
}
t = sitn->tunnels_wc[0];
t = rcu_dereference(sitn->tunnels_wc[0]);
if ((t != NULL) && (t->dev->flags & IFF_UP))
return t;
return NULL;
Expand Down Expand Up @@ -143,9 +152,9 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)

for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) {
if (t == *tp) {
write_lock_bh(&ipip6_lock);
spin_lock_bh(&ipip6_lock);
*tp = t->next;
write_unlock_bh(&ipip6_lock);
spin_unlock_bh(&ipip6_lock);
break;
}
}
Expand All @@ -155,10 +164,10 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
{
struct ip_tunnel **tp = ipip6_bucket(sitn, t);

spin_lock_bh(&ipip6_lock);
t->next = *tp;
write_lock_bh(&ipip6_lock);
*tp = t;
write_unlock_bh(&ipip6_lock);
rcu_assign_pointer(*tp, t);
spin_unlock_bh(&ipip6_lock);
}

static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
Expand Down Expand Up @@ -447,9 +456,9 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
struct sit_net *sitn = net_generic(net, sit_net_id);

if (dev == sitn->fb_tunnel_dev) {
write_lock_bh(&ipip6_lock);
spin_lock_bh(&ipip6_lock);
sitn->tunnels_wc[0] = NULL;
write_unlock_bh(&ipip6_lock);
spin_unlock_bh(&ipip6_lock);
dev_put(dev);
} else {
ipip6_tunnel_unlink(sitn, netdev_priv(dev));
Expand Down Expand Up @@ -502,7 +511,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)

err = -ENOENT;

read_lock(&ipip6_lock);
rcu_read_lock();
t = ipip6_tunnel_lookup(dev_net(skb->dev),
skb->dev,
iph->daddr,
Expand All @@ -520,7 +529,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
t->err_count = 1;
t->err_time = jiffies;
out:
read_unlock(&ipip6_lock);
rcu_read_unlock();
return err;
}

Expand All @@ -540,7 +549,7 @@ static int ipip6_rcv(struct sk_buff *skb)

iph = ip_hdr(skb);

read_lock(&ipip6_lock);
rcu_read_lock();
tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
iph->saddr, iph->daddr);
if (tunnel != NULL) {
Expand All @@ -554,7 +563,7 @@ static int ipip6_rcv(struct sk_buff *skb)
if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
!isatap_chksrc(skb, iph, tunnel)) {
tunnel->dev->stats.rx_errors++;
read_unlock(&ipip6_lock);
rcu_read_unlock();
kfree_skb(skb);
return 0;
}
Expand All @@ -565,12 +574,12 @@ static int ipip6_rcv(struct sk_buff *skb)
nf_reset(skb);
ipip6_ecn_decapsulate(iph, skb);
netif_rx(skb);
read_unlock(&ipip6_lock);
rcu_read_unlock();
return 0;
}

icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
read_unlock(&ipip6_lock);
rcu_read_unlock();
out:
kfree_skb(skb);
return 0;
Expand Down

0 comments on commit 4543c10

Please sign in to comment.