diff options
Diffstat (limited to 'net/ipv6/sit.c')
| -rw-r--r-- | net/ipv6/sit.c | 40 | 
1 files changed, 27 insertions, 13 deletions
| diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index ac912bb21747..d60ddcb0bfe2 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -91,29 +91,35 @@ struct sit_net {   * 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) +					     struct net_device *dev, +					     __be32 remote, __be32 local, +					     int sifindex)  {  	unsigned int h0 = HASH(remote);  	unsigned int h1 = HASH(local);  	struct ip_tunnel *t;  	struct sit_net *sitn = net_generic(net, sit_net_id); +	int ifindex = dev ? dev->ifindex : 0;  	for_each_ip_tunnel_rcu(t, sitn->tunnels_r_l[h0 ^ h1]) {  		if (local == t->parms.iph.saddr &&  		    remote == t->parms.iph.daddr && -		    (!dev || !t->parms.link || dev->ifindex == t->parms.link) && +		    (!dev || !t->parms.link || ifindex == t->parms.link || +		     sifindex == t->parms.link) &&  		    (t->dev->flags & IFF_UP))  			return t;  	}  	for_each_ip_tunnel_rcu(t, sitn->tunnels_r[h0]) {  		if (remote == t->parms.iph.daddr && -		    (!dev || !t->parms.link || dev->ifindex == t->parms.link) && +		    (!dev || !t->parms.link || ifindex == t->parms.link || +		     sifindex == t->parms.link) &&  		    (t->dev->flags & IFF_UP))  			return t;  	}  	for_each_ip_tunnel_rcu(t, sitn->tunnels_l[h1]) {  		if (local == t->parms.iph.saddr && -		    (!dev || !t->parms.link || dev->ifindex == t->parms.link) && +		    (!dev || !t->parms.link || ifindex == t->parms.link || +		     sifindex == t->parms.link) &&  		    (t->dev->flags & IFF_UP))  			return t;  	} @@ -486,6 +492,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)  	const int code = icmp_hdr(skb)->code;  	unsigned int data_len = 0;  	struct ip_tunnel *t; +	int sifindex;  	int err;  	switch (type) { @@ -517,10 +524,9 @@ static int ipip6_err(struct sk_buff *skb, u32 info)  	err = -ENOENT; -	t = ipip6_tunnel_lookup(dev_net(skb->dev), -				skb->dev, -				iph->daddr, -				iph->saddr); +	sifindex = netif_is_l3_master(skb->dev) ? IPCB(skb)->iif : 0; +	t = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, +				iph->daddr, iph->saddr, sifindex);  	if (!t)  		goto out; @@ -633,10 +639,12 @@ static int ipip6_rcv(struct sk_buff *skb)  {  	const struct iphdr *iph = ip_hdr(skb);  	struct ip_tunnel *tunnel; +	int sifindex;  	int err; +	sifindex = netif_is_l3_master(skb->dev) ? IPCB(skb)->iif : 0;  	tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, -				     iph->saddr, iph->daddr); +				     iph->saddr, iph->daddr, sifindex);  	if (tunnel) {  		struct pcpu_sw_netstats *tstats; @@ -704,10 +712,13 @@ static int sit_tunnel_rcv(struct sk_buff *skb, u8 ipproto)  {  	const struct iphdr *iph;  	struct ip_tunnel *tunnel; +	int sifindex; + +	sifindex = netif_is_l3_master(skb->dev) ? IPCB(skb)->iif : 0;  	iph = ip_hdr(skb);  	tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, -				     iph->saddr, iph->daddr); +				     iph->saddr, iph->daddr, sifindex);  	if (tunnel) {  		const struct tnl_ptk_info *tpi; @@ -1848,19 +1859,22 @@ err_alloc_dev:  	return err;  } -static void __net_exit sit_exit_net(struct net *net) +static void __net_exit sit_exit_batch_net(struct list_head *net_list)  {  	LIST_HEAD(list); +	struct net *net;  	rtnl_lock(); -	sit_destroy_tunnels(net, &list); +	list_for_each_entry(net, net_list, exit_list) +		sit_destroy_tunnels(net, &list); +  	unregister_netdevice_many(&list);  	rtnl_unlock();  }  static struct pernet_operations sit_net_ops = {  	.init = sit_init_net, -	.exit = sit_exit_net, +	.exit_batch = sit_exit_batch_net,  	.id   = &sit_net_id,  	.size = sizeof(struct sit_net),  }; | 
