diff options
author | Tom Herbert <therbert@google.com> | 2014-11-04 12:06:56 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-11-05 16:30:03 -0500 |
commit | b17f709a24013fcbb257f6f89b4d81ac9fdf0d18 (patch) | |
tree | 2d279bf83c7bdbe770a90f784b6c3e2b78e7237d /net | |
parent | c1aa8347e73e4092411fbd96cc59531fb7e76d04 (diff) |
gue: TX support for using remote checksum offload option
Add if_tunnel flag TUNNEL_ENCAP_FLAG_REMCSUM to configure
remote checksum offload on an IP tunnel. Add logic in gue_build_header
to insert remote checksum offload option.
Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/fou.c | 35 |
1 files changed, 32 insertions, 3 deletions
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index a3b8c5b36303..fb0db99adf9e 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c | |||
@@ -562,11 +562,19 @@ int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | |||
562 | bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM); | 562 | bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM); |
563 | int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; | 563 | int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; |
564 | struct guehdr *guehdr; | 564 | struct guehdr *guehdr; |
565 | size_t optlen = 0; | 565 | size_t hdrlen, optlen = 0; |
566 | __be16 sport; | 566 | __be16 sport; |
567 | void *data; | 567 | void *data; |
568 | bool need_priv = false; | 568 | bool need_priv = false; |
569 | 569 | ||
570 | if ((e->flags & TUNNEL_ENCAP_FLAG_REMCSUM) && | ||
571 | skb->ip_summed == CHECKSUM_PARTIAL) { | ||
572 | csum = false; | ||
573 | optlen += GUE_PLEN_REMCSUM; | ||
574 | type |= SKB_GSO_TUNNEL_REMCSUM; | ||
575 | need_priv = true; | ||
576 | } | ||
577 | |||
570 | optlen += need_priv ? GUE_LEN_PRIV : 0; | 578 | optlen += need_priv ? GUE_LEN_PRIV : 0; |
571 | 579 | ||
572 | skb = iptunnel_handle_offloads(skb, csum, type); | 580 | skb = iptunnel_handle_offloads(skb, csum, type); |
@@ -578,7 +586,9 @@ int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | |||
578 | sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev), | 586 | sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev), |
579 | skb, 0, 0, false); | 587 | skb, 0, 0, false); |
580 | 588 | ||
581 | skb_push(skb, sizeof(struct guehdr) + optlen); | 589 | hdrlen = sizeof(struct guehdr) + optlen; |
590 | |||
591 | skb_push(skb, hdrlen); | ||
582 | 592 | ||
583 | guehdr = (struct guehdr *)skb->data; | 593 | guehdr = (struct guehdr *)skb->data; |
584 | 594 | ||
@@ -597,7 +607,26 @@ int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | |||
597 | *flags = 0; | 607 | *flags = 0; |
598 | data += GUE_LEN_PRIV; | 608 | data += GUE_LEN_PRIV; |
599 | 609 | ||
600 | /* Add private flags */ | 610 | if (type & SKB_GSO_TUNNEL_REMCSUM) { |
611 | u16 csum_start = skb_checksum_start_offset(skb); | ||
612 | __be16 *pd = data; | ||
613 | |||
614 | if (csum_start < hdrlen) | ||
615 | return -EINVAL; | ||
616 | |||
617 | csum_start -= hdrlen; | ||
618 | pd[0] = htons(csum_start); | ||
619 | pd[1] = htons(csum_start + skb->csum_offset); | ||
620 | |||
621 | if (!skb_is_gso(skb)) { | ||
622 | skb->ip_summed = CHECKSUM_NONE; | ||
623 | skb->encapsulation = 0; | ||
624 | } | ||
625 | |||
626 | *flags |= GUE_PFLAG_REMCSUM; | ||
627 | data += GUE_PLEN_REMCSUM; | ||
628 | } | ||
629 | |||
601 | } | 630 | } |
602 | 631 | ||
603 | fou_build_udp(skb, e, fl4, protocol, sport); | 632 | fou_build_udp(skb, e, fl4, protocol, sport); |