Skip to content

Commit

Permalink
gre: Use GSO flags to determine csum need instead of GRE flags
Browse files Browse the repository at this point in the history
This patch updates the gre checksum path to follow something much closer to
the UDP checksum path.  By doing this we can avoid needing to do as much
header inspection and can just make use of the fields we were already
reading in the sk_buff structure.

Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Alexander Duyck authored and David S. Miller committed Feb 11, 2016
1 parent ddff00d commit 2e598af
Showing 1 changed file with 30 additions and 34 deletions.
64 changes: 30 additions & 34 deletions net/ipv4/gre_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
struct sk_buff *segs = ERR_PTR(-EINVAL);
int ghl;
struct gre_base_hdr *greh;
u16 mac_offset = skb->mac_header;
int mac_len = skb->mac_len;
__be16 protocol = skb->protocol;
int tnl_hlen;
bool csum;
u16 mac_len = skb->mac_len;
int gre_offset, outer_hlen;
bool need_csum;

if (unlikely(skb_shinfo(skb)->gso_type &
~(SKB_GSO_TCPV4 |
Expand All @@ -42,64 +42,60 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
if (!skb->encapsulation)
goto out;

if (unlikely(!pskb_may_pull(skb, sizeof(*greh))))
if (unlikely(tnl_hlen < sizeof(struct gre_base_hdr)))
goto out;

greh = (struct gre_base_hdr *)skb_transport_header(skb);

ghl = skb_inner_mac_header(skb) - skb_transport_header(skb);
if (unlikely(ghl < sizeof(*greh)))
if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
goto out;

csum = !!(greh->flags & GRE_CSUM);
if (csum)
skb->encap_hdr_csum = 1;
greh = (struct gre_base_hdr *)skb_transport_header(skb);

/* setup inner skb. */
skb->protocol = greh->protocol;
skb->encapsulation = 0;

if (unlikely(!pskb_may_pull(skb, ghl)))
goto out;

__skb_pull(skb, ghl);
__skb_pull(skb, tnl_hlen);
skb_reset_mac_header(skb);
skb_set_network_header(skb, skb_inner_network_offset(skb));
skb->mac_len = skb_inner_network_offset(skb);

need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_GRE_CSUM);
skb->encap_hdr_csum = need_csum;

features &= skb->dev->hw_enc_features;

/* segment inner packet. */
segs = skb_mac_gso_segment(skb, features);
if (IS_ERR_OR_NULL(segs)) {
skb_gso_error_unwind(skb, protocol, ghl, mac_offset, mac_len);
skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset,
mac_len);
goto out;
}

outer_hlen = skb_tnl_header_len(skb);
gre_offset = outer_hlen - tnl_hlen;
skb = segs;
tnl_hlen = skb_tnl_header_len(skb);
do {
__skb_push(skb, ghl);
if (csum) {
__be32 *pcsum;

skb_reset_transport_header(skb);

greh = (struct gre_base_hdr *)
skb_transport_header(skb);
pcsum = (__be32 *)(greh + 1);
*pcsum = 0;
*(__sum16 *)pcsum = gso_make_checksum(skb, 0);
}
__skb_push(skb, tnl_hlen - ghl);
__be32 *pcsum;

skb_reset_inner_headers(skb);
skb->encapsulation = 1;

skb_reset_mac_header(skb);
skb_set_network_header(skb, mac_len);
skb->mac_len = mac_len;
skb->protocol = protocol;

__skb_push(skb, outer_hlen);
skb_reset_mac_header(skb);
skb_set_network_header(skb, mac_len);
skb_set_transport_header(skb, gre_offset);

if (!need_csum)
continue;

greh = (struct gre_base_hdr *)skb_transport_header(skb);
pcsum = (__be32 *)(greh + 1);

*pcsum = 0;
*(__sum16 *)pcsum = gso_make_checksum(skb, 0);
} while ((skb = skb->next));
out:
return segs;
Expand Down

0 comments on commit 2e598af

Please sign in to comment.