]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/ipv4/ip_tunnel.c
ip_tunnels: extend iptunnel_xmit()
[karo-tx-linux.git] / net / ipv4 / ip_tunnel.c
index e189db409b0efb335ff17915c9aae3339d384104..a06a2ed49597ade4922eb3c15cb98bb16b46e5b3 100644 (file)
@@ -491,19 +491,17 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
        const struct iphdr *inner_iph;
-       struct iphdr *iph;
        struct flowi4 fl4;
        u8     tos, ttl;
        __be16 df;
        struct rtable *rt;              /* Route to the other host */
-       struct net_device *tdev;        /* Device to other host */
        unsigned int max_headroom;      /* The extra header space needed */
        __be32 dst;
        int mtu;
+       int err;
 
        inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
 
-       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
        dst = tnl_params->daddr;
        if (dst == 0) {
                /* NBMA tunnel */
@@ -571,14 +569,11 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                dev->stats.tx_carrier_errors++;
                goto tx_error;
        }
-       tdev = rt->dst.dev;
-
-       if (tdev == dev) {
+       if (rt->dst.dev == dev) {
                ip_rt_put(rt);
                dev->stats.collisions++;
                goto tx_error;
        }
-
        df = tnl_params->frag_off;
 
        if (df)
@@ -596,6 +591,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                if (!skb_is_gso(skb) &&
                    (inner_iph->frag_off&htons(IP_DF)) &&
                     mtu < ntohs(inner_iph->tot_len)) {
+                       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
                        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
                        ip_rt_put(rt);
                        goto tx_error;
@@ -646,8 +642,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                        ttl = ip4_dst_hoplimit(&rt->dst);
        }
 
-       max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr)
-                                              + rt->dst.header_len;
+       max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr)
+                       + rt->dst.header_len;
        if (max_headroom > dev->needed_headroom) {
                dev->needed_headroom = max_headroom;
                if (skb_cow_head(skb, dev->needed_headroom)) {
@@ -657,27 +653,11 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                }
        }
 
-       skb_dst_drop(skb);
-       skb_dst_set(skb, &rt->dst);
-
-       /* Push down and install the IP header. */
-       skb_push(skb, sizeof(struct iphdr));
-       skb_reset_network_header(skb);
-
-       iph = ip_hdr(skb);
-       inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
+       err = iptunnel_xmit(dev_net(dev), rt, skb,
+                           fl4.saddr, fl4.daddr, protocol,
+                           ip_tunnel_ecn_encap(tos, inner_iph, skb), ttl, df);
+       iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
 
-       iph->version    =       4;
-       iph->ihl        =       sizeof(struct iphdr) >> 2;
-       iph->frag_off   =       df;
-       iph->protocol   =       protocol;
-       iph->tos        =       ip_tunnel_ecn_encap(tos, inner_iph, skb);
-       iph->daddr      =       fl4.daddr;
-       iph->saddr      =       fl4.saddr;
-       iph->ttl        =       ttl;
-       tunnel_ip_select_ident(skb, inner_iph, &rt->dst);
-
-       iptunnel_xmit(skb, dev);
        return;
 
 #if IS_ENABLED(CONFIG_IPV6)