aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv/netvsc_drv.c
diff options
context:
space:
mode:
authorKY Srinivasan <kys@microsoft.com>2014-04-09 18:00:47 -0400
committerDavid S. Miller <davem@davemloft.net>2014-04-11 15:15:12 -0400
commitaf9893a3dc790ae0c4d3e68adde12bc3cb9c63fa (patch)
tree7a95879de0f7b22181a67c2e7e23e7407d97b529 /drivers/net/hyperv/netvsc_drv.c
parent1f73db495aaa0f1eb4de84856d9ea46711898c08 (diff)
Drivers: net: hyperv: Address UDP checksum issues
ws2008r2 does not support UDP checksum offload. Thus, we cannnot turn on UDP offload in the host. Also, on ws2012 and ws2012 r2, there appear to be an issue with UDP checksum offload. Fix this issue by computing the UDP checksum in the Hyper-V driver. Based on Dave Miller's comments, in this version, I have COWed the skb before modifying the UDP header (the checksum field). Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r--drivers/net/hyperv/netvsc_drv.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 6f39baa67a5f..31e55fba7cad 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -398,7 +398,30 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
398 csum_info->transmit.tcp_checksum = 1; 398 csum_info->transmit.tcp_checksum = 1;
399 csum_info->transmit.tcp_header_offset = hdr_offset; 399 csum_info->transmit.tcp_header_offset = hdr_offset;
400 } else if (net_trans_info & INFO_UDP) { 400 } else if (net_trans_info & INFO_UDP) {
401 csum_info->transmit.udp_checksum = 1; 401 /* UDP checksum offload is not supported on ws2008r2.
402 * Furthermore, on ws2012 and ws2012r2, there are some
403 * issues with udp checksum offload from Linux guests.
404 * (these are host issues).
405 * For now compute the checksum here.
406 */
407 struct udphdr *uh;
408 u16 udp_len;
409
410 ret = skb_cow_head(skb, 0);
411 if (ret)
412 goto drop;
413
414 uh = udp_hdr(skb);
415 udp_len = ntohs(uh->len);
416 uh->check = 0;
417 uh->check = csum_tcpudp_magic(ip_hdr(skb)->saddr,
418 ip_hdr(skb)->daddr,
419 udp_len, IPPROTO_UDP,
420 csum_partial(uh, udp_len, 0));
421 if (uh->check == 0)
422 uh->check = CSUM_MANGLED_0;
423
424 csum_info->transmit.udp_checksum = 0;
402 } 425 }
403 goto do_send; 426 goto do_send;
404 427
@@ -438,6 +461,7 @@ do_send:
438 461
439 ret = netvsc_send(net_device_ctx->device_ctx, packet); 462 ret = netvsc_send(net_device_ctx->device_ctx, packet);
440 463
464drop:
441 if (ret == 0) { 465 if (ret == 0) {
442 net->stats.tx_bytes += skb->len; 466 net->stats.tx_bytes += skb->len;
443 net->stats.tx_packets++; 467 net->stats.tx_packets++;