Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / net / ipv4 / ip_gre.c
index 41ba68d..202437d 100644 (file)
@@ -238,7 +238,7 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
                                return -EINVAL;
                }
        }
-       return iptunnel_pull_header(skb, hdr_len, tpi->proto);
+       return iptunnel_pull_header(skb, hdr_len, tpi->proto, false);
 }
 
 static void ipgre_err(struct sk_buff *skb, u32 info,
@@ -440,6 +440,17 @@ drop:
        return 0;
 }
 
+static __sum16 gre_checksum(struct sk_buff *skb)
+{
+       __wsum csum;
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               csum = lco_csum(skb);
+       else
+               csum = skb_checksum(skb, 0, skb->len, 0);
+       return csum_fold(csum);
+}
+
 static void build_header(struct sk_buff *skb, int hdr_len, __be16 flags,
                         __be16 proto, __be32 key, __be32 seq)
 {
@@ -467,8 +478,7 @@ static void build_header(struct sk_buff *skb, int hdr_len, __be16 flags,
                    !(skb_shinfo(skb)->gso_type &
                      (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) {
                        *ptr = 0;
-                       *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0,
-                                                                skb->len, 0));
+                       *(__sum16 *)ptr = gre_checksum(skb);
                }
        }
 }
@@ -493,8 +503,7 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
 static struct sk_buff *gre_handle_offloads(struct sk_buff *skb,
                                           bool csum)
 {
-       return iptunnel_handle_offloads(skb, csum,
-                                       csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
+       return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
 }
 
 static struct rtable *gre_get_rt(struct sk_buff *skb,
@@ -531,9 +540,16 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
                goto err_free_skb;
 
        key = &tun_info->key;
-       rt = gre_get_rt(skb, dev, &fl, key);
-       if (IS_ERR(rt))
-               goto err_free_skb;
+       rt = !skb->mark ? dst_cache_get_ip4(&tun_info->dst_cache, &fl.saddr) :
+                        NULL;
+       if (!rt) {
+               rt = gre_get_rt(skb, dev, &fl, key);
+               if (IS_ERR(rt))
+                               goto err_free_skb;
+               if (!skb->mark)
+                       dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
+                                         fl.saddr);
+       }
 
        tunnel_hlen = ip_gre_calc_hlen(key->tun_flags);