return 0;
 }
 
-static void vti6_link_config(struct ip6_tnl *t)
+static void vti6_link_config(struct ip6_tnl *t, bool keep_mtu)
 {
        struct net_device *dev = t->dev;
        struct __ip6_tnl_parm *p = &t->parms;
        else
                dev->flags &= ~IFF_POINTOPOINT;
 
+       if (keep_mtu && dev->mtu) {
+               dev->mtu = clamp(dev->mtu, dev->min_mtu, dev->max_mtu);
+               return;
+       }
+
        if (p->flags & IP6_TNL_F_CAP_XMIT) {
                int strict = (ipv6_addr_type(&p->raddr) &
                              (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
  * vti6_tnl_change - update the tunnel parameters
  *   @t: tunnel to be changed
  *   @p: tunnel configuration parameters
+ *   @keep_mtu: MTU was set from userspace, don't re-compute it
  *
  * Description:
  *   vti6_tnl_change() updates the tunnel parameters
  **/
 static int
-vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
+vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p,
+               bool keep_mtu)
 {
        t->parms.laddr = p->laddr;
        t->parms.raddr = p->raddr;
        t->parms.proto = p->proto;
        t->parms.fwmark = p->fwmark;
        dst_cache_reset(&t->dst_cache);
-       vti6_link_config(t);
+       vti6_link_config(t, keep_mtu);
        return 0;
 }
 
-static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
+static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p,
+                      bool keep_mtu)
 {
        struct net *net = dev_net(t->dev);
        struct vti6_net *ip6n = net_generic(net, vti6_net_id);
 
        vti6_tnl_unlink(ip6n, t);
        synchronize_net();
-       err = vti6_tnl_change(t, p);
+       err = vti6_tnl_change(t, p, keep_mtu);
        vti6_tnl_link(ip6n, t);
        netdev_state_change(t->dev);
        return err;
                        } else
                                t = netdev_priv(dev);
 
-                       err = vti6_update(t, &p1);
+                       err = vti6_update(t, &p1, false);
                }
                if (t) {
                        err = 0;
 
        if (err)
                return err;
-       vti6_link_config(t);
+       vti6_link_config(t, true);
        return 0;
 }
 
        } else
                t = netdev_priv(dev);
 
-       return vti6_update(t, &p);
+       return vti6_update(t, &p, tb && tb[IFLA_MTU]);
 }
 
 static size_t vti6_get_size(const struct net_device *dev)