2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

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 <pweisong@vmware.com>
Signed-off-by: Alin-Gabriel Serdean <aserdean@ovn.org>
This commit is contained in:
Wilson Peng 2022-11-09 09:35:06 +08:00 committed by Alin-Gabriel Serdean
parent bb9fedb79a
commit 62ac7b8a53

View File

@ -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);