2019-02-22 18:29:16

by Haiyang Zhang

[permalink] [raw]
Subject: [PATCH hyperv-fixes] hv_netvsc: Fix IP header checksum for coalesced packets

From: Haiyang Zhang <[email protected]>

Incoming packets may have IP header checksum verified by the host.
They may not have IP header checksum computed after coalescing.
This patch re-compute the checksum when necessary, otherwise the
packets may be dropped, because Linux network stack always checks it.

Signed-off-by: Haiyang Zhang <[email protected]>
---
drivers/net/hyperv/netvsc_drv.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 256adbd044f5..cf4897043e83 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -744,6 +744,14 @@ void netvsc_linkstatus_callback(struct net_device *net,
schedule_delayed_work(&ndev_ctx->dwork, 0);
}

+static void netvsc_comp_ipcsum(struct sk_buff *skb)
+{
+ struct iphdr *iph = (struct iphdr *)skb->data;
+
+ iph->check = 0;
+ iph->check = ip_fast_csum(iph, iph->ihl);
+}
+
static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
struct netvsc_channel *nvchan)
{
@@ -770,9 +778,17 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
/* skb is already created with CHECKSUM_NONE */
skb_checksum_none_assert(skb);

- /*
- * In Linux, the IP checksum is always checked.
- * Do L4 checksum offload if enabled and present.
+ /* Incoming packets may have IP header checksum verified by the host.
+ * They may not have IP header checksum computed after coalescing.
+ * We compute it here if the flags are set, because on Linux, the IP
+ * checksum is always checked.
+ */
+ if (csum_info && csum_info->receive.ip_checksum_value_invalid &&
+ csum_info->receive.ip_checksum_succeeded &&
+ skb->protocol == htons(ETH_P_IP))
+ netvsc_comp_ipcsum(skb);
+
+ /* Do L4 checksum offload if enabled and present.
*/
if (csum_info && (net->features & NETIF_F_RXCSUM)) {
if (csum_info->receive.tcp_checksum_succeeded ||
--
2.19.1



2019-02-23 16:51:25

by Stephen Hemminger

[permalink] [raw]
Subject: Re: [PATCH hyperv-fixes] hv_netvsc: Fix IP header checksum for coalesced packets

On Fri, 22 Feb 2019 18:25:03 +0000
Haiyang Zhang <[email protected]> wrote:

> From: Haiyang Zhang <[email protected]>
>
> Incoming packets may have IP header checksum verified by the host.
> They may not have IP header checksum computed after coalescing.
> This patch re-compute the checksum when necessary, otherwise the
> packets may be dropped, because Linux network stack always checks it.
>
> Signed-off-by: Haiyang Zhang <[email protected]>
> ---
> drivers/net/hyperv/netvsc_drv.c | 22 +++++++++++++++++++---
> 1 file changed, 19 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
> index 256adbd044f5..cf4897043e83 100644
> --- a/drivers/net/hyperv/netvsc_drv.c
> +++ b/drivers/net/hyperv/netvsc_drv.c
> @@ -744,6 +744,14 @@ void netvsc_linkstatus_callback(struct net_device *net,
> schedule_delayed_work(&ndev_ctx->dwork, 0);
> }
>
> +static void netvsc_comp_ipcsum(struct sk_buff *skb)
> +{
> + struct iphdr *iph = (struct iphdr *)skb->data;

Can you use iphdr(skb) here?

> +
> + iph->check = 0;
> + iph->check = ip_fast_csum(iph, iph->ihl);
> +}
> +
> static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
> struct netvsc_channel *nvchan)
> {
> @@ -770,9 +778,17 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
> /* skb is already created with CHECKSUM_NONE */
> skb_checksum_none_assert(skb);
>
> - /*
> - * In Linux, the IP checksum is always checked.
> - * Do L4 checksum offload if enabled and present.
> + /* Incoming packets may have IP header checksum verified by the host.
> + * They may not have IP header checksum computed after coalescing.
> + * We compute it here if the flags are set, because on Linux, the IP
> + * checksum is always checked.
> + */
> + if (csum_info && csum_info->receive.ip_checksum_value_invalid &&
> + csum_info->receive.ip_checksum_succeeded &&
> + skb->protocol == htons(ETH_P_IP))
> + netvsc_comp_ipcsum(skb);

Does this still handle for coalesced and non-coalesced packets
which are received with bad IP checksum? My concern is that you are
potentially correcting the checksum for a packet whose received checksum was bad.


> + /* Do L4 checksum offload if enabled and present.
> */
> if (csum_info && (net->features & NETIF_F_RXCSUM)) {
> if (csum_info->receive.tcp_checksum_succeeded ||


2019-02-23 17:30:26

by Haiyang Zhang

[permalink] [raw]
Subject: RE: [PATCH hyperv-fixes] hv_netvsc: Fix IP header checksum for coalesced packets



> -----Original Message-----
> From: Stephen Hemminger <[email protected]>
> Sent: Saturday, February 23, 2019 11:46 AM
> To: Haiyang Zhang <[email protected]>
> Cc: Haiyang Zhang <[email protected]>; [email protected]; linux-
> [email protected]; KY Srinivasan <[email protected]>; Stephen
> Hemminger <[email protected]>; [email protected]; vkuznets
> <[email protected]>; [email protected]; [email protected];
> [email protected]
> Subject: Re: [PATCH hyperv-fixes] hv_netvsc: Fix IP header checksum for
> coalesced packets
>
> On Fri, 22 Feb 2019 18:25:03 +0000
> Haiyang Zhang <[email protected]> wrote:
>
> > From: Haiyang Zhang <[email protected]>
> >
> > Incoming packets may have IP header checksum verified by the host.
> > They may not have IP header checksum computed after coalescing.
> > This patch re-compute the checksum when necessary, otherwise the
> > packets may be dropped, because Linux network stack always checks it.
> >
> > Signed-off-by: Haiyang Zhang <[email protected]>
> > ---
> > drivers/net/hyperv/netvsc_drv.c | 22 +++++++++++++++++++---
> > 1 file changed, 19 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/net/hyperv/netvsc_drv.c
> > b/drivers/net/hyperv/netvsc_drv.c index 256adbd044f5..cf4897043e83
> > 100644
> > --- a/drivers/net/hyperv/netvsc_drv.c
> > +++ b/drivers/net/hyperv/netvsc_drv.c
> > @@ -744,6 +744,14 @@ void netvsc_linkstatus_callback(struct net_device
> *net,
> > schedule_delayed_work(&ndev_ctx->dwork, 0); }
> >
> > +static void netvsc_comp_ipcsum(struct sk_buff *skb) {
> > + struct iphdr *iph = (struct iphdr *)skb->data;
>
> Can you use iphdr(skb) here?
This skb is just allocated by netvsc, the skb->network_header is not set yet.

>
> > +
> > + iph->check = 0;
> > + iph->check = ip_fast_csum(iph, iph->ihl); }
> > +
> > static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
> > struct netvsc_channel *nvchan)
> { @@ -770,9 +778,17 @@
> > static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
> > /* skb is already created with CHECKSUM_NONE */
> > skb_checksum_none_assert(skb);
> >
> > - /*
> > - * In Linux, the IP checksum is always checked.
> > - * Do L4 checksum offload if enabled and present.
> > + /* Incoming packets may have IP header checksum verified by the
> host.
> > + * They may not have IP header checksum computed after coalescing.
> > + * We compute it here if the flags are set, because on Linux, the IP
> > + * checksum is always checked.
> > + */
> > + if (csum_info && csum_info->receive.ip_checksum_value_invalid &&
> > + csum_info->receive.ip_checksum_succeeded &&
> > + skb->protocol == htons(ETH_P_IP))
> > + netvsc_comp_ipcsum(skb);
>
> Does this still handle for coalesced and non-coalesced packets which are
> received with bad IP checksum? My concern is that you are potentially
> correcting the checksum for a packet whose received checksum was bad.

Windows networking team told me that the flags above indicate host side
already verified the checksum. Online doc is here:
https://docs.microsoft.com/en-us/windows-hardware/drivers/network/indicating-coalesced-segments
If the NIC or miniport driver validates the TCP and IPv4 checksums but does not recompute them for the coalesced segment, it must set the TcpChecksumValueInvalid and IpChecksumValueInvalid flags in the NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO structure. Additionally, in this case the NIC or miniport driver may optionally zero out the TCP and IPv4 header checksum values in the segment.

The NIC and miniport driver must always set the IpChecksumSucceeded and TcpChecksumSucceeded flags in the NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO structure before indicating the coalesced segment.

Thanks,
- Haiyang


2019-02-26 22:46:31

by David Miller

[permalink] [raw]
Subject: Re: [PATCH hyperv-fixes] hv_netvsc: Fix IP header checksum for coalesced packets

From: Haiyang Zhang <[email protected]>
Date: Fri, 22 Feb 2019 18:25:03 +0000

> From: Haiyang Zhang <[email protected]>
>
> Incoming packets may have IP header checksum verified by the host.
> They may not have IP header checksum computed after coalescing.
> This patch re-compute the checksum when necessary, otherwise the
> packets may be dropped, because Linux network stack always checks it.
>
> Signed-off-by: Haiyang Zhang <[email protected]>

Applied and queued up for -stable.