The purpose of this patch is to refactor the software offloads found in the VXLAN and GRE code and also to refactor how the maximmum segment size for a given NBL is obtained.
This patch introduces two functions OvsApplySWChecksumOnNB and OVSGetTcpMSS. OVSGetTcpMSS - will return the mss found in a given NBL. OvsApplySWChecksumOnNB - will compute and set software offloads for a given NBL. Signed-off-by: Alin Gabriel Serdean <aserd...@cloudbasesolutions.com> Acked-by: Sorin Vinturis <svinturis at cloudbasesolutions.com> --- v2: Move new functions to Checksum.c/h. Rename Checksum.c/h to Offload.c/h.4 Add Acked-by. --- --- datapath-windows/automake.mk | 4 +- datapath-windows/ovsext/Actions.c | 6 +- datapath-windows/ovsext/BufferMgmt.c | 15 +- datapath-windows/ovsext/BufferMgmt.h | 16 +- datapath-windows/ovsext/Checksum.c | 596 ---------------------------- datapath-windows/ovsext/Checksum.h | 39 -- datapath-windows/ovsext/Gre.c | 85 +--- datapath-windows/ovsext/Offload.c | 703 +++++++++++++++++++++++++++++++++ datapath-windows/ovsext/Offload.h | 47 +++ datapath-windows/ovsext/Stt.c | 24 +- datapath-windows/ovsext/User.c | 20 +- datapath-windows/ovsext/Vxlan.c | 98 +---- datapath-windows/ovsext/ovsext.vcxproj | 4 +- 13 files changed, 816 insertions(+), 841 deletions(-) delete mode 100644 datapath-windows/ovsext/Checksum.c delete mode 100644 datapath-windows/ovsext/Checksum.h create mode 100644 datapath-windows/ovsext/Offload.c create mode 100644 datapath-windows/ovsext/Offload.h diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk index fd22218..f29f548 100644 --- a/datapath-windows/automake.mk +++ b/datapath-windows/automake.mk @@ -12,8 +12,6 @@ EXTRA_DIST += \ datapath-windows/ovsext/Atomic.h \ datapath-windows/ovsext/BufferMgmt.c \ datapath-windows/ovsext/BufferMgmt.h \ - datapath-windows/ovsext/Checksum.c \ - datapath-windows/ovsext/Checksum.h \ datapath-windows/ovsext/Datapath.c \ datapath-windows/ovsext/Datapath.h \ datapath-windows/ovsext/Debug.c \ @@ -39,6 +37,8 @@ EXTRA_DIST += \ datapath-windows/ovsext/Netlink/NetlinkBuf.h \ datapath-windows/ovsext/Netlink/NetlinkError.h \ datapath-windows/ovsext/Netlink/NetlinkProto.h \ + datapath-windows/ovsext/Offload.c \ + datapath-windows/ovsext/Offload.h \ datapath-windows/ovsext/Oid.c \ datapath-windows/ovsext/Oid.h \ datapath-windows/ovsext/PacketIO.c \ diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c index 8e41b74..5a04541 100644 --- a/datapath-windows/ovsext/Actions.c +++ b/datapath-windows/ovsext/Actions.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 VMware, Inc. + * Copyright (c) 2014, 2016 VMware, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,13 @@ #include "precomp.h" -#include "Checksum.h" +#include "Debug.h" #include "Event.h" #include "Flow.h" #include "Gre.h" #include "Mpls.h" #include "NetProto.h" +#include "Offload.h" #include "PacketIO.h" #include "Stt.h" #include "Switch.h" @@ -33,7 +34,6 @@ #undef OVS_DBG_MOD #endif #define OVS_DBG_MOD OVS_DBG_ACTION -#include "Debug.h" typedef struct _OVS_ACTION_STATS { UINT64 rxGre; diff --git a/datapath-windows/ovsext/BufferMgmt.c b/datapath-windows/ovsext/BufferMgmt.c index 7ec073b..3189e9b 100644 --- a/datapath-windows/ovsext/BufferMgmt.c +++ b/datapath-windows/ovsext/BufferMgmt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 VMware, Inc. + * Copyright (c) 2014, 2016 VMware, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -77,18 +77,19 @@ */ #include "precomp.h" +#include "Debug.h" +#include "Flow.h" +#include "Offload.h" +#include "NetProto.h" +#include "PacketParser.h" #include "Switch.h" +#include "Vport.h" #ifdef OVS_DBG_MOD #undef OVS_DBG_MOD #endif #define OVS_DBG_MOD OVS_DBG_BUFMGMT -#include "Debug.h" -#include "NetProto.h" -#include "Flow.h" -#include "Checksum.h" -#include "PacketParser.h" -#include "Vport.h" + /* * -------------------------------------------------------------------------- diff --git a/datapath-windows/ovsext/BufferMgmt.h b/datapath-windows/ovsext/BufferMgmt.h index 79abc3d..11a05b2 100644 --- a/datapath-windows/ovsext/BufferMgmt.h +++ b/datapath-windows/ovsext/BufferMgmt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 VMware, Inc. + * Copyright (c) 2014, 2016 VMware, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,7 +63,6 @@ typedef union _OVS_BUFFER_CONTEXT { UINT64 value[MEM_ALIGN_SIZE(16) >> 3]; } OVS_BUFFER_CONTEXT, *POVS_BUFFER_CONTEXT; - typedef struct _OVS_NBL_POOL { NDIS_SWITCH_CONTEXT ndisContext; NDIS_HANDLE ndisHandle; @@ -83,11 +82,13 @@ typedef struct _OVS_NBL_POOL { NDIS_STATUS OvsInitBufferPool(PVOID context); + VOID OvsCleanupBufferPool(PVOID context); PNET_BUFFER_LIST OvsAllocateFixSizeNBL(PVOID context, UINT32 size, UINT32 headRoom); + PNET_BUFFER_LIST OvsAllocateVariableSizeNBL(PVOID context, UINT32 size, UINT32 headRoom); @@ -106,20 +107,27 @@ PNET_BUFFER_LIST OvsPartialCopyToMultipleNBLs(PVOID context, UINT32 copySize, UINT32 headRoom, BOOLEAN copyNblInfo); + PNET_BUFFER_LIST OvsFullCopyNBL(PVOID context, PNET_BUFFER_LIST nbl, UINT32 headRoom, BOOLEAN copyNblInfo); + PNET_BUFFER_LIST OvsTcpSegmentNBL(PVOID context, PNET_BUFFER_LIST nbl, POVS_PACKET_HDR_INFO hdrInfo, UINT32 MSS, UINT32 headRoom); + PNET_BUFFER_LIST OvsAllocateNBLFromBuffer(PVOID context, PVOID buffer, ULONG length); -PNET_BUFFER_LIST OvsFullCopyToMultipleNBLs(PVOID context, - PNET_BUFFER_LIST nbl, UINT32 headRoom, BOOLEAN copyNblInfo); + +PNET_BUFFER_LIST OvsFullCopyToMultipleNBLs(PVOID context, PNET_BUFFER_LIST nbl, + UINT32 headRoom, + BOOLEAN copyNblInfo); + PNET_BUFFER_LIST OvsCompleteNBL(PVOID context, PNET_BUFFER_LIST nbl, BOOLEAN updateRef); + NDIS_STATUS OvsSetCtxSourcePortNo(PNET_BUFFER_LIST nbl, UINT32 portNo); NDIS_STATUS OvsGetCtxSourcePortNo(PNET_BUFFER_LIST nbl, UINT32 *portNo); diff --git a/datapath-windows/ovsext/Checksum.c b/datapath-windows/ovsext/Checksum.c deleted file mode 100644 index 5d9b035..0000000 --- a/datapath-windows/ovsext/Checksum.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * Copyright (c) 2014 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "precomp.h" -#include "Checksum.h" -#include "Flow.h" - -#ifdef OVS_DBG_MOD -#undef OVS_DBG_MOD -#endif -#define OVS_DBG_MOD OVS_DBG_CHECKSUM -#include "Debug.h" -#include "PacketParser.h" - -#ifndef htons -#define htons(_x) (((UINT16)(_x) >> 8) + (((UINT16)(_x) << 8) & 0xff00)) -#endif - -#ifndef swap64 -#define swap64(_x) ((((UINT64)(_x) >> 8) & 0x00ff00ff00ff00ff) + \ - (((UINT64)(_x) << 8) & 0xff00ff00ff00ff00)) -#endif - -#define fold64(_x) \ - _x = ((_x) >> 32) + ((_x) & 0xffffffff); \ - _x = (UINT32)(((_x) >> 32) + (_x)); \ - _x = ((_x) >> 16) + ((_x) & 0xffff); \ - _x = (UINT16)(((_x) >> 16) + (_x)) - -#define fold32(_x) \ - _x = ((_x) >> 16) + ((_x) & 0xffff); \ - _x = (UINT16)(((_x) >> 16) + (_x)) - - -/* - *---------------------------------------------------------------------------- - * CalculateOnesComplement -- - * - * Given the start address and buffer length, calculate the 1's complement - * This routine can be used when multiple buffers are used for a packets. - * - * PLEASE NOTE, even though the last parameter is UINT64, but the assumption - * is it will not overflowed after adding the extra data. - * ------------------------------------------------ - * - * Result: - * As name indicate, the final data is not 1's complemnent - *---------------------------------------------------------------------------- - */ -UINT64 -CalculateOnesComplement(UINT8 *start, - UINT16 totalLength, - UINT64 initial, - BOOLEAN isEvenStart) -{ - UINT64 sum = 0, val; - UINT64 *src = (UINT64 *)start; - while (totalLength > 7) { - val = *src; - sum += val; - if (sum < val) sum++; - src++; - totalLength -= 8; - } - - start = (UINT8 *)src; - - if (totalLength > 3) { - UINT32 val = *(UINT32 *)start; - sum += val; - if (sum < val) sum++; - start += 4; - totalLength -= 4; - } - - if (totalLength > 1) { - UINT16 val = *(UINT16 *)start; - sum += val; - if (sum < val) sum++; - start += 2; - totalLength -= 2; - } - - if (totalLength > 0) { - UINT8 val = *start; - sum += val; - if (sum < val) sum++; - start += 1; - totalLength -= 1; - } - ASSERT(totalLength == 0); - - if (!isEvenStart) { - sum = _byteswap_uint64(sum); - } - - sum += initial; - if (sum < initial) sum++; - - return sum; -} - -/* - *---------------------------------------------------------------------------- - * CalculateChecksum -- - * - * Given the start point, and length, calculate the checksum - * as 1's complement of 1's comlement. - * - * This assume the checksum field is initailized properly. - * - * Input Parameter: - * ptr: point to the data to be checksumed - * totalLength: total length of the data - * initial: inital value to remit the checksum. Please note this - * value should be network byte order value. - * - * The last parameter may be useful where you don't want to set - * checksum field to zero, in that case you can pass ~checksum, - * this is equivalent of set checksum field to zero. - * - * Result: - * The result can be assigned to checksum field directly. - *---------------------------------------------------------------------------- - */ -UINT16 -CalculateChecksum(UINT8 *ptr, - UINT16 totalLength, - UINT16 initial) -{ - UINT64 sum = CalculateOnesComplement(ptr, totalLength, initial, TRUE); - fold64(sum); - return (UINT16)~sum; -} - -/* - *---------------------------------------------------------------------------- - * CopyAndCalculateOnesComplement -- - * - * Given the start address and buffer length, calculate the 1's complement - * at same time, copt the data from src to dst. - * - * This routine can be used when multiple buffers are used for a packets. - * - * PLEASE NOTE, even though the last parameter is UINT64, but the assumption - * is it will not overflowed after adding the extra data. - * ------------------------------------------------ - * - * Result: - * As name indicate, the final data is not 1's complemnent - *---------------------------------------------------------------------------- - */ -UINT64 -CopyAndCalculateOnesComplement(UINT8 *dst, - UINT8 *src, - UINT16 length, - UINT64 initial, - BOOLEAN isEvenStart) -{ - UINT64 sum =0, val; - UINT64 *src64, *dst64; - union { - UINT32 val; - UINT8 b8[4]; - } tmp; - - src64 = (UINT64 *)src; - dst64 = (UINT64 *)dst; - - while (length > 7) { - val = *src64; - *dst64 = val; - sum += (val >> 32) + (val & 0xffffffff); - src64++; - dst64++; - length -= 8; - } - - if (length > 3) { - val = *(UINT32 *)src64; - *(UINT32 *)dst64 = (UINT32)val; - sum += (UINT32)val; - dst64 = (UINT64 *)((UINT8 *)dst64 + 4); - src64 = (UINT64 *)((UINT8 *)src64 + 4); - length -= 4; - } - src = (UINT8 *)src64; - dst = (UINT8 *)dst64; - tmp.val = 0; - switch (length) { - case 3: - dst[2] = src[2]; - tmp.b8[2] = src[2]; - case 2: - dst[1] = src[1]; - tmp.b8[1] = src[1]; - case 1: - dst[0] = src[0]; - tmp.b8[0] = src[0]; - sum += tmp.val; - } - sum = (isEvenStart ? sum : swap64(sum)) + initial; - return sum; -} - -/* - *---------------------------------------------------------------------------- - * CopyAndCalculateChecksum -- - * - * This is similar to CalculateChecksum, except it will also copy data to - * destination address. - *---------------------------------------------------------------------------- - */ -UINT16 -CopyAndCalculateChecksum(UINT8 *dst, - UINT8 *src, - UINT16 length, - UINT16 initial) -{ - - UINT64 sum = CopyAndCalculateOnesComplement(dst, src, length, initial, - TRUE); - fold64(sum); - return (UINT16)~sum; -} - - -/* - *---------------------------------------------------------------------------- - * IPChecksum -- - * - * Give IP header, calculate the IP checksum. - * We assume IP checksum field is initialized properly - * - * Input Pramater: - * ipHdr: IP header start point - * length: IP header length (potentially include IP options) - * initial: same as CalculateChecksum - * - * Result: - * The result is already 1's complement, so can be assigned - * to checksum field directly - *---------------------------------------------------------------------------- - */ -UINT16 -IPChecksum(UINT8 *ipHdr, - UINT16 length, - UINT16 initial) -{ - UINT32 sum = initial; - UINT16 *ptr = (UINT16 *)ipHdr; - ASSERT((length & 0x3) == 0); - while (length > 1) { - sum += ptr[0]; - ptr++; - length -= 2; - } - fold32(sum); - return (UINT16)~sum; -} - -/* - *---------------------------------------------------------------------------- - * IPPseudoChecksum -- - * - * Give src and dst IP address, protocol value and total - * upper layer length(not include IP header, but include - * upller layer protocol header, for example it include - * TCP header for TCP checksum), calculate the pseudo - * checksum, please note this checksum is just 1's complement - * addition. - * - * Input Parameter: - * src: please note it is in network byte order - * dst: same as src - * protocol: protocol value in IP header - * totalLength: total length of upper layer data including - * header. - * - * Result: - * - * This value should be put in TCP checksum field before - * calculating TCP checksum using CalculateChecksum with - * initial value of 0. - *---------------------------------------------------------------------------- - */ -UINT16 -IPPseudoChecksum(UINT32 *src, - UINT32 *dst, - UINT8 protocol, - UINT16 totalLength) -{ - UINT32 sum = (UINT32)htons(totalLength) + htons(protocol); - sum += (*src >> 16) + (*src & 0xffff); - sum += (*dst >> 16) + (*dst & 0xffff); - fold32(sum); - return (UINT16)sum; -} - -/* - *---------------------------------------------------------------------------- - * IPv6PseudoChecksum -- - * - * Given IPv6 src and dst address, upper layer protocol and total - * upper layer protocol data length including upper layer header - * part, calculate the pseudo checksum for upper layer protocol - * checksum. - * - * please note this checksum is just 1's complement addition. - * - * Input Parameter: - * src: src IPv6 address in network byte order - * dst: dst IPv6 address. - * protocol: upper layer protocol - * totalLength: total length of upper layer data. Please note this is - * in host byte order. - * - * Result: - * - * Place in upper layer checksum field before calculate upper layer - * checksum. - *---------------------------------------------------------------------------- - */ -UINT16 -IPv6PseudoChecksum(UINT32 *src, - UINT32 *dst, - UINT8 protocol, - UINT16 totalLength) -{ - UINT64 sum = (UINT32)htons(totalLength) + htons(protocol); - sum += (UINT64)src[0] + src[1] + src[2] + src[3]; - sum += (UINT64)dst[0] + dst[1] + dst[2] + dst[3]; - fold64(sum); - return (UINT16)sum; -} - -/* - *---------------------------------------------------------------------------- - * ChecksumUpdate32 -- - * - * Given old checksum value (as it is in checksum field), - * prev value of the relevant field in network byte order - * new value of the relevant field in the network byte order - * calculate the new checksum. - * Please check relevant RFC for reference. - * - * Input Pramater: - * oldSum: old checksum value in checksum field - * prev: previous value of relevant 32 bit feld in network - * byte order. - * new: new value of the relevant 32 bit field in network - * byte order. - * - * Result: - * new checksum value to be placed in the checksum field. - *---------------------------------------------------------------------------- - */ -UINT16 -ChecksumUpdate32(UINT16 oldSum, - UINT32 prev, - UINT32 newValue) -{ - UINT32 sum = ~prev; - sum = (sum >> 16) + (sum & 0xffff); - sum += (newValue >> 16) + (newValue & 0xffff); - sum += (UINT16)~oldSum; - fold32(sum); - return (UINT16)~sum; -} - - -/* - *---------------------------------------------------------------------------- - * ChecksumUpdate16 -- - * - * Given old checksum value (as it is in checksum field), - * prev value of the relevant field in network byte order - * new value of the relevant field in the network byte order - * calculate the new checksum. - * Please check relevant RFC for reference. - * - * Input Pramater: - * oldSum: old checksum value in checksum field - * prev: previous value of relevant 32 bit feld in network - * byte order. - * new: new value of the relevant 32 bit field in network - * byte order. - * - * Result: - * new checksum value to be placed in the checksum field. - *---------------------------------------------------------------------------- - */ -UINT16 -ChecksumUpdate16(UINT16 oldSum, - UINT16 prev, - UINT16 newValue) -{ - UINT32 sum = (UINT16)~oldSum; - sum += (UINT32)((UINT16)~prev) + newValue; - fold32(sum); - return (UINT16)~sum; -} - -/* - *---------------------------------------------------------------------------- - * CalculateChecksumNB -- - * - * Calculates checksum over a length of bytes contained in an NB. - * - * nb : NB which contains the packet bytes. - * csumDataLen : Length of bytes to be checksummed. - * offset : offset to the first bytes of the data stream to be - * checksumed. - * - * Result: - * return 0, if there is a failure. - *---------------------------------------------------------------------------- - */ -UINT16 -CalculateChecksumNB(const PNET_BUFFER nb, - UINT16 csumDataLen, - UINT32 offset) -{ - ULONG mdlLen; - UINT16 csLen; - PUCHAR src; - UINT64 csum = 0; - PMDL currentMdl; - ULONG firstMdlLen; - /* Running count of bytes in remainder of the MDLs including current. */ - ULONG packetLen; - BOOLEAN swapEnd = 1 & csumDataLen; - - if ((nb == NULL) || (csumDataLen == 0) - || (offset >= NET_BUFFER_DATA_LENGTH(nb)) - || (offset + csumDataLen > NET_BUFFER_DATA_LENGTH(nb))) { - OVS_LOG_ERROR("Invalid parameters - csum length %u, offset %u," - "pkt%s len %u", csumDataLen, offset, nb? "":"(null)", - nb? NET_BUFFER_DATA_LENGTH(nb) : 0); - return 0; - } - - currentMdl = NET_BUFFER_CURRENT_MDL(nb); - packetLen = NET_BUFFER_DATA_LENGTH(nb); - firstMdlLen = - MmGetMdlByteCount(currentMdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb); - - firstMdlLen = MIN(firstMdlLen, packetLen); - if (offset < firstMdlLen) { - src = (PUCHAR) MmGetSystemAddressForMdlSafe(currentMdl, LowPagePriority); - if (!src) { - return 0; - } - src += (NET_BUFFER_CURRENT_MDL_OFFSET(nb) + offset); - mdlLen = firstMdlLen - offset; - packetLen -= firstMdlLen; - ASSERT((INT)packetLen >= 0); - } else { - offset -= firstMdlLen; - packetLen -= firstMdlLen; - ASSERT((INT)packetLen >= 0); - currentMdl = NDIS_MDL_LINKAGE(currentMdl); - mdlLen = MmGetMdlByteCount(currentMdl); - mdlLen = MIN(mdlLen, packetLen); - - while (offset >= mdlLen) { - offset -= mdlLen; - packetLen -= mdlLen; - ASSERT((INT)packetLen >= 0); - currentMdl = NDIS_MDL_LINKAGE(currentMdl); - mdlLen = MmGetMdlByteCount(currentMdl); - mdlLen = MIN(mdlLen, packetLen); - } - - src = (PUCHAR)MmGetSystemAddressForMdlSafe(currentMdl, LowPagePriority); - if (!src) { - return 0; - } - - src += offset; - mdlLen -= offset; - } - - while (csumDataLen && (currentMdl != NULL)) { - ASSERT(mdlLen < 65536); - csLen = MIN((UINT16) mdlLen, csumDataLen); - - csum = CalculateOnesComplement(src, csLen, csum, !(1 & csumDataLen)); - fold64(csum); - - csumDataLen -= csLen; - currentMdl = NDIS_MDL_LINKAGE(currentMdl); - if (csumDataLen && currentMdl) { - src = MmGetSystemAddressForMdlSafe(currentMdl, LowPagePriority); - if (!src) { - return 0; - } - - mdlLen = MmGetMdlByteCount(currentMdl); - mdlLen = MIN(mdlLen, packetLen); - /* packetLen does not include the current MDL from here on. */ - packetLen -= mdlLen; - ASSERT((INT)packetLen >= 0); - } - } - - fold64(csum); - ASSERT(csumDataLen == 0); - ASSERT((csum & ~0xffff) == 0); - csum = (UINT16)~csum; - if (swapEnd) { - return _byteswap_ushort((UINT16)csum); - } - return (UINT16)csum; -} - -/* - * -------------------------------------------------------------------------- - * OvsValidateIPChecksum - * -------------------------------------------------------------------------- - */ -NDIS_STATUS -OvsValidateIPChecksum(PNET_BUFFER_LIST curNbl, - POVS_PACKET_HDR_INFO hdrInfo) -{ - NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo; - uint16_t checksum, hdrChecksum; - struct IPHdr ip_storage; - const IPHdr *ipHdr; - - if (!hdrInfo->isIPv4) { - return NDIS_STATUS_SUCCESS; - } - - /* First check if NIC has indicated checksum failure. */ - csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl, - TcpIpChecksumNetBufferListInfo); - if (csumInfo.Receive.IpChecksumFailed) { - return NDIS_STATUS_FAILURE; - } - - /* Next, check if the NIC did not validate the RX checksum. */ - if (!csumInfo.Receive.IpChecksumSucceeded) { - ipHdr = OvsGetIp(curNbl, hdrInfo->l3Offset, &ip_storage); - if (ipHdr) { - ip_storage = *ipHdr; - hdrChecksum = ipHdr->check; - ip_storage.check = 0; - checksum = IPChecksum((uint8 *)&ip_storage, ipHdr->ihl * 4, 0); - if (checksum != hdrChecksum) { - return NDIS_STATUS_FAILURE; - } - } - } - return NDIS_STATUS_SUCCESS; -} - -/* - *---------------------------------------------------------------------------- - * OvsValidateUDPChecksum - *---------------------------------------------------------------------------- - */ -NDIS_STATUS -OvsValidateUDPChecksum(PNET_BUFFER_LIST curNbl, BOOLEAN udpCsumZero) -{ - NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo; - - csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo); - - if (udpCsumZero) { - /* Zero is valid checksum. */ - csumInfo.Receive.UdpChecksumFailed = 0; - NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo) = csumInfo.Value; - return NDIS_STATUS_SUCCESS; - } - - /* First check if NIC has indicated UDP checksum failure. */ - if (csumInfo.Receive.UdpChecksumFailed) { - return NDIS_STATUS_INVALID_PACKET; - } - - return NDIS_STATUS_SUCCESS; -} diff --git a/datapath-windows/ovsext/Checksum.h b/datapath-windows/ovsext/Checksum.h deleted file mode 100644 index 2378a32..0000000 --- a/datapath-windows/ovsext/Checksum.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2014 VMware, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __CHECKSUM_H_ -#define __CHECKSUM_H_ 1 - -typedef union _OVS_PACKET_HDR_INFO *POVS_PACKET_HDR_INFO; - -UINT16 CalculateChecksum(UINT8 *ptr, UINT16 length, UINT16 initial); -UINT16 CopyAndCalculateChecksum(UINT8 *dst, UINT8 *src, UINT16 length, - UINT16 initial); -UINT16 IPChecksum(UINT8 *ipHdr, UINT16 length, UINT16 initial); -UINT16 IPPseudoChecksum(UINT32 *src, UINT32 *dst, UINT8 protocol, - UINT16 totalLength); -UINT16 IPv6PseudoChecksum(UINT32 *src, UINT32 *dst, UINT8 protocol, - UINT16 totalLength); -UINT16 ChecksumUpdate32(UINT16 oldSum, UINT32 prev, UINT32 newValue); -UINT16 ChecksumUpdate16(UINT16 oldSum, UINT16 prev, UINT16 newValue); -UINT16 CalculateChecksumNB(const PNET_BUFFER nb, UINT16 csumDataLen, - UINT32 offset); -NDIS_STATUS OvsValidateIPChecksum(PNET_BUFFER_LIST curNbl, - POVS_PACKET_HDR_INFO hdrInfo); -NDIS_STATUS OvsValidateUDPChecksum(PNET_BUFFER_LIST curNbl, - BOOLEAN udpCsumZero); - -#endif /* __CHECKSUM_H_ */ diff --git a/datapath-windows/ovsext/Gre.c b/datapath-windows/ovsext/Gre.c index 5abd4a4..cb41593 100644 --- a/datapath-windows/ovsext/Gre.c +++ b/datapath-windows/ovsext/Gre.c @@ -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. @@ -17,11 +17,12 @@ #include "precomp.h" #include "Atomic.h" -#include "Checksum.h" +#include "Debug.h" #include "Flow.h" #include "Gre.h" #include "IpHelper.h" #include "NetProto.h" +#include "Offload.h" #include "PacketIO.h" #include "PacketParser.h" #include "Switch.h" @@ -33,7 +34,6 @@ #undef OVS_DBG_MOD #endif #define OVS_DBG_MOD OVS_DBG_GRE -#include "Debug.h" static NDIS_STATUS OvsDoEncapGre(POVS_VPORT_ENTRY vport, PNET_BUFFER_LIST curNbl, @@ -147,21 +147,8 @@ OvsDoEncapGre(POVS_VPORT_ENTRY vport, packetLength = NET_BUFFER_DATA_LENGTH(curNb); if (layers->isTcp) { - NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO tsoInfo; - - tsoInfo.Value = NET_BUFFER_LIST_INFO(curNbl, - TcpLargeSendNetBufferListInfo); - switch (tsoInfo.Transmit.Type) { - case NDIS_TCP_LARGE_SEND_OFFLOAD_V1_TYPE: - mss = tsoInfo.LsoV1Transmit.MSS; - break; - case NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE: - mss = tsoInfo.LsoV2Transmit.MSS; - break; - default: - OVS_LOG_ERROR("Unknown LSO transmit type:%d", - tsoInfo.Transmit.Type); - } + mss = OVSGetTcpMSS(curNbl); + OVS_LOG_TRACE("MSS %u packet len %u", mss, packetLength); if (mss) { @@ -188,71 +175,15 @@ OvsDoEncapGre(POVS_VPORT_ENTRY vport, OVS_LOG_ERROR("Unable to copy NBL"); return NDIS_STATUS_FAILURE; } - /* - * To this point we do not have GRE hardware offloading. - * Apply defined checksums - */ - curNb = NET_BUFFER_LIST_FIRST_NB(*newNbl); - curMdl = NET_BUFFER_CURRENT_MDL(curNb); - bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, - LowPagePriority); - if (!bufferStart) { - status = NDIS_STATUS_RESOURCES; - goto ret_error; - } NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo; csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo); - bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb); - - if (layers->isIPv4) { - IPHdr *ip = (IPHdr *)(bufferStart + layers->l3Offset); - - if (csumInfo.Transmit.IpHeaderChecksum) { - ip->check = 0; - ip->check = IPChecksum((UINT8 *)ip, 4 * ip->ihl, 0); - } - - if (layers->isTcp && csumInfo.Transmit.TcpChecksum) { - UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); - TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset); - tcp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr, - IPPROTO_TCP, csumLength); - tcp->check = CalculateChecksumNB(curNb, csumLength, - (UINT32)(layers->l4Offset)); - } else if (layers->isUdp && csumInfo.Transmit.UdpChecksum) { - UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); - UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip); - udp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr, - IPPROTO_UDP, csumLength); - udp->check = CalculateChecksumNB(curNb, csumLength, - (UINT32)(layers->l4Offset)); - } - } else if (layers->isIPv6) { - IPv6Hdr *ip = (IPv6Hdr *)(bufferStart + layers->l3Offset); - - if (layers->isTcp && csumInfo.Transmit.TcpChecksum) { - UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); - TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset); - tcp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr, - (UINT32 *) &ip->daddr, - IPPROTO_TCP, csumLength); - tcp->check = CalculateChecksumNB(curNb, csumLength, - (UINT32)(layers->l4Offset)); - } else if (layers->isUdp && csumInfo.Transmit.UdpChecksum) { - UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); - UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip); - udp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr, - (UINT32 *) &ip->daddr, - IPPROTO_UDP, csumLength); - udp->check = CalculateChecksumNB(curNb, csumLength, - (UINT32)(layers->l4Offset)); - } + status = OvsApplySWChecksumOnNB(layers, *newNbl, &csumInfo); + if (status != NDIS_STATUS_SUCCESS) { + goto ret_error; } - /* Clear out TcpIpChecksumNetBufferListInfo flag */ - NET_BUFFER_LIST_INFO(*newNbl, TcpIpChecksumNetBufferListInfo) = 0; } curNbl = *newNbl; diff --git a/datapath-windows/ovsext/Offload.c b/datapath-windows/ovsext/Offload.c new file mode 100644 index 0000000..1e43a9e --- /dev/null +++ b/datapath-windows/ovsext/Offload.c @@ -0,0 +1,703 @@ +/* + * Copyright (c) 2014, 2016 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "precomp.h" +#include "Debug.h" +#include "Flow.h" +#include "Offload.h" +#include "PacketParser.h" + +#ifdef OVS_DBG_MOD +#undef OVS_DBG_MOD +#endif +#define OVS_DBG_MOD OVS_DBG_CHECKSUM + +#ifndef htons +#define htons(_x) (((UINT16)(_x) >> 8) + (((UINT16)(_x) << 8) & 0xff00)) +#endif + +#ifndef swap64 +#define swap64(_x) ((((UINT64)(_x) >> 8) & 0x00ff00ff00ff00ff) + \ + (((UINT64)(_x) << 8) & 0xff00ff00ff00ff00)) +#endif + +#define fold64(_x) \ + _x = ((_x) >> 32) + ((_x) & 0xffffffff); \ + _x = (UINT32)(((_x) >> 32) + (_x)); \ + _x = ((_x) >> 16) + ((_x) & 0xffff); \ + _x = (UINT16)(((_x) >> 16) + (_x)) + +#define fold32(_x) \ + _x = ((_x) >> 16) + ((_x) & 0xffff); \ + _x = (UINT16)(((_x) >> 16) + (_x)) + + +/* + *---------------------------------------------------------------------------- + * CalculateOnesComplement -- + * + * Given the start address and buffer length, calculate the 1's complement + * This routine can be used when multiple buffers are used for a packets. + * + * PLEASE NOTE, even though the last parameter is UINT64, but the assumption + * is it will not overflowed after adding the extra data. + * ------------------------------------------------ + * + * Result: + * As name indicate, the final data is not 1's complemnent + *---------------------------------------------------------------------------- + */ +UINT64 +CalculateOnesComplement(UINT8 *start, + UINT16 totalLength, + UINT64 initial, + BOOLEAN isEvenStart) +{ + UINT64 sum = 0, val; + UINT64 *src = (UINT64 *)start; + while (totalLength > 7) { + val = *src; + sum += val; + if (sum < val) sum++; + src++; + totalLength -= 8; + } + + start = (UINT8 *)src; + + if (totalLength > 3) { + UINT32 val = *(UINT32 *)start; + sum += val; + if (sum < val) sum++; + start += 4; + totalLength -= 4; + } + + if (totalLength > 1) { + UINT16 val = *(UINT16 *)start; + sum += val; + if (sum < val) sum++; + start += 2; + totalLength -= 2; + } + + if (totalLength > 0) { + UINT8 val = *start; + sum += val; + if (sum < val) sum++; + start += 1; + totalLength -= 1; + } + ASSERT(totalLength == 0); + + if (!isEvenStart) { + sum = _byteswap_uint64(sum); + } + + sum += initial; + if (sum < initial) sum++; + + return sum; +} + +/* + *---------------------------------------------------------------------------- + * CalculateChecksum -- + * + * Given the start point, and length, calculate the checksum + * as 1's complement of 1's comlement. + * + * This assume the checksum field is initailized properly. + * + * Input Parameter: + * ptr: point to the data to be checksumed + * totalLength: total length of the data + * initial: inital value to remit the checksum. Please note this + * value should be network byte order value. + * + * The last parameter may be useful where you don't want to set + * checksum field to zero, in that case you can pass ~checksum, + * this is equivalent of set checksum field to zero. + * + * Result: + * The result can be assigned to checksum field directly. + *---------------------------------------------------------------------------- + */ +UINT16 +CalculateChecksum(UINT8 *ptr, + UINT16 totalLength, + UINT16 initial) +{ + UINT64 sum = CalculateOnesComplement(ptr, totalLength, initial, TRUE); + fold64(sum); + return (UINT16)~sum; +} + +/* + *---------------------------------------------------------------------------- + * CopyAndCalculateOnesComplement -- + * + * Given the start address and buffer length, calculate the 1's complement + * at same time, copt the data from src to dst. + * + * This routine can be used when multiple buffers are used for a packets. + * + * PLEASE NOTE, even though the last parameter is UINT64, but the assumption + * is it will not overflowed after adding the extra data. + * ------------------------------------------------ + * + * Result: + * As name indicate, the final data is not 1's complemnent + *---------------------------------------------------------------------------- + */ +UINT64 +CopyAndCalculateOnesComplement(UINT8 *dst, + UINT8 *src, + UINT16 length, + UINT64 initial, + BOOLEAN isEvenStart) +{ + UINT64 sum =0, val; + UINT64 *src64, *dst64; + union { + UINT32 val; + UINT8 b8[4]; + } tmp; + + src64 = (UINT64 *)src; + dst64 = (UINT64 *)dst; + + while (length > 7) { + val = *src64; + *dst64 = val; + sum += (val >> 32) + (val & 0xffffffff); + src64++; + dst64++; + length -= 8; + } + + if (length > 3) { + val = *(UINT32 *)src64; + *(UINT32 *)dst64 = (UINT32)val; + sum += (UINT32)val; + dst64 = (UINT64 *)((UINT8 *)dst64 + 4); + src64 = (UINT64 *)((UINT8 *)src64 + 4); + length -= 4; + } + src = (UINT8 *)src64; + dst = (UINT8 *)dst64; + tmp.val = 0; + switch (length) { + case 3: + dst[2] = src[2]; + tmp.b8[2] = src[2]; + case 2: + dst[1] = src[1]; + tmp.b8[1] = src[1]; + case 1: + dst[0] = src[0]; + tmp.b8[0] = src[0]; + sum += tmp.val; + } + sum = (isEvenStart ? sum : swap64(sum)) + initial; + return sum; +} + +/* + *---------------------------------------------------------------------------- + * CopyAndCalculateChecksum -- + * + * This is similar to CalculateChecksum, except it will also copy data to + * destination address. + *---------------------------------------------------------------------------- + */ +UINT16 +CopyAndCalculateChecksum(UINT8 *dst, + UINT8 *src, + UINT16 length, + UINT16 initial) +{ + + UINT64 sum = CopyAndCalculateOnesComplement(dst, src, length, initial, + TRUE); + fold64(sum); + return (UINT16)~sum; +} + + +/* + *---------------------------------------------------------------------------- + * IPChecksum -- + * + * Give IP header, calculate the IP checksum. + * We assume IP checksum field is initialized properly + * + * Input Pramater: + * ipHdr: IP header start point + * length: IP header length (potentially include IP options) + * initial: same as CalculateChecksum + * + * Result: + * The result is already 1's complement, so can be assigned + * to checksum field directly + *---------------------------------------------------------------------------- + */ +UINT16 +IPChecksum(UINT8 *ipHdr, + UINT16 length, + UINT16 initial) +{ + UINT32 sum = initial; + UINT16 *ptr = (UINT16 *)ipHdr; + ASSERT((length & 0x3) == 0); + while (length > 1) { + sum += ptr[0]; + ptr++; + length -= 2; + } + fold32(sum); + return (UINT16)~sum; +} + +/* + *---------------------------------------------------------------------------- + * IPPseudoChecksum -- + * + * Give src and dst IP address, protocol value and total + * upper layer length(not include IP header, but include + * upller layer protocol header, for example it include + * TCP header for TCP checksum), calculate the pseudo + * checksum, please note this checksum is just 1's complement + * addition. + * + * Input Parameter: + * src: please note it is in network byte order + * dst: same as src + * protocol: protocol value in IP header + * totalLength: total length of upper layer data including + * header. + * + * Result: + * + * This value should be put in TCP checksum field before + * calculating TCP checksum using CalculateChecksum with + * initial value of 0. + *---------------------------------------------------------------------------- + */ +UINT16 +IPPseudoChecksum(UINT32 *src, + UINT32 *dst, + UINT8 protocol, + UINT16 totalLength) +{ + UINT32 sum = (UINT32)htons(totalLength) + htons(protocol); + sum += (*src >> 16) + (*src & 0xffff); + sum += (*dst >> 16) + (*dst & 0xffff); + fold32(sum); + return (UINT16)sum; +} + +/* + *---------------------------------------------------------------------------- + * IPv6PseudoChecksum -- + * + * Given IPv6 src and dst address, upper layer protocol and total + * upper layer protocol data length including upper layer header + * part, calculate the pseudo checksum for upper layer protocol + * checksum. + * + * please note this checksum is just 1's complement addition. + * + * Input Parameter: + * src: src IPv6 address in network byte order + * dst: dst IPv6 address. + * protocol: upper layer protocol + * totalLength: total length of upper layer data. Please note this is + * in host byte order. + * + * Result: + * + * Place in upper layer checksum field before calculate upper layer + * checksum. + *---------------------------------------------------------------------------- + */ +UINT16 +IPv6PseudoChecksum(UINT32 *src, + UINT32 *dst, + UINT8 protocol, + UINT16 totalLength) +{ + UINT64 sum = (UINT32)htons(totalLength) + htons(protocol); + sum += (UINT64)src[0] + src[1] + src[2] + src[3]; + sum += (UINT64)dst[0] + dst[1] + dst[2] + dst[3]; + fold64(sum); + return (UINT16)sum; +} + +/* + *---------------------------------------------------------------------------- + * ChecksumUpdate32 -- + * + * Given old checksum value (as it is in checksum field), + * prev value of the relevant field in network byte order + * new value of the relevant field in the network byte order + * calculate the new checksum. + * Please check relevant RFC for reference. + * + * Input Pramater: + * oldSum: old checksum value in checksum field + * prev: previous value of relevant 32 bit feld in network + * byte order. + * new: new value of the relevant 32 bit field in network + * byte order. + * + * Result: + * new checksum value to be placed in the checksum field. + *---------------------------------------------------------------------------- + */ +UINT16 +ChecksumUpdate32(UINT16 oldSum, + UINT32 prev, + UINT32 newValue) +{ + UINT32 sum = ~prev; + sum = (sum >> 16) + (sum & 0xffff); + sum += (newValue >> 16) + (newValue & 0xffff); + sum += (UINT16)~oldSum; + fold32(sum); + return (UINT16)~sum; +} + + +/* + *---------------------------------------------------------------------------- + * ChecksumUpdate16 -- + * + * Given old checksum value (as it is in checksum field), + * prev value of the relevant field in network byte order + * new value of the relevant field in the network byte order + * calculate the new checksum. + * Please check relevant RFC for reference. + * + * Input Pramater: + * oldSum: old checksum value in checksum field + * prev: previous value of relevant 32 bit feld in network + * byte order. + * new: new value of the relevant 32 bit field in network + * byte order. + * + * Result: + * new checksum value to be placed in the checksum field. + *---------------------------------------------------------------------------- + */ +UINT16 +ChecksumUpdate16(UINT16 oldSum, + UINT16 prev, + UINT16 newValue) +{ + UINT32 sum = (UINT16)~oldSum; + sum += (UINT32)((UINT16)~prev) + newValue; + fold32(sum); + return (UINT16)~sum; +} + +/* + *---------------------------------------------------------------------------- + * CalculateChecksumNB -- + * + * Calculates checksum over a length of bytes contained in an NB. + * + * nb : NB which contains the packet bytes. + * csumDataLen : Length of bytes to be checksummed. + * offset : offset to the first bytes of the data stream to be + * checksumed. + * + * Result: + * return 0, if there is a failure. + *---------------------------------------------------------------------------- + */ +UINT16 +CalculateChecksumNB(const PNET_BUFFER nb, + UINT16 csumDataLen, + UINT32 offset) +{ + ULONG mdlLen; + UINT16 csLen; + PUCHAR src; + UINT64 csum = 0; + PMDL currentMdl; + ULONG firstMdlLen; + /* Running count of bytes in remainder of the MDLs including current. */ + ULONG packetLen; + BOOLEAN swapEnd = 1 & csumDataLen; + + if ((nb == NULL) || (csumDataLen == 0) + || (offset >= NET_BUFFER_DATA_LENGTH(nb)) + || (offset + csumDataLen > NET_BUFFER_DATA_LENGTH(nb))) { + OVS_LOG_ERROR("Invalid parameters - csum length %u, offset %u," + "pkt%s len %u", csumDataLen, offset, nb? "":"(null)", + nb? NET_BUFFER_DATA_LENGTH(nb) : 0); + return 0; + } + + currentMdl = NET_BUFFER_CURRENT_MDL(nb); + packetLen = NET_BUFFER_DATA_LENGTH(nb); + firstMdlLen = + MmGetMdlByteCount(currentMdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb); + + firstMdlLen = MIN(firstMdlLen, packetLen); + if (offset < firstMdlLen) { + src = (PUCHAR) MmGetSystemAddressForMdlSafe(currentMdl, LowPagePriority); + if (!src) { + return 0; + } + src += (NET_BUFFER_CURRENT_MDL_OFFSET(nb) + offset); + mdlLen = firstMdlLen - offset; + packetLen -= firstMdlLen; + ASSERT((INT)packetLen >= 0); + } else { + offset -= firstMdlLen; + packetLen -= firstMdlLen; + ASSERT((INT)packetLen >= 0); + currentMdl = NDIS_MDL_LINKAGE(currentMdl); + mdlLen = MmGetMdlByteCount(currentMdl); + mdlLen = MIN(mdlLen, packetLen); + + while (offset >= mdlLen) { + offset -= mdlLen; + packetLen -= mdlLen; + ASSERT((INT)packetLen >= 0); + currentMdl = NDIS_MDL_LINKAGE(currentMdl); + mdlLen = MmGetMdlByteCount(currentMdl); + mdlLen = MIN(mdlLen, packetLen); + } + + src = (PUCHAR)MmGetSystemAddressForMdlSafe(currentMdl, LowPagePriority); + if (!src) { + return 0; + } + + src += offset; + mdlLen -= offset; + } + + while (csumDataLen && (currentMdl != NULL)) { + ASSERT(mdlLen < 65536); + csLen = MIN((UINT16) mdlLen, csumDataLen); + + csum = CalculateOnesComplement(src, csLen, csum, !(1 & csumDataLen)); + fold64(csum); + + csumDataLen -= csLen; + currentMdl = NDIS_MDL_LINKAGE(currentMdl); + if (csumDataLen && currentMdl) { + src = MmGetSystemAddressForMdlSafe(currentMdl, LowPagePriority); + if (!src) { + return 0; + } + + mdlLen = MmGetMdlByteCount(currentMdl); + mdlLen = MIN(mdlLen, packetLen); + /* packetLen does not include the current MDL from here on. */ + packetLen -= mdlLen; + ASSERT((INT)packetLen >= 0); + } + } + + fold64(csum); + ASSERT(csumDataLen == 0); + ASSERT((csum & ~0xffff) == 0); + csum = (UINT16)~csum; + if (swapEnd) { + return _byteswap_ushort((UINT16)csum); + } + return (UINT16)csum; +} + +/* + * -------------------------------------------------------------------------- + * OvsValidateIPChecksum + * -------------------------------------------------------------------------- + */ +NDIS_STATUS +OvsValidateIPChecksum(PNET_BUFFER_LIST curNbl, + POVS_PACKET_HDR_INFO hdrInfo) +{ + NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo; + uint16_t checksum, hdrChecksum; + struct IPHdr ip_storage; + const IPHdr *ipHdr; + + if (!hdrInfo->isIPv4) { + return NDIS_STATUS_SUCCESS; + } + + /* First check if NIC has indicated checksum failure. */ + csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl, + TcpIpChecksumNetBufferListInfo); + if (csumInfo.Receive.IpChecksumFailed) { + return NDIS_STATUS_FAILURE; + } + + /* Next, check if the NIC did not validate the RX checksum. */ + if (!csumInfo.Receive.IpChecksumSucceeded) { + ipHdr = OvsGetIp(curNbl, hdrInfo->l3Offset, &ip_storage); + if (ipHdr) { + ip_storage = *ipHdr; + hdrChecksum = ipHdr->check; + ip_storage.check = 0; + checksum = IPChecksum((uint8 *)&ip_storage, ipHdr->ihl * 4, 0); + if (checksum != hdrChecksum) { + return NDIS_STATUS_FAILURE; + } + } + } + return NDIS_STATUS_SUCCESS; +} + +/* + *---------------------------------------------------------------------------- + * OvsValidateUDPChecksum + *---------------------------------------------------------------------------- + */ +NDIS_STATUS +OvsValidateUDPChecksum(PNET_BUFFER_LIST curNbl, BOOLEAN udpCsumZero) +{ + NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo; + + csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo); + + if (udpCsumZero) { + /* Zero is valid checksum. */ + csumInfo.Receive.UdpChecksumFailed = 0; + NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo) = csumInfo.Value; + return NDIS_STATUS_SUCCESS; + } + + /* First check if NIC has indicated UDP checksum failure. */ + if (csumInfo.Receive.UdpChecksumFailed) { + return NDIS_STATUS_INVALID_PACKET; + } + + return NDIS_STATUS_SUCCESS; +} + + +/* + * OvsApplySWChecksumOnNB -- + * + * This function calculates and sets the required sofware offloads given by + * csumInfo for a given NBL(nbl) with a single NB. + * + */ +NDIS_STATUS +OvsApplySWChecksumOnNB(POVS_PACKET_HDR_INFO layers, + PNET_BUFFER_LIST nbl, + PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo) +{ + PNET_BUFFER curNb; + PMDL curMdl; + PUINT8 bufferStart; + UINT32 packetLength = 0; + ASSERT(nbl != NULL); + + curNb = NET_BUFFER_LIST_FIRST_NB(nbl); + ASSERT(curNb->Next == NULL); + packetLength = NET_BUFFER_DATA_LENGTH(curNb); + curMdl = NET_BUFFER_CURRENT_MDL(curNb); + bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, + LowPagePriority); + if (!bufferStart) { + return NDIS_STATUS_RESOURCES; + } + + bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb); + + if (layers->isIPv4) { + IPHdr *ip = (IPHdr *)(bufferStart + layers->l3Offset); + + if (csumInfo->Transmit.IpHeaderChecksum) { + ip->check = 0; + ip->check = IPChecksum((UINT8 *)ip, 4 * ip->ihl, 0); + } + + if (layers->isTcp && csumInfo->Transmit.TcpChecksum) { + UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); + TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset); + tcp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr, + IPPROTO_TCP, csumLength); + tcp->check = CalculateChecksumNB(curNb, csumLength, + (UINT32)(layers->l4Offset)); + } else if (layers->isUdp && csumInfo->Transmit.UdpChecksum) { + UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); + UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip); + udp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr, + IPPROTO_UDP, csumLength); + udp->check = CalculateChecksumNB(curNb, csumLength, + (UINT32)(layers->l4Offset)); + } + } else if (layers->isIPv6) { + IPv6Hdr *ip = (IPv6Hdr *)(bufferStart + layers->l3Offset); + + if (layers->isTcp && csumInfo->Transmit.TcpChecksum) { + UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); + TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset); + tcp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr, + (UINT32 *) &ip->daddr, + IPPROTO_TCP, csumLength); + tcp->check = CalculateChecksumNB(curNb, csumLength, + (UINT32)(layers->l4Offset)); + } else if (layers->isUdp && csumInfo->Transmit.UdpChecksum) { + UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); + UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip); + udp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr, + (UINT32 *) &ip->daddr, + IPPROTO_UDP, csumLength); + udp->check = CalculateChecksumNB(curNb, csumLength, + (UINT32)(layers->l4Offset)); + } + } + + return NDIS_STATUS_SUCCESS; +} + +/* + * OVSGetTcpMSS -- + * + * This function returns the maximum segment size of the given NBL. It takes + * into consideration both LSO v1 and v2. + */ +ULONG +OVSGetTcpMSS(PNET_BUFFER_LIST nbl) +{ + NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO lsoInfo; + ASSERT(nbl != NULL); + + lsoInfo.Value = NET_BUFFER_LIST_INFO(nbl, + TcpLargeSendNetBufferListInfo); + switch (lsoInfo.Transmit.Type) { + case NDIS_TCP_LARGE_SEND_OFFLOAD_V1_TYPE: + return lsoInfo.LsoV1Transmit.MSS; + break; + case NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE: + return lsoInfo.LsoV2Transmit.MSS; + break; + default: + OVS_LOG_ERROR("Unknown LSO transmit type:%d", + lsoInfo.Transmit.Type); + return 0; + } +} diff --git a/datapath-windows/ovsext/Offload.h b/datapath-windows/ovsext/Offload.h new file mode 100644 index 0000000..b5cae2f --- /dev/null +++ b/datapath-windows/ovsext/Offload.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014, 2016 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __OFFLOAD_H_ +#define __OFFLOAD_H_ 1 + +typedef union _OVS_PACKET_HDR_INFO *POVS_PACKET_HDR_INFO; + +UINT16 CalculateChecksum(UINT8 *ptr, UINT16 length, UINT16 initial); +UINT16 CopyAndCalculateChecksum(UINT8 *dst, UINT8 *src, UINT16 length, + UINT16 initial); +UINT16 IPChecksum(UINT8 *ipHdr, UINT16 length, UINT16 initial); +UINT16 IPPseudoChecksum(UINT32 *src, UINT32 *dst, UINT8 protocol, + UINT16 totalLength); +UINT16 IPv6PseudoChecksum(UINT32 *src, UINT32 *dst, UINT8 protocol, + UINT16 totalLength); +UINT16 ChecksumUpdate32(UINT16 oldSum, UINT32 prev, UINT32 newValue); +UINT16 ChecksumUpdate16(UINT16 oldSum, UINT16 prev, UINT16 newValue); +UINT16 CalculateChecksumNB(const PNET_BUFFER nb, UINT16 csumDataLen, + UINT32 offset); +NDIS_STATUS OvsValidateIPChecksum(PNET_BUFFER_LIST curNbl, + POVS_PACKET_HDR_INFO hdrInfo); +NDIS_STATUS OvsValidateUDPChecksum(PNET_BUFFER_LIST curNbl, + BOOLEAN udpCsumZero); + + +ULONG OVSGetTcpMSS(PNET_BUFFER_LIST nbl); + +NDIS_STATUS OvsApplySWChecksumOnNB(POVS_PACKET_HDR_INFO layers, + PNET_BUFFER_LIST nbl, + PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO + csumInfo); + +#endif /* __OFFLOAD_H_ */ diff --git a/datapath-windows/ovsext/Stt.c b/datapath-windows/ovsext/Stt.c index 0ae2633..dd7bf92 100644 --- a/datapath-windows/ovsext/Stt.c +++ b/datapath-windows/ovsext/Stt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 VMware, Inc. + * Copyright (c) 2015, 2016 VMware, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,12 @@ #include "precomp.h" #include "Atomic.h" -#include "Checksum.h" +#include "Debug.h" #include "Flow.h" #include "IpHelper.h" +#include "Jhash.h" #include "NetProto.h" +#include "Offload.h" #include "PacketIO.h" #include "PacketParser.h" #include "Stt.h" @@ -33,8 +35,7 @@ #undef OVS_DBG_MOD #endif #define OVS_DBG_MOD OVS_DBG_STT -#include "Debug.h" -#include "Jhash.h" + KSTART_ROUTINE OvsSttDefragCleaner; static PLIST_ENTRY OvsSttPktFragHash; @@ -163,20 +164,7 @@ OvsDoEncapStt(POVS_VPORT_ENTRY vport, BOOLEAN innerPartialChecksum = FALSE; if (layers->isTcp) { - lsoInfo.Value = NET_BUFFER_LIST_INFO(curNbl, - TcpLargeSendNetBufferListInfo); - - switch (lsoInfo.Transmit.Type) { - case NDIS_TCP_LARGE_SEND_OFFLOAD_V1_TYPE: - mss = lsoInfo.LsoV1Transmit.MSS; - break; - case NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE: - mss = lsoInfo.LsoV2Transmit.MSS; - break; - default: - OVS_LOG_ERROR("Unknown LSO transmit type:%d", - lsoInfo.Transmit.Type); - } + mss = OVSGetTcpMSS(curNbl); } vportStt = (POVS_STT_VPORT) GetOvsVportPriv(vport); diff --git a/datapath-windows/ovsext/User.c b/datapath-windows/ovsext/User.c index 04d2294..e97f2b2 100644 --- a/datapath-windows/ovsext/User.c +++ b/datapath-windows/ovsext/User.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 VMware, Inc. + * Copyright (c) 2014, 2016 VMware, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,23 +22,23 @@ #include "precomp.h" -#include "Switch.h" -#include "Vport.h" -#include "Event.h" -#include "User.h" #include "Datapath.h" -#include "PacketIO.h" -#include "Checksum.h" -#include "NetProto.h" +#include "Debug.h" +#include "Event.h" #include "Flow.h" -#include "TunnelIntf.h" #include "Jhash.h" +#include "NetProto.h" +#include "Offload.h" +#include "PacketIO.h" +#include "Switch.h" +#include "TunnelIntf.h" +#include "User.h" +#include "Vport.h" #ifdef OVS_DBG_MOD #undef OVS_DBG_MOD #endif #define OVS_DBG_MOD OVS_DBG_USER -#include "Debug.h" POVS_PACKET_QUEUE_ELEM OvsGetNextPacket(POVS_OPEN_INSTANCE instance); extern PNDIS_SPIN_LOCK gOvsCtrlLock; diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c index 2516ece..b89c032 100644 --- a/datapath-windows/ovsext/Vxlan.c +++ b/datapath-windows/ovsext/Vxlan.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 VMware, Inc. + * Copyright (c) 2014, 2016 VMware, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,18 +15,20 @@ */ #include "precomp.h" + #include "Atomic.h" -#include "NetProto.h" -#include "Switch.h" -#include "Vport.h" +#include "Debug.h" +#include "Flow.h" #include "Flow.h" -#include "Vxlan.h" #include "IpHelper.h" -#include "Checksum.h" -#include "User.h" +#include "NetProto.h" +#include "Offload.h" #include "PacketIO.h" -#include "Flow.h" #include "PacketParser.h" +#include "Switch.h" +#include "User.h" +#include "Vport.h" +#include "Vxlan.h" #pragma warning( push ) #pragma warning( disable:4127 ) @@ -36,7 +38,6 @@ #undef OVS_DBG_MOD #endif #define OVS_DBG_MOD OVS_DBG_VXLAN -#include "Debug.h" /* Helper macro to check if a VXLAN ID is valid. */ #define VXLAN_ID_IS_VALID(vxlanID) (0 < (vxlanID) && (vxlanID) <= 0xffffff) @@ -201,21 +202,8 @@ OvsDoEncapVxlan(POVS_VPORT_ENTRY vport, packetLength = NET_BUFFER_DATA_LENGTH(curNb); if (layers->isTcp) { - NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO tsoInfo; - - tsoInfo.Value = NET_BUFFER_LIST_INFO(curNbl, - TcpLargeSendNetBufferListInfo); - switch (tsoInfo.Transmit.Type) { - case NDIS_TCP_LARGE_SEND_OFFLOAD_V1_TYPE: - mss = tsoInfo.LsoV1Transmit.MSS; - break; - case NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE: - mss = tsoInfo.LsoV2Transmit.MSS; - break; - default: - OVS_LOG_ERROR("Unknown LSO transmit type:%d", - tsoInfo.Transmit.Type); - } + mss = OVSGetTcpMSS(curNbl); + OVS_LOG_TRACE("MSS %u packet len %u", mss, packetLength); if (mss) { @@ -242,70 +230,14 @@ OvsDoEncapVxlan(POVS_VPORT_ENTRY vport, OVS_LOG_ERROR("Unable to copy NBL"); return NDIS_STATUS_FAILURE; } - /* - * To this point we do not have VXLAN offloading. - * Apply defined checksums - */ - curNb = NET_BUFFER_LIST_FIRST_NB(*newNbl); - curMdl = NET_BUFFER_CURRENT_MDL(curNb); - bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority); - if (!bufferStart) { - status = NDIS_STATUS_RESOURCES; - goto ret_error; - } - NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo; csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo); + status = OvsApplySWChecksumOnNB(layers, *newNbl, &csumInfo); - bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb); - - if (layers->isIPv4) { - IPHdr *ip = (IPHdr *)(bufferStart + layers->l3Offset); - - if (csumInfo.Transmit.IpHeaderChecksum) { - ip->check = 0; - ip->check = IPChecksum((UINT8 *)ip, 4 * ip->ihl, 0); - } - - if (layers->isTcp && csumInfo.Transmit.TcpChecksum) { - UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); - TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset); - tcp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr, - IPPROTO_TCP, csumLength); - tcp->check = CalculateChecksumNB(curNb, csumLength, - (UINT32)(layers->l4Offset)); - } else if (layers->isUdp && csumInfo.Transmit.UdpChecksum) { - UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); - UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip); - udp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr, - IPPROTO_UDP, csumLength); - udp->check = CalculateChecksumNB(curNb, csumLength, - (UINT32)(layers->l4Offset)); - } - } else if (layers->isIPv6) { - IPv6Hdr *ip = (IPv6Hdr *)(bufferStart + layers->l3Offset); - - if (layers->isTcp && csumInfo.Transmit.TcpChecksum) { - UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); - TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset); - tcp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr, - (UINT32 *) &ip->daddr, - IPPROTO_TCP, csumLength); - tcp->check = CalculateChecksumNB(curNb, csumLength, - (UINT32)(layers->l4Offset)); - } else if (layers->isUdp && csumInfo.Transmit.UdpChecksum) { - UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset); - UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip); - udp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr, - (UINT32 *) &ip->daddr, - IPPROTO_UDP, csumLength); - udp->check = CalculateChecksumNB(curNb, csumLength, - (UINT32)(layers->l4Offset)); - } + if (status != NDIS_STATUS_SUCCESS) { + goto ret_error; } - /* Clear out TcpIpChecksumNetBufferListInfo flag */ - NET_BUFFER_LIST_INFO(*newNbl, TcpIpChecksumNetBufferListInfo) = 0; } curNbl = *newNbl; diff --git a/datapath-windows/ovsext/ovsext.vcxproj b/datapath-windows/ovsext/ovsext.vcxproj index fd10809..7b0ebcf 100644 --- a/datapath-windows/ovsext/ovsext.vcxproj +++ b/datapath-windows/ovsext/ovsext.vcxproj @@ -73,7 +73,6 @@ <ClInclude Include="..\include\OvsDpInterfaceExt.h" /> <ClInclude Include="Atomic.h" /> <ClInclude Include="BufferMgmt.h" /> - <ClInclude Include="Checksum.h" /> <ClInclude Include="Datapath.h" /> <ClInclude Include="Debug.h" /> <ClInclude Include="DpInternal.h" /> @@ -89,6 +88,7 @@ <ClInclude Include="Netlink/NetlinkProto.h" /> <ClInclude Include="Netlink\NetlinkError.h" /> <ClInclude Include="NetProto.h" /> + <ClInclude Include="Offload.h" /> <ClInclude Include="Oid.h" /> <ClInclude Include="PacketIO.h" /> <ClInclude Include="PacketParser.h" /> @@ -169,7 +169,6 @@ <ItemGroup> <ClCompile Include="Actions.c" /> <ClCompile Include="BufferMgmt.c" /> - <ClCompile Include="Checksum.c" /> <ClCompile Include="Debug.c" /> <ClCompile Include="Driver.c" /> <ClCompile Include="Event.c" /> @@ -180,6 +179,7 @@ <ClCompile Include="Netlink/Netlink.c" /> <ClCompile Include="Netlink/NetlinkBuf.c" /> <ClCompile Include="Datapath.c" /> + <ClCompile Include="Offload.c" /> <ClCompile Include="Oid.c" /> <ClCompile Include="PacketIO.c" /> <ClCompile Include="PacketParser.c" /> -- 1.9.5.msysgit.0 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev