Message ID | 20180504183039.5194.93287.stgit@localhost.localdomain |
---|---|
State | Changes Requested, archived |
Delegated to: | David Miller |
Headers | show |
Series | UDP GSO Segmentation clean-ups | expand |
On Sat, May 5, 2018 at 3:31 AM, Alexander Duyck <alexander.duyck@gmail.com> wrote: > From: Alexander Duyck <alexander.h.duyck@intel.com> > > 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 <alexander.h.duyck@intel.com> > --- > net/ipv4/udp_offload.c | 28 ++++++++++++++++++---------- > net/ipv6/udp_offload.c | 11 +---------- > 2 files changed, 19 insertions(+), 20 deletions(-) > > diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c > index 946d06d2aa0c..fd94bbb369b2 100644 > --- a/net/ipv4/udp_offload.c > +++ b/net/ipv4/udp_offload.c > @@ -217,6 +217,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); > > @@ -237,6 +244,11 @@ 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); Here and below, this needs if (uh->check == 0) uh->check = CSUM_MANGLED_0; similar to __skb_udp_tunnel_segment?
On Sun, May 6, 2018 at 2:50 PM, Willem de Bruijn <willemdebruijn.kernel@gmail.com> wrote: > On Sat, May 5, 2018 at 3:31 AM, Alexander Duyck > <alexander.duyck@gmail.com> wrote: >> From: Alexander Duyck <alexander.h.duyck@intel.com> >> >> 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 <alexander.h.duyck@intel.com> >> --- >> net/ipv4/udp_offload.c | 28 ++++++++++++++++++---------- >> net/ipv6/udp_offload.c | 11 +---------- >> 2 files changed, 19 insertions(+), 20 deletions(-) >> >> diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c >> index 946d06d2aa0c..fd94bbb369b2 100644 >> --- a/net/ipv4/udp_offload.c >> +++ b/net/ipv4/udp_offload.c >> @@ -217,6 +217,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); >> >> @@ -237,6 +244,11 @@ 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); > > Here and below, this needs > > if (uh->check == 0) > uh->check = CSUM_MANGLED_0; > > similar to __skb_udp_tunnel_segment? Good call, though I think I might change this up a bit and do something like: uh->check = gso_make_checksum(seg, ~check) ? : CSUM_MANGLED_0; That way I can avoid the extra read. Thanks. - Alex
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 946d06d2aa0c..fd94bbb369b2 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -217,6 +217,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); @@ -237,6 +244,11 @@ 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); + seg = seg->next; uh = udp_hdr(seg); } @@ -250,6 +262,11 @@ 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); + /* update refcount for the packet */ refcount_add(sum_truesize - gso_skb->truesize, &sk->sk_wmem_alloc); out: @@ -257,15 +274,6 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, } 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) { @@ -289,7 +297,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)) diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 61e34f1d2fa2..03a2ff3fe1e6 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -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) { @@ -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.