Browse Source

vti6: Keep set MTU on link creation or change, validate it

In vti6_link_config(), if MTU is already given on link creation
or change, validate and use it instead of recomputing it. To do
that, we need to propagate the knowledge that MTU was set by
userspace all the way down to vti6_link_config().

To keep this simple, vti6_dev_init() sets the new 'keep_mtu'
argument of vti6_link_config() to true: on initialization, we
don't have convenient access to netlink attributes there, but we
will anyway check whether dev->mtu is set in vti6_link_config().
If it's non-zero, it was set to the value of the IFLA_MTU
attribute during creation. Otherwise, determine a reasonable
value.

Fixes: ed1efb2aefbb ("ipv6: Add support for IPsec virtual tunnel interfaces")
Fixes: 53c81e95df17 ("ip6_vti: adjust vti mtu according to mtu of lower device")
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Acked-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Stefano Brivio 7 years ago
parent
commit
7a67e69a33
1 changed files with 16 additions and 8 deletions
  1. 16 8
      net/ipv6/ip6_vti.c

+ 16 - 8
net/ipv6/ip6_vti.c

@@ -622,7 +622,7 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	return 0;
 	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 net_device *dev = t->dev;
 	struct __ip6_tnl_parm *p = &t->parms;
 	struct __ip6_tnl_parm *p = &t->parms;
@@ -641,6 +641,11 @@ static void vti6_link_config(struct ip6_tnl *t)
 	else
 	else
 		dev->flags &= ~IFF_POINTOPOINT;
 		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) {
 	if (p->flags & IP6_TNL_F_CAP_XMIT) {
 		int strict = (ipv6_addr_type(&p->raddr) &
 		int strict = (ipv6_addr_type(&p->raddr) &
 			      (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
 			      (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
@@ -668,12 +673,14 @@ static void vti6_link_config(struct ip6_tnl *t)
  * vti6_tnl_change - update the tunnel parameters
  * vti6_tnl_change - update the tunnel parameters
  *   @t: tunnel to be changed
  *   @t: tunnel to be changed
  *   @p: tunnel configuration parameters
  *   @p: tunnel configuration parameters
+ *   @keep_mtu: MTU was set from userspace, don't re-compute it
  *
  *
  * Description:
  * Description:
  *   vti6_tnl_change() updates the tunnel parameters
  *   vti6_tnl_change() updates the tunnel parameters
  **/
  **/
 static int
 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.laddr = p->laddr;
 	t->parms.raddr = p->raddr;
 	t->parms.raddr = p->raddr;
@@ -683,11 +690,12 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
 	t->parms.proto = p->proto;
 	t->parms.proto = p->proto;
 	t->parms.fwmark = p->fwmark;
 	t->parms.fwmark = p->fwmark;
 	dst_cache_reset(&t->dst_cache);
 	dst_cache_reset(&t->dst_cache);
-	vti6_link_config(t);
+	vti6_link_config(t, keep_mtu);
 	return 0;
 	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 net *net = dev_net(t->dev);
 	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
 	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
@@ -695,7 +703,7 @@ static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
 
 
 	vti6_tnl_unlink(ip6n, t);
 	vti6_tnl_unlink(ip6n, t);
 	synchronize_net();
 	synchronize_net();
-	err = vti6_tnl_change(t, p);
+	err = vti6_tnl_change(t, p, keep_mtu);
 	vti6_tnl_link(ip6n, t);
 	vti6_tnl_link(ip6n, t);
 	netdev_state_change(t->dev);
 	netdev_state_change(t->dev);
 	return err;
 	return err;
@@ -808,7 +816,7 @@ vti6_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 			} else
 			} else
 				t = netdev_priv(dev);
 				t = netdev_priv(dev);
 
 
-			err = vti6_update(t, &p1);
+			err = vti6_update(t, &p1, false);
 		}
 		}
 		if (t) {
 		if (t) {
 			err = 0;
 			err = 0;
@@ -907,7 +915,7 @@ static int vti6_dev_init(struct net_device *dev)
 
 
 	if (err)
 	if (err)
 		return err;
 		return err;
-	vti6_link_config(t);
+	vti6_link_config(t, true);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1012,7 +1020,7 @@ static int vti6_changelink(struct net_device *dev, struct nlattr *tb[],
 	} else
 	} else
 		t = netdev_priv(dev);
 		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)
 static size_t vti6_get_size(const struct net_device *dev)