diff options
Diffstat (limited to 'net/ipv4/ip_tunnel.c')
-rw-r--r-- | net/ipv4/ip_tunnel.c | 38 |
1 files changed, 9 insertions, 29 deletions
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index e189db409b0e..a06a2ed49597 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c | |||
@@ -491,19 +491,17 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
491 | { | 491 | { |
492 | struct ip_tunnel *tunnel = netdev_priv(dev); | 492 | struct ip_tunnel *tunnel = netdev_priv(dev); |
493 | const struct iphdr *inner_iph; | 493 | const struct iphdr *inner_iph; |
494 | struct iphdr *iph; | ||
495 | struct flowi4 fl4; | 494 | struct flowi4 fl4; |
496 | u8 tos, ttl; | 495 | u8 tos, ttl; |
497 | __be16 df; | 496 | __be16 df; |
498 | struct rtable *rt; /* Route to the other host */ | 497 | struct rtable *rt; /* Route to the other host */ |
499 | struct net_device *tdev; /* Device to other host */ | ||
500 | unsigned int max_headroom; /* The extra header space needed */ | 498 | unsigned int max_headroom; /* The extra header space needed */ |
501 | __be32 dst; | 499 | __be32 dst; |
502 | int mtu; | 500 | int mtu; |
501 | int err; | ||
503 | 502 | ||
504 | inner_iph = (const struct iphdr *)skb_inner_network_header(skb); | 503 | inner_iph = (const struct iphdr *)skb_inner_network_header(skb); |
505 | 504 | ||
506 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); | ||
507 | dst = tnl_params->daddr; | 505 | dst = tnl_params->daddr; |
508 | if (dst == 0) { | 506 | if (dst == 0) { |
509 | /* NBMA tunnel */ | 507 | /* NBMA tunnel */ |
@@ -571,14 +569,11 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
571 | dev->stats.tx_carrier_errors++; | 569 | dev->stats.tx_carrier_errors++; |
572 | goto tx_error; | 570 | goto tx_error; |
573 | } | 571 | } |
574 | tdev = rt->dst.dev; | 572 | if (rt->dst.dev == dev) { |
575 | |||
576 | if (tdev == dev) { | ||
577 | ip_rt_put(rt); | 573 | ip_rt_put(rt); |
578 | dev->stats.collisions++; | 574 | dev->stats.collisions++; |
579 | goto tx_error; | 575 | goto tx_error; |
580 | } | 576 | } |
581 | |||
582 | df = tnl_params->frag_off; | 577 | df = tnl_params->frag_off; |
583 | 578 | ||
584 | if (df) | 579 | if (df) |
@@ -596,6 +591,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
596 | if (!skb_is_gso(skb) && | 591 | if (!skb_is_gso(skb) && |
597 | (inner_iph->frag_off&htons(IP_DF)) && | 592 | (inner_iph->frag_off&htons(IP_DF)) && |
598 | mtu < ntohs(inner_iph->tot_len)) { | 593 | mtu < ntohs(inner_iph->tot_len)) { |
594 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); | ||
599 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); | 595 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); |
600 | ip_rt_put(rt); | 596 | ip_rt_put(rt); |
601 | goto tx_error; | 597 | goto tx_error; |
@@ -646,8 +642,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
646 | ttl = ip4_dst_hoplimit(&rt->dst); | 642 | ttl = ip4_dst_hoplimit(&rt->dst); |
647 | } | 643 | } |
648 | 644 | ||
649 | max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr) | 645 | max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr) |
650 | + rt->dst.header_len; | 646 | + rt->dst.header_len; |
651 | if (max_headroom > dev->needed_headroom) { | 647 | if (max_headroom > dev->needed_headroom) { |
652 | dev->needed_headroom = max_headroom; | 648 | dev->needed_headroom = max_headroom; |
653 | if (skb_cow_head(skb, dev->needed_headroom)) { | 649 | if (skb_cow_head(skb, dev->needed_headroom)) { |
@@ -657,27 +653,11 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
657 | } | 653 | } |
658 | } | 654 | } |
659 | 655 | ||
660 | skb_dst_drop(skb); | 656 | err = iptunnel_xmit(dev_net(dev), rt, skb, |
661 | skb_dst_set(skb, &rt->dst); | 657 | fl4.saddr, fl4.daddr, protocol, |
662 | 658 | ip_tunnel_ecn_encap(tos, inner_iph, skb), ttl, df); | |
663 | /* Push down and install the IP header. */ | 659 | iptunnel_xmit_stats(err, &dev->stats, dev->tstats); |
664 | skb_push(skb, sizeof(struct iphdr)); | ||
665 | skb_reset_network_header(skb); | ||
666 | |||
667 | iph = ip_hdr(skb); | ||
668 | inner_iph = (const struct iphdr *)skb_inner_network_header(skb); | ||
669 | 660 | ||
670 | iph->version = 4; | ||
671 | iph->ihl = sizeof(struct iphdr) >> 2; | ||
672 | iph->frag_off = df; | ||
673 | iph->protocol = protocol; | ||
674 | iph->tos = ip_tunnel_ecn_encap(tos, inner_iph, skb); | ||
675 | iph->daddr = fl4.daddr; | ||
676 | iph->saddr = fl4.saddr; | ||
677 | iph->ttl = ttl; | ||
678 | tunnel_ip_select_ident(skb, inner_iph, &rt->dst); | ||
679 | |||
680 | iptunnel_xmit(skb, dev); | ||
681 | return; | 661 | return; |
682 | 662 | ||
683 | #if IS_ENABLED(CONFIG_IPV6) | 663 | #if IS_ENABLED(CONFIG_IPV6) |