mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-27 03:07:43 +02:00
112 lines
3.8 KiB
Diff
112 lines
3.8 KiB
Diff
From b822ee7a17efd1bc8c7584da5d0a2c042e9ca5b6 Mon Sep 17 00:00:00 2001
|
|
From: KY Srinivasan <kys@microsoft.com>
|
|
Date: Wed, 9 Apr 2014 15:00:47 -0700
|
|
Subject: [PATCH 14/25] 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>
|
|
---
|
|
drivers/net/hyperv/hyperv_net.h | 1 +
|
|
drivers/net/hyperv/netvsc_drv.c | 26 +++++++++++++++++++++++++-
|
|
drivers/net/hyperv/rndis_filter.c | 12 +++++++++++-
|
|
3 files changed, 37 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
|
|
index 13010b4dae5b..d18f711d0b0c 100644
|
|
--- a/drivers/net/hyperv/hyperv_net.h
|
|
+++ b/drivers/net/hyperv/hyperv_net.h
|
|
@@ -747,6 +747,7 @@ struct ndis_oject_header {
|
|
#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4 0
|
|
#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6 1
|
|
|
|
+#define VERSION_4_OFFLOAD_SIZE 22
|
|
/*
|
|
* New offload OIDs for NDIS 6
|
|
*/
|
|
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
|
|
index c76c85176644..0d898876689e 100644
|
|
--- a/drivers/net/hyperv/netvsc_drv.c
|
|
+++ b/drivers/net/hyperv/netvsc_drv.c
|
|
@@ -399,7 +399,30 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
|
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;
|
|
|
|
@@ -439,6 +462,7 @@ do_send:
|
|
|
|
ret = netvsc_send(net_device_ctx->device_ctx, packet);
|
|
|
|
+drop:
|
|
if (ret == 0) {
|
|
net->stats.tx_bytes += skb_length;
|
|
net->stats.tx_packets++;
|
|
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
|
|
index 4a37e3db9e32..143a98caf618 100644
|
|
--- a/drivers/net/hyperv/rndis_filter.c
|
|
+++ b/drivers/net/hyperv/rndis_filter.c
|
|
@@ -641,6 +641,16 @@ int rndis_filter_set_offload_params(struct hv_device *hdev,
|
|
struct rndis_set_complete *set_complete;
|
|
u32 extlen = sizeof(struct ndis_offload_params);
|
|
int ret, t;
|
|
+ u32 vsp_version = nvdev->nvsp_version;
|
|
+
|
|
+ if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
|
|
+ extlen = VERSION_4_OFFLOAD_SIZE;
|
|
+ /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
|
|
+ * UDP checksum offload.
|
|
+ */
|
|
+ req_offloads->udp_ip_v4_csum = 0;
|
|
+ req_offloads->udp_ip_v6_csum = 0;
|
|
+ }
|
|
|
|
request = get_rndis_request(rdev, RNDIS_MSG_SET,
|
|
RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
|
|
@@ -674,7 +684,7 @@ int rndis_filter_set_offload_params(struct hv_device *hdev,
|
|
} else {
|
|
set_complete = &request->response_msg.msg.set_complete;
|
|
if (set_complete->status != RNDIS_STATUS_SUCCESS) {
|
|
- netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
|
|
+ netdev_err(ndev, "Fail to set offload on host side:0x%x\n",
|
|
set_complete->status);
|
|
ret = -EINVAL;
|
|
}
|
|
--
|
|
2.4.3
|
|
|