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[], | |||
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 | ||
625 | static void vti6_link_config(struct ip6_tnl *t) | 625 | static 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 | **/ |
671 | static int | 681 | static int |
672 | vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) | 682 | vti6_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 | ||
686 | static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p) | 697 | static 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 | ||
1016 | static size_t vti6_get_size(const struct net_device *dev) | 1026 | 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 { | |||
26 | }; | 26 | }; |
27 | 27 | ||
28 | struct xfrm_trans_cb { | 28 | struct 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 | } |
292 | EXPORT_SYMBOL_GPL(xfrm_local_error); | 293 | EXPORT_SYMBOL_GPL(xfrm_local_error); |