aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_tunnel.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ip_tunnel.c')
-rw-r--r--net/ipv4/ip_tunnel.c38
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)