diff options
author | David S. Miller <davem@davemloft.net> | 2014-04-11 15:15:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-04-11 15:15:22 -0400 |
commit | ad20d5f673898578f9d8a156d7a4c921f5ca4584 (patch) | |
tree | 7a95879de0f7b22181a67c2e7e23e7407d97b529 /drivers/net/hyperv/netvsc_drv.c | |
parent | eb7076182d1ae4bc4641534134ed707100d76acc (diff) | |
parent | af9893a3dc790ae0c4d3e68adde12bc3cb9c63fa (diff) |
Merge branch 'hyperv'
K. Y. Srinivasan says:
====================
Fix issues with Heper-V network offload code
WS2008 R2 does not support udp checksum offload. Furthermore, ws2012 and
ws2012 r2 have issues offloading udp checksum from Linux guests.
This patch-set addresses these issues as well as other bug fixes.
Please apply.
In this version, I have addressed the comment from David Miller with reagards
to COWing the skb prior to modifying the header (patch 3/3).
====================
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.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 4e4cf9e0c8d7..31e55fba7cad 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -319,7 +319,9 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
319 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + | 319 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + |
320 | (num_data_pgs * sizeof(struct hv_page_buffer)) + | 320 | (num_data_pgs * sizeof(struct hv_page_buffer)) + |
321 | sizeof(struct rndis_message) + | 321 | sizeof(struct rndis_message) + |
322 | NDIS_VLAN_PPI_SIZE, GFP_ATOMIC); | 322 | NDIS_VLAN_PPI_SIZE + |
323 | NDIS_CSUM_PPI_SIZE + | ||
324 | NDIS_LSO_PPI_SIZE, GFP_ATOMIC); | ||
323 | if (!packet) { | 325 | if (!packet) { |
324 | /* out of memory, drop packet */ | 326 | /* out of memory, drop packet */ |
325 | netdev_err(net, "unable to allocate hv_netvsc_packet\n"); | 327 | netdev_err(net, "unable to allocate hv_netvsc_packet\n"); |
@@ -396,7 +398,30 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
396 | csum_info->transmit.tcp_checksum = 1; | 398 | csum_info->transmit.tcp_checksum = 1; |
397 | csum_info->transmit.tcp_header_offset = hdr_offset; | 399 | csum_info->transmit.tcp_header_offset = hdr_offset; |
398 | } else if (net_trans_info & INFO_UDP) { | 400 | } else if (net_trans_info & INFO_UDP) { |
399 | 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; | ||
400 | } | 425 | } |
401 | goto do_send; | 426 | goto do_send; |
402 | 427 | ||
@@ -436,6 +461,7 @@ do_send: | |||
436 | 461 | ||
437 | ret = netvsc_send(net_device_ctx->device_ctx, packet); | 462 | ret = netvsc_send(net_device_ctx->device_ctx, packet); |
438 | 463 | ||
464 | drop: | ||
439 | if (ret == 0) { | 465 | if (ret == 0) { |
440 | net->stats.tx_bytes += skb->len; | 466 | net->stats.tx_bytes += skb->len; |
441 | net->stats.tx_packets++; | 467 | net->stats.tx_packets++; |