From 62ac7b8a53506d910b787d2909fe8bbe9fd99855 Mon Sep 17 00:00:00 2001 From: Wilson Peng Date: Wed, 9 Nov 2022 09:35:06 +0800 Subject: datapath-windows: Check the condition to reset pseudo header checksum on Rx side If ovs node running on Windows is processing NAT action on the RX side, it will reset pseudo header checksum only if the L4 checksum is same as the calculated pseudo header checksum before NAT action. Without the fix, if the L4 header checksum is filled with a pseudo header checksum (sourceip, dstip, protocol, tcppayloadlen+tcpheaderlen) OVS will still do the checksum update(replace some IP and port and recalculate the checksum). It will lead to incorrect L4 header checksum. Reported-at:https://github.com/openvswitch/ovs-issues/issues/265 Signed-off-by: Wilson Peng Signed-off-by: Alin-Gabriel Serdean --- datapath-windows/ovsext/Actions.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'datapath-windows') diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c index 2f44086b4..97029b0f4 100644 --- a/datapath-windows/ovsext/Actions.c +++ b/datapath-windows/ovsext/Actions.c @@ -1514,6 +1514,8 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx, UINT16 *checkField = NULL; BOOLEAN l4Offload = FALSE; NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo; + UINT16 preNatPseudoChecksum = 0; + BOOLEAN preservePseudoChecksum = FALSE; ASSERT(layers->value != 0); @@ -1549,6 +1551,11 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx, * case, we only update the TTL. */ /*Only tx direction the checksum value will be reset to be PseudoChecksum*/ + if (!isTx) { + preNatPseudoChecksum = IPPseudoChecksum(&ipHdr->saddr, &ipHdr->daddr, + tcpHdr ? IPPROTO_TCP : IPPROTO_UDP, + ntohs(ipHdr->tot_len) - ipHdr->ihl * 4); + } if (isSource) { addrField = &ipHdr->saddr; @@ -1565,7 +1572,12 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx, ((BOOLEAN)csumInfo.Receive.UdpChecksumSucceeded || (BOOLEAN)csumInfo.Receive.UdpChecksumFailed); } - if (isTx && l4Offload) { + if (!isTx && l4Offload) { + if (*checkField == preNatPseudoChecksum) { + preservePseudoChecksum = TRUE; + } + } + if (isTx && l4Offload || preservePseudoChecksum) { *checkField = IPPseudoChecksum(&newAddr, &ipHdr->daddr, tcpHdr ? IPPROTO_TCP : IPPROTO_UDP, ntohs(ipHdr->tot_len) - ipHdr->ihl * 4); @@ -1585,8 +1597,13 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx, ((BOOLEAN)csumInfo.Receive.UdpChecksumSucceeded || (BOOLEAN)csumInfo.Receive.UdpChecksumFailed); } + if (!isTx && l4Offload) { + if (*checkField == preNatPseudoChecksum) { + preservePseudoChecksum = TRUE; + } + } - if (isTx && l4Offload) { + if (isTx && l4Offload || preservePseudoChecksum) { *checkField = IPPseudoChecksum(&ipHdr->saddr, &newAddr, tcpHdr ? IPPROTO_TCP : IPPROTO_UDP, ntohs(ipHdr->tot_len) - ipHdr->ihl * 4); @@ -1595,7 +1612,8 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx, if (*addrField != newAddr) { UINT32 oldAddr = *addrField; - if ((checkField && *checkField != 0) && (!l4Offload || !isTx)) { + if ((checkField && *checkField != 0) && + (!l4Offload || (!isTx && !preservePseudoChecksum))) { /* Recompute total checksum. */ *checkField = ChecksumUpdate32(*checkField, oldAddr, newAddr); @@ -1609,7 +1627,8 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx, } if (portField && *portField != newPort) { - if ((checkField) && (!l4Offload || !isTx)) { + if ((checkField) && + (!l4Offload || (!isTx && !preservePseudoChecksum))) { /* Recompute total checksum. */ *checkField = ChecksumUpdate16(*checkField, *portField, newPort); -- cgit v1.2.1