diff options
| -rw-r--r-- | net/ipv4/ip_tunnel.c | 7 | ||||
| -rw-r--r-- | net/ipv4/ip_vti.c | 2 | ||||
| -rw-r--r-- | net/ipv6/ip6_vti.c | 36 | ||||
| -rw-r--r-- | net/xfrm/xfrm_input.c | 6 | ||||
| -rw-r--r-- | net/xfrm/xfrm_output.c | 5 | 
5 files changed, 38 insertions, 18 deletions
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 7b85ffad5d74..f3db1f35a79d 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -1117,7 +1117,12 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],  		eth_hw_addr_random(dev);  	mtu = ip_tunnel_bind_dev(dev); -	if (!tb[IFLA_MTU]) { +	if (tb[IFLA_MTU]) { +		unsigned int max = 0xfff8 - dev->hard_header_len - nt->hlen; + +		dev->mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU, +				 (unsigned int)(max - sizeof(struct iphdr))); +	} else {  		err = dev_set_mtu(dev, mtu);  		if (err)  			goto err_dev_set_mtu; diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 51b1669334fe..3f091ccad9af 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -387,8 +387,6 @@ static int vti_tunnel_init(struct net_device *dev)  	memcpy(dev->dev_addr, &iph->saddr, 4);  	memcpy(dev->broadcast, &iph->daddr, 4); -	dev->hard_header_len	= LL_MAX_HEADER + sizeof(struct iphdr); -	dev->mtu		= ETH_DATA_LEN;  	dev->flags		= IFF_NOARP;  	dev->addr_len		= 4;  	dev->features		|= NETIF_F_LLTX; diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index fa3ae1cb50d3..ce18cd20389d 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -622,11 +622,12 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,  	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;  	struct net_device *tdev = NULL; +	int mtu;  	memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));  	memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); @@ -640,6 +641,11 @@ static void vti6_link_config(struct ip6_tnl *t)  	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)); @@ -656,20 +662,25 @@ static void vti6_link_config(struct ip6_tnl *t)  		tdev = __dev_get_by_index(t->net, p->link);  	if (tdev) -		dev->mtu = max_t(int, tdev->mtu - dev->hard_header_len, -				 IPV6_MIN_MTU); +		mtu = tdev->mtu - sizeof(struct ipv6hdr); +	else +		mtu = ETH_DATA_LEN - LL_MAX_HEADER - sizeof(struct ipv6hdr); + +	dev->mtu = max_t(int, mtu, IPV6_MIN_MTU);  }  /**   * 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; @@ -679,11 +690,12 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)  	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); @@ -691,7 +703,7 @@ static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)  	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; @@ -804,7 +816,7 @@ vti6_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)  			} else  				t = netdev_priv(dev); -			err = vti6_update(t, &p1); +			err = vti6_update(t, &p1, false);  		}  		if (t) {  			err = 0; @@ -866,10 +878,8 @@ static void vti6_dev_setup(struct net_device *dev)  	dev->priv_destructor = vti6_dev_free;  	dev->type = ARPHRD_TUNNEL6; -	dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr); -	dev->mtu = ETH_DATA_LEN;  	dev->min_mtu = IPV6_MIN_MTU; -	dev->max_mtu = IP_MAX_MTU; +	dev->max_mtu = IP_MAX_MTU - sizeof(struct ipv6hdr);  	dev->flags |= IFF_NOARP;  	dev->addr_len = sizeof(struct in6_addr);  	netif_keep_dst(dev); @@ -905,7 +915,7 @@ static int vti6_dev_init(struct net_device *dev)  	if (err)  		return err; -	vti6_link_config(t); +	vti6_link_config(t, true);  	return 0;  } @@ -1010,7 +1020,7 @@ static int vti6_changelink(struct net_device *dev, struct nlattr *tb[],  	} 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) diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 1472c0857975..81788105c164 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -26,6 +26,12 @@ struct xfrm_trans_tasklet {  };  struct xfrm_trans_cb { +	union { +		struct inet_skb_parm	h4; +#if IS_ENABLED(CONFIG_IPV6) +		struct inet6_skb_parm	h6; +#endif +	} header;  	int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb);  }; diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 23468672a767..89b178a78dc7 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -285,8 +285,9 @@ void xfrm_local_error(struct sk_buff *skb, int mtu)  		return;  	afinfo = xfrm_state_get_afinfo(proto); -	if (afinfo) +	if (afinfo) {  		afinfo->local_error(skb, mtu); -	rcu_read_unlock(); +		rcu_read_unlock(); +	}  }  EXPORT_SYMBOL_GPL(xfrm_local_error);  | 
