Commit 2e598af7 authored by Alexander Duyck's avatar Alexander Duyck Committed by David S. Miller

gre: Use GSO flags to determine csum need instead of GRE flags

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: default avatarAlexander Duyck <aduyck@mirantis.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ddff00d4
...@@ -18,14 +18,14 @@ ...@@ -18,14 +18,14 @@
static struct sk_buff *gre_gso_segment(struct sk_buff *skb, static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
netdev_features_t features) netdev_features_t features)
{ {
int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
struct sk_buff *segs = ERR_PTR(-EINVAL); struct sk_buff *segs = ERR_PTR(-EINVAL);
int ghl;
struct gre_base_hdr *greh; struct gre_base_hdr *greh;
u16 mac_offset = skb->mac_header; u16 mac_offset = skb->mac_header;
int mac_len = skb->mac_len;
__be16 protocol = skb->protocol; __be16 protocol = skb->protocol;
int tnl_hlen; u16 mac_len = skb->mac_len;
bool csum; int gre_offset, outer_hlen;
bool need_csum;
if (unlikely(skb_shinfo(skb)->gso_type & if (unlikely(skb_shinfo(skb)->gso_type &
~(SKB_GSO_TCPV4 | ~(SKB_GSO_TCPV4 |
...@@ -42,64 +42,60 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, ...@@ -42,64 +42,60 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
if (!skb->encapsulation) if (!skb->encapsulation)
goto out; goto out;
if (unlikely(!pskb_may_pull(skb, sizeof(*greh)))) if (unlikely(tnl_hlen < sizeof(struct gre_base_hdr)))
goto out; goto out;
greh = (struct gre_base_hdr *)skb_transport_header(skb); if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
ghl = skb_inner_mac_header(skb) - skb_transport_header(skb);
if (unlikely(ghl < sizeof(*greh)))
goto out; goto out;
csum = !!(greh->flags & GRE_CSUM); greh = (struct gre_base_hdr *)skb_transport_header(skb);
if (csum)
skb->encap_hdr_csum = 1;
/* setup inner skb. */ /* setup inner skb. */
skb->protocol = greh->protocol; skb->protocol = greh->protocol;
skb->encapsulation = 0; skb->encapsulation = 0;
__skb_pull(skb, tnl_hlen);
if (unlikely(!pskb_may_pull(skb, ghl)))
goto out;
__skb_pull(skb, ghl);
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
skb_set_network_header(skb, skb_inner_network_offset(skb)); skb_set_network_header(skb, skb_inner_network_offset(skb));
skb->mac_len = 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; features &= skb->dev->hw_enc_features;
/* segment inner packet. */ /* segment inner packet. */
segs = skb_mac_gso_segment(skb, features); segs = skb_mac_gso_segment(skb, features);
if (IS_ERR_OR_NULL(segs)) { 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; goto out;
} }
outer_hlen = skb_tnl_header_len(skb);
gre_offset = outer_hlen - tnl_hlen;
skb = segs; skb = segs;
tnl_hlen = skb_tnl_header_len(skb);
do { do {
__skb_push(skb, ghl);
if (csum) {
__be32 *pcsum; __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);
skb_reset_inner_headers(skb); skb_reset_inner_headers(skb);
skb->encapsulation = 1; skb->encapsulation = 1;
skb_reset_mac_header(skb);
skb_set_network_header(skb, mac_len);
skb->mac_len = mac_len; skb->mac_len = mac_len;
skb->protocol = protocol; 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)); } while ((skb = skb->next));
out: out:
return segs; return segs;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment