[ovs-dev] [PATCH] datapath-windows: Refactor sofware offloads and mss

Alin Serdean aserdean at cloudbasesolutions.com
Thu Feb 11 01:38:54 UTC 2016


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 <aserdean at 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



More information about the dev mailing list