Skip to content

Commit

Permalink
udp: Add support for software checksum and GSO_PARTIAL with GSO offload
Browse files Browse the repository at this point in the history
This patch adds support for a software provided checksum and GSO_PARTIAL
segmentation support. With this we can offload UDP segmentation on devices
that only have partial support for tunnels.

Since we are no longer needing the hardware checksum we can drop the checks
in the segmentation code that were verifying if it was present.

Signed-off-by: Alexander Duyck <[email protected]>
Acked-by: Willem de Bruijn <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Alexander Duyck authored and davem330 committed May 9, 2018
1 parent 0ad6509 commit 6053d0f
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 20 deletions.
29 changes: 19 additions & 10 deletions net/ipv4/udp_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,13 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
return segs;
}

/* GSO partial and frag_list segmentation only requires splitting
* the frame into an MSS multiple and possibly a remainder, both
* cases return a GSO skb. So update the mss now.
*/
if (skb_is_gso(segs))
mss *= skb_shinfo(segs)->gso_segs;

seg = segs;
uh = udp_hdr(seg);

Expand All @@ -232,6 +239,12 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
uh->len = newlen;
uh->check = check;

if (seg->ip_summed == CHECKSUM_PARTIAL)
gso_reset_checksum(seg, ~check);
else
uh->check = gso_make_checksum(seg, ~check) ? :
CSUM_MANGLED_0;

seg = seg->next;
uh = udp_hdr(seg);
}
Expand All @@ -244,22 +257,18 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
uh->len = newlen;
uh->check = check;

if (seg->ip_summed == CHECKSUM_PARTIAL)
gso_reset_checksum(seg, ~check);
else
uh->check = gso_make_checksum(seg, ~check) ? : CSUM_MANGLED_0;

/* update refcount for the packet */
refcount_add(sum_truesize - gso_skb->truesize, &sk->sk_wmem_alloc);

return segs;
}
EXPORT_SYMBOL_GPL(__udp_gso_segment);

static struct sk_buff *__udp4_gso_segment(struct sk_buff *gso_skb,
netdev_features_t features)
{
if (!can_checksum_protocol(features, htons(ETH_P_IP)))
return ERR_PTR(-EIO);

return __udp_gso_segment(gso_skb, features);
}

static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
netdev_features_t features)
{
Expand All @@ -283,7 +292,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
goto out;

if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
return __udp4_gso_segment(skb, features);
return __udp_gso_segment(skb, features);

mss = skb_shinfo(skb)->gso_size;
if (unlikely(skb->len <= mss))
Expand Down
11 changes: 1 addition & 10 deletions net/ipv6/udp_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,6 @@
#include <net/ip6_checksum.h>
#include "ip6_offload.h"

static struct sk_buff *__udp6_gso_segment(struct sk_buff *gso_skb,
netdev_features_t features)
{
if (!can_checksum_protocol(features, htons(ETH_P_IPV6)))
return ERR_PTR(-EIO);

return __udp_gso_segment(gso_skb, features);
}

static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
netdev_features_t features)
{
Expand Down Expand Up @@ -58,7 +49,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
goto out;

if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
return __udp6_gso_segment(skb, features);
return __udp_gso_segment(skb, features);

/* Do software UFO. Complete and fill in the UDP checksum as HW cannot
* do checksum of UDP packets sent as multiple IP fragments.
Expand Down

0 comments on commit 6053d0f

Please sign in to comment.