aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/ip_tunnel.c7
-rw-r--r--net/ipv4/ip_vti.c2
-rw-r--r--net/ipv6/ip6_vti.c36
-rw-r--r--net/xfrm/xfrm_input.c6
-rw-r--r--net/xfrm/xfrm_output.c5
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[],
1117 eth_hw_addr_random(dev); 1117 eth_hw_addr_random(dev);
1118 1118
1119 mtu = ip_tunnel_bind_dev(dev); 1119 mtu = ip_tunnel_bind_dev(dev);
1120 if (!tb[IFLA_MTU]) { 1120 if (tb[IFLA_MTU]) {
1121 unsigned int max = 0xfff8 - dev->hard_header_len - nt->hlen;
1122
1123 dev->mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU,
1124 (unsigned int)(max - sizeof(struct iphdr)));
1125 } else {
1121 err = dev_set_mtu(dev, mtu); 1126 err = dev_set_mtu(dev, mtu);
1122 if (err) 1127 if (err)
1123 goto err_dev_set_mtu; 1128 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)
387 memcpy(dev->dev_addr, &iph->saddr, 4); 387 memcpy(dev->dev_addr, &iph->saddr, 4);
388 memcpy(dev->broadcast, &iph->daddr, 4); 388 memcpy(dev->broadcast, &iph->daddr, 4);
389 389
390 dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr);
391 dev->mtu = ETH_DATA_LEN;
392 dev->flags = IFF_NOARP; 390 dev->flags = IFF_NOARP;
393 dev->addr_len = 4; 391 dev->addr_len = 4;
394 dev->features |= NETIF_F_LLTX; 392 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,
622 return 0; 622 return 0;
623} 623}
624 624
625static void vti6_link_config(struct ip6_tnl *t) 625static void vti6_link_config(struct ip6_tnl *t, bool keep_mtu)
626{ 626{
627 struct net_device *dev = t->dev; 627 struct net_device *dev = t->dev;
628 struct __ip6_tnl_parm *p = &t->parms; 628 struct __ip6_tnl_parm *p = &t->parms;
629 struct net_device *tdev = NULL; 629 struct net_device *tdev = NULL;
630 int mtu;
630 631
631 memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); 632 memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
632 memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); 633 memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
@@ -640,6 +641,11 @@ static void vti6_link_config(struct ip6_tnl *t)
640 else 641 else
641 dev->flags &= ~IFF_POINTOPOINT; 642 dev->flags &= ~IFF_POINTOPOINT;
642 643
644 if (keep_mtu && dev->mtu) {
645 dev->mtu = clamp(dev->mtu, dev->min_mtu, dev->max_mtu);
646 return;
647 }
648
643 if (p->flags & IP6_TNL_F_CAP_XMIT) { 649 if (p->flags & IP6_TNL_F_CAP_XMIT) {
644 int strict = (ipv6_addr_type(&p->raddr) & 650 int strict = (ipv6_addr_type(&p->raddr) &
645 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); 651 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
@@ -656,20 +662,25 @@ static void vti6_link_config(struct ip6_tnl *t)
656 tdev = __dev_get_by_index(t->net, p->link); 662 tdev = __dev_get_by_index(t->net, p->link);
657 663
658 if (tdev) 664 if (tdev)
659 dev->mtu = max_t(int, tdev->mtu - dev->hard_header_len, 665 mtu = tdev->mtu - sizeof(struct ipv6hdr);
660 IPV6_MIN_MTU); 666 else
667 mtu = ETH_DATA_LEN - LL_MAX_HEADER - sizeof(struct ipv6hdr);
668
669 dev->mtu = max_t(int, mtu, IPV6_MIN_MTU);
661} 670}
662 671
663/** 672/**
664 * vti6_tnl_change - update the tunnel parameters 673 * vti6_tnl_change - update the tunnel parameters
665 * @t: tunnel to be changed 674 * @t: tunnel to be changed
666 * @p: tunnel configuration parameters 675 * @p: tunnel configuration parameters
676 * @keep_mtu: MTU was set from userspace, don't re-compute it
667 * 677 *
668 * Description: 678 * Description:
669 * vti6_tnl_change() updates the tunnel parameters 679 * vti6_tnl_change() updates the tunnel parameters
670 **/ 680 **/
671static int 681static int
672vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) 682vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p,
683 bool keep_mtu)
673{ 684{
674 t->parms.laddr = p->laddr; 685 t->parms.laddr = p->laddr;
675 t->parms.raddr = p->raddr; 686 t->parms.raddr = p->raddr;
@@ -679,11 +690,12 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
679 t->parms.proto = p->proto; 690 t->parms.proto = p->proto;
680 t->parms.fwmark = p->fwmark; 691 t->parms.fwmark = p->fwmark;
681 dst_cache_reset(&t->dst_cache); 692 dst_cache_reset(&t->dst_cache);
682 vti6_link_config(t); 693 vti6_link_config(t, keep_mtu);
683 return 0; 694 return 0;
684} 695}
685 696
686static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p) 697static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p,
698 bool keep_mtu)
687{ 699{
688 struct net *net = dev_net(t->dev); 700 struct net *net = dev_net(t->dev);
689 struct vti6_net *ip6n = net_generic(net, vti6_net_id); 701 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)
691 703
692 vti6_tnl_unlink(ip6n, t); 704 vti6_tnl_unlink(ip6n, t);
693 synchronize_net(); 705 synchronize_net();
694 err = vti6_tnl_change(t, p); 706 err = vti6_tnl_change(t, p, keep_mtu);
695 vti6_tnl_link(ip6n, t); 707 vti6_tnl_link(ip6n, t);
696 netdev_state_change(t->dev); 708 netdev_state_change(t->dev);
697 return err; 709 return err;
@@ -804,7 +816,7 @@ vti6_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
804 } else 816 } else
805 t = netdev_priv(dev); 817 t = netdev_priv(dev);
806 818
807 err = vti6_update(t, &p1); 819 err = vti6_update(t, &p1, false);
808 } 820 }
809 if (t) { 821 if (t) {
810 err = 0; 822 err = 0;
@@ -866,10 +878,8 @@ static void vti6_dev_setup(struct net_device *dev)
866 dev->priv_destructor = vti6_dev_free; 878 dev->priv_destructor = vti6_dev_free;
867 879
868 dev->type = ARPHRD_TUNNEL6; 880 dev->type = ARPHRD_TUNNEL6;
869 dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr);
870 dev->mtu = ETH_DATA_LEN;
871 dev->min_mtu = IPV6_MIN_MTU; 881 dev->min_mtu = IPV6_MIN_MTU;
872 dev->max_mtu = IP_MAX_MTU; 882 dev->max_mtu = IP_MAX_MTU - sizeof(struct ipv6hdr);
873 dev->flags |= IFF_NOARP; 883 dev->flags |= IFF_NOARP;
874 dev->addr_len = sizeof(struct in6_addr); 884 dev->addr_len = sizeof(struct in6_addr);
875 netif_keep_dst(dev); 885 netif_keep_dst(dev);
@@ -905,7 +915,7 @@ static int vti6_dev_init(struct net_device *dev)
905 915
906 if (err) 916 if (err)
907 return err; 917 return err;
908 vti6_link_config(t); 918 vti6_link_config(t, true);
909 return 0; 919 return 0;
910} 920}
911 921
@@ -1010,7 +1020,7 @@ static int vti6_changelink(struct net_device *dev, struct nlattr *tb[],
1010 } else 1020 } else
1011 t = netdev_priv(dev); 1021 t = netdev_priv(dev);
1012 1022
1013 return vti6_update(t, &p); 1023 return vti6_update(t, &p, tb && tb[IFLA_MTU]);
1014} 1024}
1015 1025
1016static size_t vti6_get_size(const struct net_device *dev) 1026static 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 {
26}; 26};
27 27
28struct xfrm_trans_cb { 28struct xfrm_trans_cb {
29 union {
30 struct inet_skb_parm h4;
31#if IS_ENABLED(CONFIG_IPV6)
32 struct inet6_skb_parm h6;
33#endif
34 } header;
29 int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb); 35 int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb);
30}; 36};
31 37
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)
285 return; 285 return;
286 286
287 afinfo = xfrm_state_get_afinfo(proto); 287 afinfo = xfrm_state_get_afinfo(proto);
288 if (afinfo) 288 if (afinfo) {
289 afinfo->local_error(skb, mtu); 289 afinfo->local_error(skb, mtu);
290 rcu_read_unlock(); 290 rcu_read_unlock();
291 }
291} 292}
292EXPORT_SYMBOL_GPL(xfrm_local_error); 293EXPORT_SYMBOL_GPL(xfrm_local_error);