Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4543c10d authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

ipv6 sit: RCU conversion phase II



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: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ef9a9d11
Loading
Loading
Loading
Loading
+27 −18
Original line number Diff line number Diff line
@@ -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)
{
@@ -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;
@@ -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;
		}
	}
@@ -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)
@@ -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));
@@ -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,
@@ -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;
}

@@ -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) {
@@ -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;
		}
@@ -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;