diff options
Diffstat (limited to 'net/ipv4/gre_offload.c')
-rw-r--r-- | net/ipv4/gre_offload.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 003b0ebbcfdd..47f4c544c916 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c @@ -24,7 +24,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, __be16 protocol = skb->protocol; u16 mac_len = skb->mac_len; int gre_offset, outer_hlen; - bool need_csum; + bool need_csum, ufo; if (unlikely(skb_shinfo(skb)->gso_type & ~(SKB_GSO_TCPV4 | @@ -58,8 +58,20 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_GRE_CSUM); skb->encap_hdr_csum = need_csum; + ufo = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP); + features &= skb->dev->hw_enc_features; + /* The only checksum offload we care about from here on out is the + * outer one so strip the existing checksum feature flags based + * on the fact that we will be computing our checksum in software. + */ + if (ufo) { + features &= ~NETIF_F_CSUM_MASK; + if (!need_csum) + features |= NETIF_F_HW_CSUM; + } + /* segment inner packet. */ segs = skb_mac_gso_segment(skb, features); if (IS_ERR_OR_NULL(segs)) { @@ -75,8 +87,11 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, struct gre_base_hdr *greh; __be32 *pcsum; - skb_reset_inner_headers(skb); - skb->encapsulation = 1; + /* Set up inner headers if we are offloading inner checksum */ + if (skb->ip_summed == CHECKSUM_PARTIAL) { + skb_reset_inner_headers(skb); + skb->encapsulation = 1; + } skb->mac_len = mac_len; skb->protocol = protocol; |