This patch introduces GRE checksum computation if the userspace requires it on Tx. On Rx we verify the GRE checksum if the checksum bit was specified and also inform the userspace about it.
Also fix the GRE header length as specified by the GRE flags not the tunnel flags. Signed-off-by: Alin Gabriel Serdean <aserd...@cloudbasesolutions.com> --- datapath-windows/ovsext/Gre.c | 68 ++++++++++++++++++++++++++++++------------- datapath-windows/ovsext/Gre.h | 14 ++++----- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/datapath-windows/ovsext/Gre.c b/datapath-windows/ovsext/Gre.c index cb41593..5fa10c3 100644 --- a/datapath-windows/ovsext/Gre.c +++ b/datapath-windows/ovsext/Gre.c @@ -135,7 +135,8 @@ OvsDoEncapGre(POVS_VPORT_ENTRY vport, IPHdr *ipHdr; PGREHdr greHdr; POVS_GRE_VPORT vportGre; - UINT32 headRoom = GreTunHdrSize(tunKey->flags); + PCHAR pChk = NULL; + UINT32 headRoom = GreTunHdrSize(OvsTunnelFlagsToGreFlags(tunKey->flags)); #if DBG UINT32 counterHeadRoom; #endif @@ -259,6 +260,7 @@ OvsDoEncapGre(POVS_VPORT_ENTRY vport, if (tunKey->flags & OVS_TNL_F_CSUM) { RtlZeroMemory(currentOffset, 4); + pChk = currentOffset; currentOffset += 4; #if DBG counterHeadRoom -= 4; @@ -275,6 +277,17 @@ OvsDoEncapGre(POVS_VPORT_ENTRY vport, #endif } + /* Checksum needs to be done after the GRE header has been set */ + if (tunKey->flags & OVS_TNL_F_CSUM) { + ASSERT(pChk); + UINT16 chksum = + CalculateChecksumNB(curNb, + (UINT16)(NET_BUFFER_DATA_LENGTH(curNb) - + sizeof *ipHdr - sizeof *ethHdr), + sizeof *ipHdr + sizeof *ethHdr); + RtlCopyMemory(pChk, &chksum, 2); + } + #if DBG ASSERT(counterHeadRoom == 0); #endif @@ -306,25 +319,12 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext, curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); packetLength = NET_BUFFER_DATA_LENGTH(curNb); - tunnelSize = GreTunHdrSize(tunKey->flags); + curMdl = NET_BUFFER_CURRENT_MDL(curNb); + tunnelSize = GreTunHdrSize(0); if (packetLength <= tunnelSize) { return NDIS_STATUS_INVALID_LENGTH; } - /* - * Create a copy of the NBL so that we have all the headers in one MDL. - */ - *newNbl = OvsPartialCopyNBL(switchContext, curNbl, - tunnelSize + OVS_DEFAULT_COPY_SIZE, 0, - TRUE /*copy NBL info */); - - if (*newNbl == NULL) { - return NDIS_STATUS_RESOURCES; - } - - curNbl = *newNbl; - curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); - curMdl = NET_BUFFER_CURRENT_MDL(curNb); bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority) + NET_BUFFER_CURRENT_MDL_OFFSET(curNb); if (!bufferStart) { @@ -346,16 +346,30 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext, greHdr = (GREHdr *)((PCHAR)ipHdr + sizeof *ipHdr); headRoom += sizeof *greHdr; + tunnelSize = GreTunHdrSize(greHdr->flags); + /* Validate if GRE header protocol type. */ if (greHdr->protocolType != GRE_NET_TEB) { - status = STATUS_NDIS_INVALID_PACKET; - goto dropNbl; + *newNbl = NULL; + return STATUS_NDIS_INVALID_PACKET; } PCHAR currentOffset = (PCHAR)greHdr + sizeof *greHdr; if (greHdr->flags & GRE_CSUM) { tunKey->flags |= OVS_TNL_F_CSUM; + UINT16 prevChksum = *((UINT16 *)currentOffset); + RtlZeroMemory(currentOffset, 2); + UINT16 chksum = + CalculateChecksumNB(curNb, + (UINT16)(NET_BUFFER_DATA_LENGTH(curNb) - + (ipHdr->ihl * 4 + sizeof *ethHdr)), + ipHdr->ihl * 4 + sizeof *ethHdr); + if (prevChksum != chksum) { + *newNbl = NULL; + return STATUS_NDIS_INVALID_PACKET; + } + RtlCopyMemory(currentOffset, &prevChksum, 2); currentOffset += 4; headRoom += 4; } @@ -369,11 +383,25 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext, headRoom += 4; } + /* + * Create a copy of the NBL so that we have all the headers in one MDL. + */ + *newNbl = OvsPartialCopyNBL(switchContext, curNbl, + tunnelSize, 0, + TRUE /*copy NBL info */); + + if (*newNbl == NULL) { + return NDIS_STATUS_RESOURCES; + } + + curNbl = *newNbl; + curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); + /* Clear out the receive flag for the inner packet. */ NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo) = 0; - NdisAdvanceNetBufferDataStart(curNb, GreTunHdrSize(tunKey->flags), FALSE, + NdisAdvanceNetBufferDataStart(curNb, GreTunHdrSize(greHdr->flags), FALSE, NULL); - ASSERT(headRoom == GreTunHdrSize(tunKey->flags)); + ASSERT(headRoom == GreTunHdrSize(greHdr->flags)); return NDIS_STATUS_SUCCESS; dropNbl: diff --git a/datapath-windows/ovsext/Gre.h b/datapath-windows/ovsext/Gre.h index d2472d9..beee86c 100644 --- a/datapath-windows/ovsext/Gre.h +++ b/datapath-windows/ovsext/Gre.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cloudbase Solutions Srl + * Copyright (c) 2015, 2016 Cloudbase Solutions Srl * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -76,11 +76,13 @@ OvsTunnelFlagsToGreFlags(UINT16 tunnelflags) { UINT16 flags = 0; - if (tunnelflags & OVS_TNL_F_CSUM) + if (tunnelflags & OVS_TNL_F_CSUM) { flags |= GRE_CSUM; + } - if (tunnelflags & OVS_TNL_F_KEY) + if (tunnelflags & OVS_TNL_F_KEY) { flags |= GRE_KEY; + } return flags; } @@ -89,10 +91,8 @@ static __inline UINT32 GreTunHdrSize(UINT16 flags) { UINT32 sum = sizeof(EthHdr) + sizeof(IPHdr) + sizeof(GREHdr); - sum += (flags & OVS_TNL_F_CSUM) ? - 4 : 0; - sum += (flags & OVS_TNL_F_KEY) ? - 4 : 0; + sum += (flags & GRE_CSUM) ? 4 : 0; + sum += (flags & GRE_KEY) ? 4 : 0; return sum; } -- 1.9.5.msysgit.0 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev