diff options
author | Tom Herbert <therbert@google.com> | 2014-11-04 18:06:56 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-11-05 22:30:03 +0100 |
commit | b17f709a24013fcbb257f6f89b4d81ac9fdf0d18 (patch) | |
tree | 2d279bf83c7bdbe770a90f784b6c3e2b78e7237d /net/ipv4/fou.c | |
parent | gue: Protocol constants for remote checksum offload (diff) | |
download | linux-b17f709a24013fcbb257f6f89b4d81ac9fdf0d18.tar.xz linux-b17f709a24013fcbb257f6f89b4d81ac9fdf0d18.zip |
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/ipv4/fou.c')
-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, bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM); int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; struct guehdr *guehdr; - size_t optlen = 0; + size_t hdrlen, optlen = 0; __be16 sport; void *data; bool need_priv = false; + if ((e->flags & TUNNEL_ENCAP_FLAG_REMCSUM) && + skb->ip_summed == CHECKSUM_PARTIAL) { + csum = false; + optlen += GUE_PLEN_REMCSUM; + type |= SKB_GSO_TUNNEL_REMCSUM; + need_priv = true; + } + optlen += need_priv ? GUE_LEN_PRIV : 0; skb = iptunnel_handle_offloads(skb, csum, type); @@ -578,7 +586,9 @@ int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev), skb, 0, 0, false); - skb_push(skb, sizeof(struct guehdr) + optlen); + hdrlen = sizeof(struct guehdr) + optlen; + + skb_push(skb, hdrlen); guehdr = (struct guehdr *)skb->data; @@ -597,7 +607,26 @@ int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, *flags = 0; data += GUE_LEN_PRIV; - /* Add private flags */ + if (type & SKB_GSO_TUNNEL_REMCSUM) { + u16 csum_start = skb_checksum_start_offset(skb); + __be16 *pd = data; + + if (csum_start < hdrlen) + return -EINVAL; + + csum_start -= hdrlen; + pd[0] = htons(csum_start); + pd[1] = htons(csum_start + skb->csum_offset); + + if (!skb_is_gso(skb)) { + skb->ip_summed = CHECKSUM_NONE; + skb->encapsulation = 0; + } + + *flags |= GUE_PFLAG_REMCSUM; + data += GUE_PLEN_REMCSUM; + } + } fou_build_udp(skb, e, fl4, protocol, sport); |