/**
  * ip6_tnl_lookup - fetch tunnel matching the end-point addresses
+ *   @link: ifindex of underlying interface
  *   @remote: the address of the tunnel exit-point
  *   @local: the address of the tunnel entry-point
  *
        for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
 
 static struct ip6_tnl *
-ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
+ip6_tnl_lookup(struct net *net, int link,
+              const struct in6_addr *remote, const struct in6_addr *local)
 {
        unsigned int hash = HASH(remote, local);
-       struct ip6_tnl *t;
+       struct ip6_tnl *t, *cand = NULL;
        struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
        struct in6_addr any;
 
        for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
-               if (ipv6_addr_equal(local, &t->parms.laddr) &&
-                   ipv6_addr_equal(remote, &t->parms.raddr) &&
-                   (t->dev->flags & IFF_UP))
+               if (!ipv6_addr_equal(local, &t->parms.laddr) ||
+                   !ipv6_addr_equal(remote, &t->parms.raddr) ||
+                   !(t->dev->flags & IFF_UP))
+                       continue;
+
+               if (link == t->parms.link)
                        return t;
+               else
+                       cand = t;
        }
 
        memset(&any, 0, sizeof(any));
        hash = HASH(&any, local);
        for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
-               if (ipv6_addr_equal(local, &t->parms.laddr) &&
-                   ipv6_addr_any(&t->parms.raddr) &&
-                   (t->dev->flags & IFF_UP))
+               if (!ipv6_addr_equal(local, &t->parms.laddr) ||
+                   !ipv6_addr_any(&t->parms.raddr) ||
+                   !(t->dev->flags & IFF_UP))
+                       continue;
+
+               if (link == t->parms.link)
                        return t;
+               else if (!cand)
+                       cand = t;
        }
 
        hash = HASH(remote, &any);
        for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
-               if (ipv6_addr_equal(remote, &t->parms.raddr) &&
-                   ipv6_addr_any(&t->parms.laddr) &&
-                   (t->dev->flags & IFF_UP))
+               if (!ipv6_addr_equal(remote, &t->parms.raddr) ||
+                   !ipv6_addr_any(&t->parms.laddr) ||
+                   !(t->dev->flags & IFF_UP))
+                       continue;
+
+               if (link == t->parms.link)
                        return t;
+               else if (!cand)
+                       cand = t;
        }
 
+       if (cand)
+               return cand;
+
        t = rcu_dereference(ip6n->collect_md_tun);
        if (t && t->dev->flags & IFF_UP)
                return t;
             (t = rtnl_dereference(*tp)) != NULL;
             tp = &t->next) {
                if (ipv6_addr_equal(local, &t->parms.laddr) &&
-                   ipv6_addr_equal(remote, &t->parms.raddr)) {
+                   ipv6_addr_equal(remote, &t->parms.raddr) &&
+                   p->link == t->parms.link) {
                        if (create)
                                return ERR_PTR(-EEXIST);
 
           processing of the error. */
 
        rcu_read_lock();
-       t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr, &ipv6h->saddr);
+       t = ip6_tnl_lookup(dev_net(skb->dev), skb->dev->ifindex, &ipv6h->daddr, &ipv6h->saddr);
        if (!t)
                goto out;
 
        int ret = -1;
 
        rcu_read_lock();
-       t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
+       t = ip6_tnl_lookup(dev_net(skb->dev), skb->dev->ifindex, &ipv6h->saddr, &ipv6h->daddr);
 
        if (t) {
                u8 tproto = READ_ONCE(t->parms.proto);
 static void ip6_tnl_link_config(struct ip6_tnl *t)
 {
        struct net_device *dev = t->dev;
+       struct net_device *tdev = NULL;
        struct __ip6_tnl_parm *p = &t->parms;
        struct flowi6 *fl6 = &t->fl.u.ip6;
+       unsigned int mtu;
        int t_hlen;
 
        memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
                struct rt6_info *rt = rt6_lookup(t->net,
                                                 &p->raddr, &p->laddr,
                                                 p->link, NULL, strict);
+               if (rt) {
+                       tdev = rt->dst.dev;
+                       ip6_rt_put(rt);
+               }
 
-               if (!rt)
-                       return;
+               if (!tdev && p->link)
+                       tdev = __dev_get_by_index(t->net, p->link);
 
-               if (rt->dst.dev) {
-                       dev->hard_header_len = rt->dst.dev->hard_header_len +
-                               t_hlen;
+               if (tdev) {
+                       dev->hard_header_len = tdev->hard_header_len + t_hlen;
+                       mtu = min_t(unsigned int, tdev->mtu, IP6_MAX_MTU);
 
-                       dev->mtu = rt->dst.dev->mtu - t_hlen;
+                       dev->mtu = mtu - t_hlen;
                        if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
                                dev->mtu -= 8;
 
                        if (dev->mtu < IPV6_MIN_MTU)
                                dev->mtu = IPV6_MIN_MTU;
                }
-               ip6_rt_put(rt);
        }
 }