forked from Minki/linux
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: Alexander Duyck <aduyck@mirantis.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ddff00d420
commit
2e598af713
@ -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 |
|
||||
@ -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;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
|
||||
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)))
|
||||
goto out;
|
||||
|
||||
csum = !!(greh->flags & GRE_CSUM);
|
||||
if (csum)
|
||||
skb->encap_hdr_csum = 1;
|
||||
|
||||
/* 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;
|
||||
|
Loading…
Reference in New Issue
Block a user