Index: linux-4.19.118/drivers/net/vxlan.c
===================================================================
--- linux-4.19.118.orig/drivers/net/vxlan.c
+++ linux-4.19.118/drivers/net/vxlan.c
@@ -53,6 +53,22 @@ static bool log_ecn_error = true;
 module_param(log_ecn_error, bool, 0644);
 MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
 
+static unsigned short vxlan_max_mtu = 1500;
+module_param_named(max_mtu, vxlan_max_mtu, ushort, 0664);
+MODULE_PARM_DESC(max_mtu, "Max allowed MTU");
+
+static unsigned short vxlan_def_mtu __read_mostly = 0;
+module_param_named(mtu, vxlan_def_mtu, ushort, 0664);
+MODULE_PARM_DESC(default_mtu, "Default MTU or 0 for underlying device MTU.");
+
+static bool vxlan_slave_mtu __read_mostly = true;
+module_param_named(slave_mtu, vxlan_slave_mtu, bool, 0664);
+MODULE_PARM_DESC(slave_mtu, "MTU slaved to underlying interface and cannot exceed its MTU");
+
+static bool vxlan_clear_df __read_mostly = false;
+module_param_named(clear_df, vxlan_clear_df, bool, 0664);
+MODULE_PARM_DESC(clear_df, "Clear DF bit for all packets, otherwise only packets larger then physical device MTU will be cleared");
+
 static unsigned int vxlan_net_id;
 static struct rtnl_link_ops vxlan_link_ops;
 
@@ -2208,9 +2224,14 @@ static void vxlan_xmit_one(struct sk_buf
 						    &rt->dst, rt->rt_flags);
 			if (err)
 				goto out_unlock;
-		} else if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT) {
-			df = htons(IP_DF);
-		}
+		} else if (!vxlan_clear_df && info->key.tun_flags & TUNNEL_DONT_FRAGMENT) {
+			u32 rtm = 0;
+
+			rtm = (rt->dst.dev && rt->dst.dev->mtu) ? rt->dst.dev->mtu : 0;
+			if (vxlan_slave_mtu || (rtm && skb->len <= (rtm - VXLAN_HEADROOM)))
+				df = htons(IP_DF);
+		} else
+			df = 0;
 
 		ndst = &rt->dst;
 		skb_tunnel_check_pmtu(skb, ndst, VXLAN_HEADROOM);
@@ -2569,12 +2590,14 @@ static int vxlan_change_mtu(struct net_d
 	/* This check is different than dev->max_mtu, because it looks at
 	 * the lowerdev->mtu, rather than the static dev->max_mtu
 	 */
-	if (lowerdev) {
+	if (lowerdev && vxlan_slave_mtu) {
 		int max_mtu = lowerdev->mtu -
 			      (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM);
 		if (new_mtu > max_mtu)
 			return -EINVAL;
 	}
+	if (new_mtu > vxlan_max_mtu || new_mtu < 68)
+		return -EINVAL;
 
 	dev->mtu = new_mtu;
 	return 0;
@@ -2791,7 +2814,7 @@ static int vxlan_validate(struct nlattr
 	if (tb[IFLA_MTU]) {
 		u32 mtu = nla_get_u32(tb[IFLA_MTU]);
 
-		if (mtu < ETH_MIN_MTU || mtu > ETH_MAX_MTU) {
+		if (mtu < ETH_MIN_MTU || (mtu > ETH_MAX_MTU && vxlan_slave_mtu)) {
 			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_MTU],
 					    "MTU must be between 68 and 65535");
 			return -EINVAL;
@@ -3147,7 +3170,7 @@ static void vxlan_config_apply(struct ne
 	struct vxlan_rdst *dst = &vxlan->default_dst;
 	unsigned short needed_headroom = ETH_HLEN;
 	bool use_ipv6 = !!(conf->flags & VXLAN_F_IPV6);
-	int max_mtu = ETH_MAX_MTU;
+	int max_mtu = (vxlan_def_mtu > ETH_MIN_MTU) ? vxlan_def_mtu : ETH_MAX_MTU;
 
 	if (!changelink) {
 		if (conf->flags & VXLAN_F_GPE)
@@ -3173,17 +3196,28 @@ static void vxlan_config_apply(struct ne
 
 		needed_headroom = lowerdev->hard_header_len;
 
-		max_mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM :
+		if (vxlan_slave_mtu)
+			max_mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM :
 					   VXLAN_HEADROOM);
 		if (max_mtu < ETH_MIN_MTU)
 			max_mtu = ETH_MIN_MTU;
 
+		if (vxlan_max_mtu && max_mtu > vxlan_max_mtu)
+			max_mtu = vxlan_max_mtu;
+
 		if (!changelink && !conf->mtu)
 			dev->mtu = max_mtu;
-	}
+		else
+			(void) vxlan_change_mtu(dev,
+				       	conf->mtu ? conf->mtu : max_mtu);
 
-	if (dev->mtu > max_mtu)
-		dev->mtu = max_mtu;
+	} else if (conf->mtu && conf->mtu >= dev->min_mtu &&
+		   (!vxlan_slave_mtu || conf->mtu <= dev->max_mtu)) {
+		dev->mtu = conf->mtu;
+	} else if (!changelink) {
+			dev->mtu = max_mtu;
+	} else
+		(void) vxlan_change_mtu(dev, max_mtu);
 
 	if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA)
 		needed_headroom += VXLAN6_HEADROOM;
@@ -3471,9 +3505,14 @@ static int vxlan_nl2conf(struct nlattr *
 	}
 
 	if (tb[IFLA_MTU]) {
-		if (changelink)
-			return -EOPNOTSUPP;
 		conf->mtu = nla_get_u32(tb[IFLA_MTU]);
+		if (conf->mtu < dev->min_mtu) {
+				return -EINVAL;
+		} else if (conf->mtu > dev->max_mtu && vxlan_slave_mtu) {
+				return -EINVAL;
+		}
+		if (vxlan_change_mtu(dev, conf->mtu))
+			return -EINVAL;
 	}
 
 	return 0;
