aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2017-10-26 07:27:17 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-27 10:45:42 -0400
commit8aec4959d832bae0889a8e2f348973b5e4abffef (patch)
tree836c695f7362deabd94423583c1b71a5174c6f72
parentf8d20b46ce55cf40afb30dcef6d9288f7ef46d9b (diff)
ip6_gre: update dst pmtu if dev mtu has been updated by toobig in __gre6_xmit
When receiving a Toobig icmpv6 packet, ip6gre_err would just set tunnel dev's mtu, that's not enough. For skb_dst(skb)'s pmtu may still be using the old value, it has no chance to be updated with tunnel dev's mtu. Jianlin found this issue by reducing route's mtu while running netperf, the performance went to 0. ip6ip6 and ip4ip6 tunnel can work well with this, as they lookup the upper dst and update_pmtu it's pmtu or icmpv6_send a Toobig to upper socket after setting tunnel dev's mtu. We couldn't do that for ip6_gre, as gre's inner packet could be any protocol, it's difficult to handle them (like lookup upper dst) in a good way. So this patch is to fix it by updating skb_dst(skb)'s pmtu when dev->mtu < skb_dst(skb)'s pmtu in tx path. It's safe to do this update there, as usually dev->mtu <= skb_dst(skb)'s pmtu and no performance regression can be caused by this. Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Reported-by: Jianlin Shi <jishi@redhat.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/ip6_gre.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index fb595e8dc15b..59c121b932ac 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -503,8 +503,8 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
503 __u32 *pmtu, __be16 proto) 503 __u32 *pmtu, __be16 proto)
504{ 504{
505 struct ip6_tnl *tunnel = netdev_priv(dev); 505 struct ip6_tnl *tunnel = netdev_priv(dev);
506 __be16 protocol = (dev->type == ARPHRD_ETHER) ? 506 struct dst_entry *dst = skb_dst(skb);
507 htons(ETH_P_TEB) : proto; 507 __be16 protocol;
508 508
509 if (dev->type == ARPHRD_ETHER) 509 if (dev->type == ARPHRD_ETHER)
510 IPCB(skb)->flags = 0; 510 IPCB(skb)->flags = 0;
@@ -518,9 +518,14 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
518 tunnel->o_seqno++; 518 tunnel->o_seqno++;
519 519
520 /* Push GRE header. */ 520 /* Push GRE header. */
521 protocol = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : proto;
521 gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags, 522 gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags,
522 protocol, tunnel->parms.o_key, htonl(tunnel->o_seqno)); 523 protocol, tunnel->parms.o_key, htonl(tunnel->o_seqno));
523 524
525 /* TooBig packet may have updated dst->dev's mtu */
526 if (dst && dst_mtu(dst) > dst->dev->mtu)
527 dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu);
528
524 return ip6_tnl_xmit(skb, dev, dsfield, fl6, encap_limit, pmtu, 529 return ip6_tnl_xmit(skb, dev, dsfield, fl6, encap_limit, pmtu,
525 NEXTHDR_GRE); 530 NEXTHDR_GRE);
526} 531}