aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@intel.com>2018-05-07 14:08:46 -0400
committerDavid S. Miller <davem@davemloft.net>2018-05-08 22:30:06 -0400
commit6053d0f189064302420930f9ef9022e24a04946a (patch)
treea32784880b5707ba05ab9a1c5d6114ff4012fd85 /net/ipv4
parent0ad6509571e06b302d519f2f05e616ac8c1a10d7 (diff)
udp: Add support for software checksum and GSO_PARTIAL with GSO offload
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> Acked-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/udp_offload.c29
1 files changed, 19 insertions, 10 deletions
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index b15c78ac3f23..d4f2daca0c33 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -214,6 +214,13 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
214 return segs; 214 return segs;
215 } 215 }
216 216
217 /* GSO partial and frag_list segmentation only requires splitting
218 * the frame into an MSS multiple and possibly a remainder, both
219 * cases return a GSO skb. So update the mss now.
220 */
221 if (skb_is_gso(segs))
222 mss *= skb_shinfo(segs)->gso_segs;
223
217 seg = segs; 224 seg = segs;
218 uh = udp_hdr(seg); 225 uh = udp_hdr(seg);
219 226
@@ -232,6 +239,12 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
232 uh->len = newlen; 239 uh->len = newlen;
233 uh->check = check; 240 uh->check = check;
234 241
242 if (seg->ip_summed == CHECKSUM_PARTIAL)
243 gso_reset_checksum(seg, ~check);
244 else
245 uh->check = gso_make_checksum(seg, ~check) ? :
246 CSUM_MANGLED_0;
247
235 seg = seg->next; 248 seg = seg->next;
236 uh = udp_hdr(seg); 249 uh = udp_hdr(seg);
237 } 250 }
@@ -244,6 +257,11 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
244 uh->len = newlen; 257 uh->len = newlen;
245 uh->check = check; 258 uh->check = check;
246 259
260 if (seg->ip_summed == CHECKSUM_PARTIAL)
261 gso_reset_checksum(seg, ~check);
262 else
263 uh->check = gso_make_checksum(seg, ~check) ? : CSUM_MANGLED_0;
264
247 /* update refcount for the packet */ 265 /* update refcount for the packet */
248 refcount_add(sum_truesize - gso_skb->truesize, &sk->sk_wmem_alloc); 266 refcount_add(sum_truesize - gso_skb->truesize, &sk->sk_wmem_alloc);
249 267
@@ -251,15 +269,6 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
251} 269}
252EXPORT_SYMBOL_GPL(__udp_gso_segment); 270EXPORT_SYMBOL_GPL(__udp_gso_segment);
253 271
254static struct sk_buff *__udp4_gso_segment(struct sk_buff *gso_skb,
255 netdev_features_t features)
256{
257 if (!can_checksum_protocol(features, htons(ETH_P_IP)))
258 return ERR_PTR(-EIO);
259
260 return __udp_gso_segment(gso_skb, features);
261}
262
263static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, 272static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
264 netdev_features_t features) 273 netdev_features_t features)
265{ 274{
@@ -283,7 +292,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
283 goto out; 292 goto out;
284 293
285 if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) 294 if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
286 return __udp4_gso_segment(skb, features); 295 return __udp_gso_segment(skb, features);
287 296
288 mss = skb_shinfo(skb)->gso_size; 297 mss = skb_shinfo(skb)->gso_size;
289 if (unlikely(skb->len <= mss)) 298 if (unlikely(skb->len <= mss))