Index: linux-2.6.26.8/net/ipv4/ip_gre.c =================================================================== --- linux-2.6.26.8.orig/net/ipv4/ip_gre.c 2009-01-08 12:54:44.000000000 +0200 +++ linux-2.6.26.8/net/ipv4/ip_gre.c 2009-01-08 15:30:38.000000000 +0200 @@ -162,41 +162,65 @@ /* Given src, dst and key, find appropriate for input tunnel. */ -static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net, +static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, __be32 remote, __be32 local, __be32 key) { + struct net *net = dev_net(dev); + int link = dev->ifindex; unsigned h0 = HASH(remote); unsigned h1 = HASH(key); - struct ip_tunnel *t; + struct ip_tunnel *t, *tlinkless = NULL; struct ipgre_net *ign = net_generic(net, ipgre_net_id); for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) { - if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) { - if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) + if (local == t->parms.iph.saddr && + remote == t->parms.iph.daddr && + key == t->parms.i_key && + (t->dev->flags & IFF_UP)) { + if (link == t->parms.link) return t; + if (tlinkless == NULL) + tlinkless = t; } } for (t = ign->tunnels_r[h0^h1]; t; t = t->next) { - if (remote == t->parms.iph.daddr) { - if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) + if (remote == t->parms.iph.daddr && + key == t->parms.i_key && + (t->dev->flags&IFF_UP)) { + if (link == t->parms.link) return t; + if (tlinkless == NULL) + tlinkless = t; } } for (t = ign->tunnels_l[h1]; t; t = t->next) { - if (local == t->parms.iph.saddr || - (local == t->parms.iph.daddr && - ipv4_is_multicast(local))) { - if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) + if ((local == t->parms.iph.saddr || + (local == t->parms.iph.daddr && ipv4_is_multicast(local))) && + key == t->parms.i_key && + (t->dev->flags & IFF_UP)) { + if (link == t->parms.link) return t; + if (tlinkless == NULL) + tlinkless = t; } } + for (t = ign->tunnels_wc[h1]; t; t = t->next) { - if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) - return t; + if (t->parms.i_key == key && + (t->dev->flags & IFF_UP)) { + if (link == t->parms.link) + return t; + if (tlinkless == NULL) + tlinkless = t; + } } - if (ign->fb_tunnel_dev->flags&IFF_UP) + if (tlinkless != NULL) + return tlinkless; + + if (ign->fb_tunnel_dev->flags & IFF_UP) return netdev_priv(ign->fb_tunnel_dev); + return NULL; } @@ -255,16 +279,18 @@ __be32 remote = parms->iph.daddr; __be32 local = parms->iph.saddr; __be32 key = parms->i_key; + int link = parms->link; struct ip_tunnel *t, **tp, *nt; struct net_device *dev; char name[IFNAMSIZ]; struct ipgre_net *ign = net_generic(net, ipgre_net_id); for (tp = __ipgre_bucket(ign, parms); (t = *tp) != NULL; tp = &t->next) { - if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) { - if (key == t->parms.i_key) - return t; - } + if (local == t->parms.iph.saddr && + remote == t->parms.iph.daddr && + key == t->parms.i_key && + link == t->parms.link) + return t; } if (!create) return NULL; @@ -379,7 +405,7 @@ } read_lock(&ipgre_lock); - t = ipgre_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr, + t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((__be32*)p) + (grehlen>>2) - 1) : 0); if (t == NULL || t->parms.iph.daddr == 0 || @@ -471,7 +497,7 @@ } read_lock(&ipgre_lock); - if ((tunnel = ipgre_tunnel_lookup(dev_net(skb->dev), + if ((tunnel = ipgre_tunnel_lookup(skb->dev, iph->saddr, iph->daddr, key)) != NULL) { secpath_reset(skb);