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>
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 6f39baa..31e55fb 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -398,7 +398,30 @@
csum_info->transmit.tcp_checksum = 1;
csum_info->transmit.tcp_header_offset = hdr_offset;
} else if (net_trans_info & INFO_UDP) {
- csum_info->transmit.udp_checksum = 1;
+ /* UDP checksum offload is not supported on ws2008r2.
+ * Furthermore, on ws2012 and ws2012r2, there are some
+ * issues with udp checksum offload from Linux guests.
+ * (these are host issues).
+ * For now compute the checksum here.
+ */
+ struct udphdr *uh;
+ u16 udp_len;
+
+ ret = skb_cow_head(skb, 0);
+ if (ret)
+ goto drop;
+
+ uh = udp_hdr(skb);
+ udp_len = ntohs(uh->len);
+ uh->check = 0;
+ uh->check = csum_tcpudp_magic(ip_hdr(skb)->saddr,
+ ip_hdr(skb)->daddr,
+ udp_len, IPPROTO_UDP,
+ csum_partial(uh, udp_len, 0));
+ if (uh->check == 0)
+ uh->check = CSUM_MANGLED_0;
+
+ csum_info->transmit.udp_checksum = 0;
}
goto do_send;
@@ -438,6 +461,7 @@
ret = netvsc_send(net_device_ctx->device_ctx, packet);
+drop:
if (ret == 0) {
net->stats.tx_bytes += skb->len;
net->stats.tx_packets++;