[ovs-dev] [PATCH] Add Geneve support on Windows datapath.

Yin Lin linyi at vmware.com
Wed May 18 00:02:32 UTC 2016


---
 datapath-windows/ovsext/Actions.c      |  82 +++-----
 datapath-windows/ovsext/Debug.h        |   1 +
 datapath-windows/ovsext/DpInternal.h   |  29 ++-
 datapath-windows/ovsext/Flow.c         | 154 ++++++++++++--
 datapath-windows/ovsext/Flow.h         |   6 +
 datapath-windows/ovsext/Geneve.c       | 362 +++++++++++++++++++++++++++++++++
 datapath-windows/ovsext/Geneve.h       | 122 +++++++++++
 datapath-windows/ovsext/Gre.c          |   8 +-
 datapath-windows/ovsext/Offload.c      |  45 ++++
 datapath-windows/ovsext/Offload.h      |   6 +-
 datapath-windows/ovsext/Stt.c          |   2 +-
 datapath-windows/ovsext/Tunnel.c       |   3 +-
 datapath-windows/ovsext/Util.h         |   1 +
 datapath-windows/ovsext/Vport.c        |  23 ++-
 datapath-windows/ovsext/Vport.h        |  10 +-
 datapath-windows/ovsext/Vxlan.c        |  49 +----
 datapath-windows/ovsext/ovsext.vcxproj |   2 +
 manpages.mk                            |   4 -
 18 files changed, 767 insertions(+), 142 deletions(-)
 create mode 100644 datapath-windows/ovsext/Geneve.c
 create mode 100644 datapath-windows/ovsext/Geneve.h

diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c
index 5ad29ee..560f7a1 100644
--- a/datapath-windows/ovsext/Actions.c
+++ b/datapath-windows/ovsext/Actions.c
@@ -48,6 +48,8 @@ typedef struct _OVS_ACTION_STATS {
     UINT64 txVxlan;
     UINT64 rxStt;
     UINT64 txStt;
+    UINT64 rxGeneve;
+    UINT64 txGeneve;
     UINT64 flowMiss;
     UINT64 flowUserspace;
     UINT64 txTcp;
@@ -227,18 +229,22 @@ OvsDetectTunnelRxPkt(OvsForwardingContext *ovsFwdCtx,
             break;
         case IPPROTO_TCP:
             tunnelVport = OvsFindTunnelVportByDstPort(ovsFwdCtx->switchContext,
-                                                      dstPort,
-                                                      OVS_VPORT_TYPE_STT);
+                                                      dstPort);
             if (tunnelVport) {
+                ASSERT(tunnelVport->ovsType == OVS_VPORT_TYPE_STT);
                 ovsActionStats.rxStt++;
             }
             break;
         case IPPROTO_UDP:
             tunnelVport = OvsFindTunnelVportByDstPort(ovsFwdCtx->switchContext,
-                                                      dstPort,
-                                                      OVS_VPORT_TYPE_VXLAN);
+                                                      dstPort);
             if (tunnelVport) {
-                ovsActionStats.rxVxlan++;
+                if (tunnelVport->ovsType == OVS_VPORT_TYPE_VXLAN) {
+                    ovsActionStats.rxVxlan++;
+                } else {
+                    ASSERT(tunnelVport->ovsType == OVS_VPORT_TYPE_GENEVE);
+                    ovsActionStats.rxGeneve++;
+                }
             }
             break;
         }
@@ -333,6 +339,9 @@ OvsDetectTunnelPkt(OvsForwardingContext *ovsFwdCtx,
             case OVS_VPORT_TYPE_STT:
                 ovsActionStats.txStt++;
                 break;
+            case OVS_VPORT_TYPE_GENEVE:
+               ovsActionStats.txGeneve++;
+               break;
             }
             ovsFwdCtx->tunnelTxNic = dstVport;
         }
@@ -689,6 +698,11 @@ OvsTunnelPortTx(OvsForwardingContext *ovsFwdCtx)
                              &ovsFwdCtx->tunKey, ovsFwdCtx->switchContext,
                              &ovsFwdCtx->layers, &newNbl);
         break;
+    case OVS_VPORT_TYPE_GENEVE:
+        status = OvsEncapGeneve(ovsFwdCtx->tunnelTxNic, ovsFwdCtx->curNbl,
+                                &ovsFwdCtx->tunKey, ovsFwdCtx->switchContext,
+                                &ovsFwdCtx->layers, &newNbl);
+        break;
     default:
         ASSERT(! "Tx: Unhandled tunnel type");
     }
@@ -767,6 +781,10 @@ OvsTunnelPortRx(OvsForwardingContext *ovsFwdCtx)
             dropReason = L"OVS-STT segment is cached";
         }
         break;
+    case OVS_VPORT_TYPE_GENEVE:
+        status = OvsDecapGeneve(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
+                                &ovsFwdCtx->tunKey, &newNbl);
+        break;
     default:
         OVS_LOG_ERROR("Rx: Unhandled tunnel type: %d\n",
                       tunnelRxVport->ovsType);
@@ -1233,57 +1251,6 @@ OvsActionMplsPush(OvsForwardingContext *ovsFwdCtx,
 }
 
 /*
- * --------------------------------------------------------------------------
- * OvsTunnelAttrToIPv4TunnelKey --
- *      Convert tunnel attribute to OvsIPv4TunnelKey.
- * --------------------------------------------------------------------------
- */
-static __inline NDIS_STATUS
-OvsTunnelAttrToIPv4TunnelKey(PNL_ATTR attr,
-                             OvsIPv4TunnelKey *tunKey)
-{
-   PNL_ATTR a;
-   INT rem;
-
-   tunKey->attr[0] = 0;
-   tunKey->attr[1] = 0;
-   tunKey->attr[2] = 0;
-   ASSERT(NlAttrType(attr) == OVS_KEY_ATTR_TUNNEL);
-
-   NL_ATTR_FOR_EACH_UNSAFE (a, rem, NlAttrData(attr),
-                            NlAttrGetSize(attr)) {
-      switch (NlAttrType(a)) {
-      case OVS_TUNNEL_KEY_ATTR_ID:
-         tunKey->tunnelId = NlAttrGetBe64(a);
-         tunKey->flags |= OVS_TNL_F_KEY;
-         break;
-      case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
-         tunKey->src = NlAttrGetBe32(a);
-         break;
-      case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
-         tunKey->dst = NlAttrGetBe32(a);
-         break;
-      case OVS_TUNNEL_KEY_ATTR_TOS:
-         tunKey->tos = NlAttrGetU8(a);
-         break;
-      case OVS_TUNNEL_KEY_ATTR_TTL:
-         tunKey->ttl = NlAttrGetU8(a);
-         break;
-      case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
-         tunKey->flags |= OVS_TNL_F_DONT_FRAGMENT;
-         break;
-      case OVS_TUNNEL_KEY_ATTR_CSUM:
-         tunKey->flags |= OVS_TNL_F_CSUM;
-         break;
-      default:
-         ASSERT(0);
-      }
-   }
-
-   return NDIS_STATUS_SUCCESS;
-}
-
-/*
  *----------------------------------------------------------------------------
  * OvsUpdateEthHeader --
  *      Updates the ethernet header in ovsFwdCtx.curNbl inline based on the
@@ -1511,7 +1478,8 @@ OvsExecuteSetAction(OvsForwardingContext *ovsFwdCtx,
     case OVS_KEY_ATTR_TUNNEL:
     {
         OvsIPv4TunnelKey tunKey;
-        status = OvsTunnelAttrToIPv4TunnelKey((PNL_ATTR)a, &tunKey);
+        NTSTATUS convertStatus = OvsTunnelAttrToIPv4TunnelKey((PNL_ATTR)a, &tunKey);
+        status = SUCCEEDED(convertStatus) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE;
         ASSERT(status == NDIS_STATUS_SUCCESS);
         tunKey.flow_hash = (uint16)(hash ? *hash : OvsHashFlow(key));
         tunKey.dst_port = key->ipKey.l4.tpDst;
diff --git a/datapath-windows/ovsext/Debug.h b/datapath-windows/ovsext/Debug.h
index e5ed963..935f858 100644
--- a/datapath-windows/ovsext/Debug.h
+++ b/datapath-windows/ovsext/Debug.h
@@ -41,6 +41,7 @@
 #define OVS_DBG_TUNFLT   BIT32(21)
 #define OVS_DBG_STT      BIT32(22)
 #define OVS_DBG_CONTRK   BIT32(23)
+#define OVS_DBG_GENEVE   BIT32(24)
 
 #define OVS_DBG_RESERVED BIT32(31)
 //Please add above OVS_DBG_RESERVED.
diff --git a/datapath-windows/ovsext/DpInternal.h b/datapath-windows/ovsext/DpInternal.h
index a3ce311..a95467b 100644
--- a/datapath-windows/ovsext/DpInternal.h
+++ b/datapath-windows/ovsext/DpInternal.h
@@ -128,10 +128,18 @@ typedef struct L2Key {
 } L2Key; /* Size of 24 byte. */
 
 /* Number of packet attributes required to store OVS tunnel key. */
-#define NUM_PKT_ATTR_REQUIRED 3
+#define NUM_PKT_ATTR_REQUIRED 35
+#define TUN_OPT_MAX_LEN 255
 
 typedef union OvsIPv4TunnelKey {
+    /* Options should always be the first member of tunnel key.
+     * They are stored at the end of the array if they are less than the
+     * maximum size. This allows us to get the benefits of variable length
+     * matching for small options.
+     */
     struct {
+        UINT8 tunOpts[TUN_OPT_MAX_LEN];          /* Tunnel options. */
+        UINT8 tunOptLen;             /* Tunnel option length in byte. */
         ovs_be32 dst;
         ovs_be32 src;
         ovs_be64 tunnelId;
@@ -147,7 +155,22 @@ typedef union OvsIPv4TunnelKey {
         };
     };
     uint64_t attr[NUM_PKT_ATTR_REQUIRED];
-} OvsIPv4TunnelKey; /* Size of 24 byte. */
+} OvsIPv4TunnelKey; /* Size of 280 byte. */
+
+__inline uint8_t TunnelKeyGetOptionsOffset(OvsIPv4TunnelKey *key)
+{
+    return TUN_OPT_MAX_LEN - key->tunOptLen;
+}
+
+__inline uint8_t* TunnelKeyGetOptions(OvsIPv4TunnelKey *key)
+{
+    return key->tunOpts + TunnelKeyGetOptionsOffset(key);
+}
+
+__inline uint16_t TunnelKeyGetRealSize(OvsIPv4TunnelKey *key)
+{
+    return sizeof(OvsIPv4TunnelKey) - TunnelKeyGetOptionsOffset(key);
+}
 
 typedef struct MplsKey {
     ovs_be32 lse;                /* MPLS topmost label stack entry. */
@@ -155,7 +178,7 @@ typedef struct MplsKey {
 } MplsKey; /* Size of 8 bytes. */
 
 typedef __declspec(align(8)) struct OvsFlowKey {
-    OvsIPv4TunnelKey tunKey;     /* 24 bytes */
+    OvsIPv4TunnelKey tunKey;     /* 280 bytes */
     L2Key l2;                    /* 24 bytes */
     union {
         /* These headers are mutually exclusive. */
diff --git a/datapath-windows/ovsext/Flow.c b/datapath-windows/ovsext/Flow.c
index d957d39..200c11c 100644
--- a/datapath-windows/ovsext/Flow.c
+++ b/datapath-windows/ovsext/Flow.c
@@ -88,7 +88,7 @@ static NTSTATUS OvsDoDumpFlows(OvsFlowDumpInput *dumpInput,
                                UINT32 *replyLen);
 static NTSTATUS OvsProbeSupportedFeature(POVS_MESSAGE msgIn,
                                          PNL_ATTR keyAttr);
-
+static UINT16 OvsGetFlowL2Offset(OvsIPv4TunnelKey *tunKey);
 
 #define OVS_FLOW_TABLE_SIZE 2048
 #define OVS_FLOW_TABLE_MASK (OVS_FLOW_TABLE_SIZE -1)
@@ -1029,6 +1029,13 @@ MapFlowTunKeyToNlKey(PNL_BUFFER nlBuf,
         goto done;
     }
 
+    if (tunKey->tunOptLen > 0 &&
+        !NlMsgPutTailUnspec(nlBuf, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
+                            (PCHAR)TunnelKeyGetOptions(tunKey), tunKey->tunOptLen)) {
+        rc = STATUS_UNSUCCESSFUL;
+        goto done;
+    }
+
 done:
     NlMsgEndNested(nlBuf, offset);
 error_nested_start:
@@ -1635,6 +1642,99 @@ _MapKeyAttrToFlowPut(PNL_ATTR *keyAttrs,
 
 /*
  *----------------------------------------------------------------------------
+ *  OvsTunnelAttrToGeneveOptions --
+ *    Converts OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS attribute to tunKey->tunOpts.
+ *----------------------------------------------------------------------------
+ */
+static __inline NTSTATUS
+OvsTunnelAttrToGeneveOptions(PNL_ATTR attr,
+                             OvsIPv4TunnelKey *tunKey)
+{
+    UINT32 optLen = NlAttrGetSize(attr);
+    if (optLen > TUN_OPT_MAX_LEN) {
+        OVS_LOG_ERROR("Geneve option length err (len %d, max %Iu).",
+                      optLen, TUN_OPT_MAX_LEN);
+        return STATUS_INFO_LENGTH_MISMATCH;
+    } else if (optLen % 4 != 0) {
+        OVS_LOG_ERROR("Geneve opt len %d is not a multiple of 4.", optLen);
+        return STATUS_INFO_LENGTH_MISMATCH;
+    }
+    tunKey->tunOptLen = (UINT8)optLen;
+    memcpy(TunnelKeyGetOptions(tunKey), NlAttrData(attr), optLen);
+    return STATUS_SUCCESS;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *  OvsTunnelAttrToGeneveOptions --
+ *    Converts OVS_KEY_ATTR_TUNNEL attribute to tunKey.
+ *----------------------------------------------------------------------------
+ */
+NTSTATUS
+OvsTunnelAttrToIPv4TunnelKey(PNL_ATTR attr,
+                             OvsIPv4TunnelKey *tunKey)
+{
+    PNL_ATTR a;
+    INT rem;
+    INT hasOpt = 0;
+    NTSTATUS status;
+
+    memset(tunKey, 0, OVS_WIN_TUNNEL_KEY_SIZE);
+    ASSERT(NlAttrType(attr) == OVS_KEY_ATTR_TUNNEL);
+
+    NL_ATTR_FOR_EACH_UNSAFE(a, rem, NlAttrData(attr),
+        NlAttrGetSize(attr)) {
+        switch (NlAttrType(a)) {
+        case OVS_TUNNEL_KEY_ATTR_ID:
+            tunKey->tunnelId = NlAttrGetBe64(a);
+            tunKey->flags |= OVS_TNL_F_KEY;
+            break;
+        case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
+            tunKey->src = NlAttrGetBe32(a);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
+            tunKey->dst = NlAttrGetBe32(a);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_TOS:
+            tunKey->tos = NlAttrGetU8(a);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_TTL:
+            tunKey->ttl = NlAttrGetU8(a);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
+            tunKey->flags |= OVS_TNL_F_DONT_FRAGMENT;
+            break;
+        case OVS_TUNNEL_KEY_ATTR_CSUM:
+            tunKey->flags |= OVS_TNL_F_CSUM;
+            break;
+        case OVS_TUNNEL_KEY_ATTR_OAM:
+            tunKey->flags |= OVS_TNL_F_OAM;
+            break;
+        case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
+            if (hasOpt) {
+                /* Duplicate options attribute is not allowed. */
+                return NDIS_STATUS_FAILURE;
+            }
+            status = OvsTunnelAttrToGeneveOptions(a, tunKey);
+            if (!SUCCEEDED(status)) {
+                return status;
+            }
+            tunKey->flags |= OVS_TNL_F_GENEVE_OPT;
+            hasOpt = 1;
+            break;
+        default:
+            // XXX: Support OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS
+            return STATUS_INVALID_PARAMETER;
+        }
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
  *  _MapTunAttrToFlowPut --
  *    Converts FLOW_TUNNEL_KEY attribute to OvsFlowKey->tunKey.
  *----------------------------------------------------------------------------
@@ -1644,8 +1744,10 @@ _MapTunAttrToFlowPut(PNL_ATTR *keyAttrs,
                      PNL_ATTR *tunAttrs,
                      OvsFlowKey *destKey)
 {
+    memset(&destKey->tunKey, 0, OVS_WIN_TUNNEL_KEY_SIZE);
     if (keyAttrs[OVS_KEY_ATTR_TUNNEL]) {
-
+        /* XXX: This blocks performs same functionality as OvsTunnelAttrToIPv4TunnelKey.
+           Consider refactoring the code.*/
         if (tunAttrs[OVS_TUNNEL_KEY_ATTR_ID]) {
             destKey->tunKey.tunnelId = NlAttrGetU64
                                        (tunAttrs[OVS_TUNNEL_KEY_ATTR_ID]);
@@ -1680,13 +1782,18 @@ _MapTunAttrToFlowPut(PNL_ATTR *keyAttrs,
                               (tunAttrs[OVS_TUNNEL_KEY_ATTR_TTL]);
         }
 
-        destKey->tunKey.pad = 0;
-        destKey->l2.offset = 0;
+        if (tunAttrs[OVS_TUNNEL_KEY_ATTR_OAM]) {
+        destKey->tunKey.flags |= OVS_TNL_F_OAM;
+        }
+
+        if (tunAttrs[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS]) {
+        OvsTunnelAttrToGeneveOptions(tunAttrs[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS],
+                                     &destKey->tunKey);
+        destKey->tunKey.flags |= OVS_TNL_F_GENEVE_OPT;
+        }
+        destKey->l2.offset = OvsGetFlowL2Offset(&destKey->tunKey);
     } else {
-        destKey->tunKey.attr[0] = 0;
-        destKey->tunKey.attr[1] = 0;
-        destKey->tunKey.attr[2] = 0;
-        destKey->l2.offset = sizeof destKey->tunKey;
+        destKey->l2.offset = OvsGetFlowL2Offset(NULL);
     }
 }
 
@@ -1850,6 +1957,20 @@ OvsGetFlowMetadata(OvsFlowKey *key,
     return status;
 }
 
+UINT16
+OvsGetFlowL2Offset(OvsIPv4TunnelKey *tunKey)
+{
+    if (tunKey != NULL) {
+        // Align with int64 boundary
+        if (tunKey->tunOptLen == 0) {
+            return (TUN_OPT_MAX_LEN + 1) / 8 * 8;
+        }
+        return TunnelKeyGetOptionsOffset(tunKey) / 8 * 8;
+    } else {
+        return OVS_WIN_TUNNEL_KEY_SIZE;
+    }
+}
+
 /*
  *----------------------------------------------------------------------------
  * Initializes 'flow' members from 'packet', 'skb_priority', 'tun_id', and
@@ -1881,23 +2002,25 @@ OvsExtractFlow(const NET_BUFFER_LIST *packet,
                OvsIPv4TunnelKey *tunKey)
 {
     struct Eth_Header *eth;
-    UINT8 offset = 0;
+    UINT8 offset;
     PVOID vlanTagValue;
 
     layers->value = 0;
 
     if (tunKey) {
         ASSERT(tunKey->dst != 0);
-        RtlMoveMemory(&flow->tunKey, tunKey, sizeof flow->tunKey);
-        flow->l2.offset = 0;
+        offset = TunnelKeyGetOptionsOffset(tunKey);
+        RtlMoveMemory(((UINT8 *)&flow->tunKey) + offset,
+                      ((UINT8 *)tunKey) + offset,
+                      TunnelKeyGetRealSize(tunKey));
     } else {
         flow->tunKey.dst = 0;
-        flow->l2.offset = OVS_WIN_TUNNEL_KEY_SIZE;
     }
-
+    flow->l2.offset = OvsGetFlowL2Offset(tunKey);
     flow->l2.inPort = inPort;
+    offset = 0;
 
-    if ( OvsPacketLenNBL(packet) < ETH_HEADER_LEN_DIX) {
+    if (OvsPacketLenNBL(packet) < ETH_HEADER_LEN_DIX) {
         flow->l2.keyLen = OVS_WIN_TUNNEL_KEY_SIZE + 8 - flow->l2.offset;
         return NDIS_STATUS_SUCCESS;
     }
@@ -2222,7 +2345,6 @@ OvsLookupFlow(OVS_DATAPATH *datapath,
     UINT8 *start;
 
     ASSERT(key->tunKey.dst || offset == sizeof (OvsIPv4TunnelKey));
-    ASSERT(!key->tunKey.dst || offset == 0);
 
     start = (UINT8 *)key + offset;
 
@@ -2278,7 +2400,7 @@ OvsHashFlow(const OvsFlowKey *key)
     UINT16 size = key->l2.keyLen;
     UINT8 *start;
 
-    ASSERT(key->tunKey.dst || offset == sizeof (OvsIPv4TunnelKey));
+    ASSERT(key->tunKey.dst || offset == sizeof(OvsIPv4TunnelKey));
     ASSERT(!key->tunKey.dst || offset == 0);
     start = (UINT8 *)key + offset;
     return OvsJhashBytes(start, size, 0);
diff --git a/datapath-windows/ovsext/Flow.h b/datapath-windows/ovsext/Flow.h
index 310c472..111d421 100644
--- a/datapath-windows/ovsext/Flow.h
+++ b/datapath-windows/ovsext/Flow.h
@@ -83,10 +83,16 @@ NTSTATUS MapFlowTunKeyToNlKey(PNL_BUFFER nlBuf, OvsIPv4TunnelKey *tunKey,
                               UINT16 tunKeyType);
 UINT32 OvsFlowKeyAttrSize(void);
 UINT32 OvsTunKeyAttrSize(void);
+NTSTATUS OvsTunnelAttrToIPv4TunnelKey(PNL_ATTR attr, OvsIPv4TunnelKey *tunKey);
 
 /* Flags for tunneling */
 #define OVS_TNL_F_DONT_FRAGMENT         (1 << 0)
 #define OVS_TNL_F_CSUM                  (1 << 1)
 #define OVS_TNL_F_KEY                   (1 << 2)
+#define OVS_TNL_F_OAM                   (1 << 3)
+#define OVS_TNL_F_GENEVE_OPT            (1 << 4)
+#define OVS_TNL_F_VXLAN_OPT             (1 << 5)
+
+#define OVS_TNL_HAS_OPTIONS             (OVS_TNL_F_GENEVE_OPT | OVS_TNL_F_VXLAN_OPT)
 
 #endif /* __FLOW_H_ */
diff --git a/datapath-windows/ovsext/Geneve.c b/datapath-windows/ovsext/Geneve.c
new file mode 100644
index 0000000..d3eed86
--- /dev/null
+++ b/datapath-windows/ovsext/Geneve.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 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 "Atomic.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 "Geneve.h"
+#include "Switch.h"
+#include "User.h"
+#include "Util.h"
+#include "Vport.h"
+
+#ifdef OVS_DBG_MOD
+#undef OVS_DBG_MOD
+#endif
+#define OVS_DBG_MOD OVS_DBG_GENEVE
+
+#pragma warning(disable:4100)
+
+static BOOLEAN
+OvsTunnelKeyIsCritical(OvsIPv4TunnelKey *tunKey)
+{
+    GeneveOptionHdr *hdr = (GeneveOptionHdr *)TunnelKeyGetOptions(tunKey);
+    for (UINT8 i = 0; i < tunKey->tunOptLen; i++, hdr++) {
+        if (hdr->type & GENEVE_CRIT_OPT_TYPE) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+NTSTATUS OvsInitGeneveTunnel(POVS_VPORT_ENTRY vport,
+                             UINT16 udpDestPort)
+{
+    POVS_GENEVE_VPORT genevePort;
+
+    genevePort = (POVS_GENEVE_VPORT) OvsAllocateMemoryWithTag(sizeof(*genevePort),
+                                                              OVS_GENEVE_POOL_TAG);
+    if (!genevePort) {
+        OVS_LOG_ERROR("Insufficient memory, can't allocate GENEVE_VPORT");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(genevePort, sizeof(*genevePort));
+    genevePort->dstPort = udpDestPort;
+    vport->priv = (PVOID) genevePort;
+    return STATUS_SUCCESS;
+}
+
+VOID
+OvsCleanupGeneveTunnel(POVS_VPORT_ENTRY vport)
+{
+    if (vport->ovsType != OVS_VPORT_TYPE_GENEVE ||
+        vport->priv == NULL) {
+        return;
+    }
+
+    OvsFreeMemoryWithTag(vport->priv, OVS_GENEVE_POOL_TAG);
+    vport->priv = NULL;
+}
+
+NDIS_STATUS OvsEncapGeneve(POVS_VPORT_ENTRY vport,
+                           PNET_BUFFER_LIST curNbl,
+                           OvsIPv4TunnelKey *tunKey,
+                           POVS_SWITCH_CONTEXT switchContext,
+                           POVS_PACKET_HDR_INFO layers,
+                           PNET_BUFFER_LIST *newNbl)
+{
+    NTSTATUS status;
+    OVS_FWD_INFO fwdInfo;
+    PNET_BUFFER curNb;
+    PMDL curMdl;
+    PUINT8 bufferStart;
+    EthHdr *ethHdr;
+    IPHdr *ipHdr;
+    UDPHdr *udpHdr;
+    GeneveHdr *geneveHdr;
+    GeneveOptionHdr *optHdr;
+    POVS_GENEVE_VPORT vportGeneve;
+    UINT32 headRoom = OvsGetGeneveTunHdrMinSize() + tunKey->tunOptLen;
+    UINT32 packetLength;
+    ULONG mss = 0;
+    UINT8 i;
+
+    status = OvsLookupIPFwdInfo(tunKey->dst, &fwdInfo);
+    if (status != STATUS_SUCCESS) {
+        OvsFwdIPHelperRequest(NULL, 0, tunKey, NULL, NULL, NULL);
+        // return NDIS_STATUS_PENDING;
+        /*
+         * XXX: Don't know if the completionList will make any sense when
+         * accessed in the callback. Make sure the caveats are known.
+         *
+         * XXX: This code will work once we are able to grab locks in the
+         * callback.
+         */
+        return NDIS_STATUS_FAILURE;
+    }
+
+     /*
+     * XXX: the assumption currently is that the NBL is owned by OVS, and
+     * headroom has already been allocated as part of allocating the NBL and
+     * MDL.
+     */
+    curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
+    packetLength = NET_BUFFER_DATA_LENGTH(curNb);
+
+    if (layers->isTcp) {
+        mss = OVSGetTcpMSS(curNbl);
+
+        OVS_LOG_TRACE("MSS %u packet len %u", mss,
+                      packetLength);
+        if (mss) {
+            OVS_LOG_TRACE("l4Offset %d", layers->l4Offset);
+            *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
+                                       mss, headRoom);
+            if (*newNbl == NULL) {
+                OVS_LOG_ERROR("Unable to segment NBL");
+                return NDIS_STATUS_FAILURE;
+            }
+            /* Clear out LSO flags after this point */
+            NET_BUFFER_LIST_INFO(*newNbl, TcpLargeSendNetBufferListInfo) = 0;
+        }
+    }
+
+    vportGeneve = (POVS_GENEVE_VPORT) GetOvsVportPriv(vport);
+    ASSERT(vportGeneve != NULL);
+
+    /* If we didn't split the packet above, make a copy now */
+    if (*newNbl == NULL) {
+        *newNbl = OvsPartialCopyNBL(switchContext, curNbl, 0, headRoom,
+                                    FALSE /*NBL info*/);
+        if (*newNbl == NULL) {
+            OVS_LOG_ERROR("Unable to copy NBL");
+            return NDIS_STATUS_FAILURE;
+        }
+        NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
+        csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl,
+                                              TcpIpChecksumNetBufferListInfo);
+        status = OvsApplySWChecksumOnNB(layers, *newNbl, &csumInfo);
+
+        if (status != NDIS_STATUS_SUCCESS) {
+            goto ret_error;
+        }
+    }
+
+    curNbl = *newNbl;
+    for (curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); curNb != NULL;
+            curNb = curNb->Next) {
+        status = NdisRetreatNetBufferDataStart(curNb, headRoom, 0, NULL);
+        if (status != NDIS_STATUS_SUCCESS) {
+            goto ret_error;
+        }
+
+        curMdl = NET_BUFFER_CURRENT_MDL(curNb);
+        bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority);
+        if (!bufferStart) {
+            status = NDIS_STATUS_RESOURCES;
+            goto ret_error;
+        }
+
+        bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
+        if (NET_BUFFER_NEXT_NB(curNb)) {
+            OVS_LOG_TRACE("nb length %u next %u", NET_BUFFER_DATA_LENGTH(curNb),
+                          NET_BUFFER_DATA_LENGTH(curNb->Next));
+        }
+
+        /* L2 header */
+        ethHdr = (EthHdr *)bufferStart;
+        ASSERT(((PCHAR)&fwdInfo.dstMacAddr + sizeof fwdInfo.dstMacAddr) ==
+               (PCHAR)&fwdInfo.srcMacAddr);
+        NdisMoveMemory(ethHdr->Destination, fwdInfo.dstMacAddr,
+                       sizeof ethHdr->Destination + sizeof ethHdr->Source);
+        ethHdr->Type = htons(ETH_TYPE_IPV4);
+
+        /* IP header */
+        ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr);
+
+        ipHdr->ihl = sizeof *ipHdr / 4;
+        ipHdr->version = IPPROTO_IPV4;
+        ipHdr->tos = tunKey->tos;
+        ipHdr->tot_len = htons(NET_BUFFER_DATA_LENGTH(curNb) - sizeof *ethHdr);
+        ipHdr->id = (uint16)atomic_add64(&vportGeneve->ipId,
+                                         NET_BUFFER_DATA_LENGTH(curNb));
+        ipHdr->frag_off = (tunKey->flags & OVS_TNL_F_DONT_FRAGMENT) ?
+                          IP_DF_NBO : 0;
+        ipHdr->ttl = tunKey->ttl ? tunKey->ttl : GENEVE_DEFAULT_TTL;
+        ipHdr->protocol = IPPROTO_UDP;
+        ASSERT(tunKey->dst == fwdInfo.dstIpAddr);
+        ASSERT(tunKey->src == fwdInfo.srcIpAddr || tunKey->src == 0);
+        ipHdr->saddr = fwdInfo.srcIpAddr;
+        ipHdr->daddr = fwdInfo.dstIpAddr;
+
+        ipHdr->check = 0;
+        ipHdr->check = IPChecksum((UINT8 *)ipHdr, sizeof *ipHdr, 0);
+
+        /* UDP header */
+        udpHdr = (UDPHdr *)((PCHAR)ipHdr + sizeof *ipHdr);
+        udpHdr->source = htons(tunKey->flow_hash | MAXINT16);
+        udpHdr->dest = htons(vportGeneve->dstPort);
+        udpHdr->len = htons(NET_BUFFER_DATA_LENGTH(curNb) - headRoom +
+                            sizeof *udpHdr + sizeof *geneveHdr + tunKey->tunOptLen);
+        udpHdr->check = 0;
+
+        /* Geneve header */
+        geneveHdr = (GeneveHdr *)((PCHAR)udpHdr + sizeof *udpHdr);
+        geneveHdr->version = GENEVE_VER;
+        geneveHdr->optLen = tunKey->tunOptLen / 4;
+        geneveHdr->oam = !!(tunKey->flags & OVS_TNL_F_OAM);
+        geneveHdr->critical = 0;
+        geneveHdr->reserved1 = 0;
+        geneveHdr->protocol = htons(ETH_P_TEB);
+        geneveHdr->vni = GENEVE_TUNNELID_TO_VNI(tunKey->tunnelId);
+        geneveHdr->reserved2 = 0;
+
+        /* Geneve header options */
+        optHdr = (GeneveOptionHdr *)(geneveHdr + 1);
+        memcpy(optHdr, TunnelKeyGetOptions(tunKey), tunKey->tunOptLen);
+        geneveHdr->critical = OvsTunnelKeyIsCritical(tunKey) ? 1 : 0;
+        for (i = 0; i < tunKey->tunOptLen; i++) {
+            if (optHdr[i].type & GENEVE_CRIT_OPT_TYPE) {
+                geneveHdr->critical = 1;
+            }
+        }
+    }
+    return STATUS_SUCCESS;
+
+ret_error:
+    OvsCompleteNBL(switchContext, *newNbl, TRUE);
+    *newNbl = NULL;
+    return status;
+}
+
+NDIS_STATUS OvsDecapGeneve(POVS_SWITCH_CONTEXT switchContext,
+                           PNET_BUFFER_LIST curNbl,
+                           OvsIPv4TunnelKey *tunKey,
+                           PNET_BUFFER_LIST *newNbl)
+{
+    PNET_BUFFER curNb;
+    PMDL curMdl;
+    EthHdr *ethHdr;
+    IPHdr *ipHdr;
+    UDPHdr *udpHdr;
+    GeneveHdr *geneveHdr;
+    UINT32 tunnelSize;
+    UINT32 packetLength;
+    PUINT8 bufferStart;
+    PVOID optStart;
+    NDIS_STATUS status;
+
+    /* Check the length of the UDP payload */
+    curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
+    tunnelSize = OvsGetGeneveTunHdrMinSize();
+    packetLength = NET_BUFFER_DATA_LENGTH(curNb);
+    if (packetLength <= tunnelSize) {
+        return NDIS_STATUS_INVALID_LENGTH;
+    }
+
+    /*
+     * Create a copy of the NBL so that we have all the headers in one MDL.
+     */
+    *newNbl = OvsPartialCopyNBL(switchContext, curNbl,
+                                tunnelSize, 0,
+                                TRUE /*copy NBL info */);
+
+    if (*newNbl == NULL) {
+        return NDIS_STATUS_RESOURCES;
+    }
+
+    /* XXX: Handle VLAN header. */
+    curNbl = *newNbl;
+    curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
+    curMdl = NET_BUFFER_CURRENT_MDL(curNb);
+    bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority) +
+                  NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
+    if (!bufferStart) {
+        status = NDIS_STATUS_RESOURCES;
+        goto dropNbl;
+    }
+
+    ethHdr = (EthHdr *)bufferStart;
+    /* XXX: Handle IP options. */
+    ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr);
+    tunKey->src = ipHdr->saddr;
+    tunKey->dst = ipHdr->daddr;
+    tunKey->tos = ipHdr->tos;
+    tunKey->ttl = ipHdr->ttl;
+    tunKey->pad = 0;
+    udpHdr = (UDPHdr *)((PCHAR)ipHdr + sizeof *ipHdr);
+
+    /* Validate if NIC has indicated checksum failure. */
+    status = OvsValidateUDPChecksum(curNbl, udpHdr->check == 0);
+    if (status != NDIS_STATUS_SUCCESS) {
+        goto dropNbl;
+    }
+
+    /* Calculate and verify UDP checksum if NIC didn't do it. */
+    if (udpHdr->check != 0) {
+        status = OvsCalculateUDPChecksum(curNbl, curNb, ipHdr, udpHdr, packetLength);
+        if (status != NDIS_STATUS_SUCCESS) {
+            goto dropNbl;
+        }
+    }
+
+    geneveHdr = (GeneveHdr *)((PCHAR)udpHdr + sizeof *udpHdr);
+    if (geneveHdr->protocol != htons(ETH_P_TEB)) {
+        status = STATUS_NDIS_INVALID_PACKET;
+        goto dropNbl;
+    }
+    tunKey->flags = OVS_TNL_F_KEY;
+    if (geneveHdr->oam) {
+        tunKey->flags |= OVS_TNL_F_OAM;
+    }
+    tunKey->tunnelId = GENEVE_VNI_TO_TUNNELID(geneveHdr->vni);
+    tunKey->tunOptLen = (uint8)geneveHdr->optLen * 4;
+    if (tunKey->tunOptLen > TUN_OPT_MAX_LEN ||
+        packetLength < tunnelSize + tunKey->tunOptLen) {
+        status = NDIS_STATUS_INVALID_LENGTH;
+        goto dropNbl;
+    }
+    /* Clear out the receive flag for the inner packet. */
+    NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo) = 0;
+
+    NdisAdvanceNetBufferDataStart(curNb, tunnelSize, FALSE, NULL);
+    if (tunKey->tunOptLen > 0) {
+        optStart = NdisGetDataBuffer(curNb, tunKey->tunOptLen,
+                                     TunnelKeyGetOptions(tunKey), 1 /*no align*/, 0);
+
+        /* If data is contiguous in the buffer, NdisGetDataBuffer will not copy
+           data to the storage. Manual copy is needed. */
+        if (optStart != TunnelKeyGetOptions(tunKey)) {
+            memcpy(TunnelKeyGetOptions(tunKey), optStart, tunKey->tunOptLen);
+        }
+        NdisAdvanceNetBufferDataStart(curNb, tunKey->tunOptLen, FALSE, NULL);
+    }
+    return NDIS_STATUS_SUCCESS;
+
+dropNbl:
+    OvsCompleteNBL(switchContext, *newNbl, TRUE);
+    *newNbl = NULL;
+    return status;
+}
diff --git a/datapath-windows/ovsext/Geneve.h b/datapath-windows/ovsext/Geneve.h
new file mode 100644
index 0000000..265e7b5
--- /dev/null
+++ b/datapath-windows/ovsext/Geneve.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 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 __GENEVE_H_
+#define __GENEVE_H_ 1
+
+#include "NetProto.h"
+typedef struct _OVS_GENEVE_VPORT {
+    UINT16 dstPort;
+    UINT64 filterID;
+    UINT64 ipId;
+    /*
+     * To be filled
+     */
+} OVS_GENEVE_VPORT, *POVS_GENEVE_VPORT;
+
+/* Geneve Header:
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |Ver|  Opt Len  |O|C|    Rsvd.  |          Protocol Type        |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |        Virtual Network Identifier (VNI)       |    Reserved   |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                    Variable Length Options                    |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Option Header:
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |          Option Class         |      Type     |R|R|R| Length  |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                      Variable Option Data                     |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+typedef struct GeneveHdr {
+    /* Version. */
+    UINT32   version:2;
+    /* Length of options fields in int32 excluding the common header */
+    UINT32   optLen:6;
+    /* This packet contains a control message instead of a data payload */
+    UINT32   oam:1;
+    /* Critical options present */
+    UINT32   critical:1;
+    /* Reserved. */
+    UINT32   reserved1:6;
+    /* Protocol Type. */
+    UINT32   protocol:16;
+    /* VNI */
+    UINT32   vni:24;
+    /* Reserved. */
+    UINT32   reserved2:8;
+} GeneveHdr;
+
+typedef struct GeneveOptionHdr {
+    /* Namespace for the 'type' field. */
+    UINT32   optionClass:16;
+    /* Format of data contained in the option. */
+    UINT32   type:8;
+    /* Reserved. */
+    UINT32   reserved:3;
+    /* Length of option in int32 excluding the option header. */
+    UINT32   length:5;
+} GeneveOptionHdr;
+
+#define GENEVE_CRIT_OPT_TYPE (1 << 7)
+
+NTSTATUS OvsInitGeneveTunnel(POVS_VPORT_ENTRY vport,
+                             UINT16 udpDestPort);
+
+VOID OvsCleanupGeneveTunnel(POVS_VPORT_ENTRY vport);
+
+
+NDIS_STATUS OvsEncapGeneve(POVS_VPORT_ENTRY vport,
+                           PNET_BUFFER_LIST curNbl,
+                           OvsIPv4TunnelKey *tunKey,
+                           POVS_SWITCH_CONTEXT switchContext,
+                           POVS_PACKET_HDR_INFO layers,
+                           PNET_BUFFER_LIST *newNbl);
+
+NDIS_STATUS OvsDecapGeneve(POVS_SWITCH_CONTEXT switchContext,
+                           PNET_BUFFER_LIST curNbl,
+                           OvsIPv4TunnelKey *tunKey,
+                           PNET_BUFFER_LIST *newNbl);
+
+static __inline UINT32
+OvsGetGeneveTunHdrMinSize(VOID)
+{
+    /* XXX: Can L2 include VLAN at all? */
+    return sizeof (EthHdr) + sizeof (IPHdr) + sizeof (UDPHdr) +
+           sizeof (GeneveHdr);
+}
+
+static __inline UINT32
+OvsGetGeneveTunHdrMaxSize(VOID)
+{
+    /* XXX: Can L2 include VLAN at all? */
+    return OvsGetGeneveTunHdrMinSize() + TUN_OPT_MAX_LEN;
+}
+
+#define GENEVE_UDP_PORT 6081
+#define GENEVE_UDP_PORT_NBO 0xC117
+#define GENEVE_VER 0
+#define GENEVE_DEFAULT_TTL 64
+#define GENEVE_ID_IS_VALID(geneveID) (0 < (geneveID) && (vxlanID) <= 0xffffff)
+#define GENEVE_TUNNELID_TO_VNI(_tID)   (UINT32)(((UINT64)(_tID)) >> 40)
+#define GENEVE_VNI_TO_TUNNELID(_vni) (((UINT64)(_vni)) << 40)
+#define ETH_P_TEB       0x6558          /* Trans Ether Bridging */
+
+#endif /* __GENEVE_H_ */
+
diff --git a/datapath-windows/ovsext/Gre.c b/datapath-windows/ovsext/Gre.c
index cb41593..de4e748 100644
--- a/datapath-windows/ovsext/Gre.c
+++ b/datapath-windows/ovsext/Gre.c
@@ -299,7 +299,7 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext,
     EthHdr *ethHdr;
     IPHdr *ipHdr;
     GREHdr *greHdr;
-    UINT32 tunnelSize = 0, packetLength = 0;
+    UINT32 tunnelSize, packetLength, copySize;
     UINT32 headRoom = 0;
     PUINT8 bufferStart;
     NDIS_STATUS status;
@@ -307,7 +307,9 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext,
     curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
     packetLength = NET_BUFFER_DATA_LENGTH(curNb);
     tunnelSize = GreTunHdrSize(tunKey->flags);
-    if (packetLength <= tunnelSize) {
+    copySize = tunnelSize + OVS_DEFAULT_COPY_SIZE;
+
+    if (packetLength < copySize) {
         return NDIS_STATUS_INVALID_LENGTH;
     }
 
@@ -315,7 +317,7 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext,
      * Create a copy of the NBL so that we have all the headers in one MDL.
      */
     *newNbl = OvsPartialCopyNBL(switchContext, curNbl,
-                                tunnelSize + OVS_DEFAULT_COPY_SIZE, 0,
+                                copySize, 0,
                                 TRUE /*copy NBL info */);
 
     if (*newNbl == NULL) {
diff --git a/datapath-windows/ovsext/Offload.c b/datapath-windows/ovsext/Offload.c
index 1e43a9e..921c732 100644
--- a/datapath-windows/ovsext/Offload.c
+++ b/datapath-windows/ovsext/Offload.c
@@ -597,6 +597,51 @@ OvsValidateUDPChecksum(PNET_BUFFER_LIST curNbl, BOOLEAN udpCsumZero)
 
 
 /*
+ *----------------------------------------------------------------------------
+ * OvsCalculateUDPChecksum
+ *     Calculate UDP checksum
+ *----------------------------------------------------------------------------
+ */
+NDIS_STATUS
+OvsCalculateUDPChecksum(PNET_BUFFER_LIST curNbl,
+                        PNET_BUFFER curNb,
+                        IPHdr *ipHdr,
+                        UDPHdr *udpHdr,
+                        UINT32 packetLength)
+{
+    NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
+    UINT16 checkSum;
+
+    csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo);
+
+    /* Next check if UDP checksum has been calculated. */
+    if (!csumInfo.Receive.UdpChecksumSucceeded) {
+        UINT32 l4Payload;
+
+        checkSum = udpHdr->check;
+
+        l4Payload = packetLength - sizeof(EthHdr) - ipHdr->ihl * 4;
+        udpHdr->check = 0;
+        udpHdr->check =
+            IPPseudoChecksum((UINT32 *)&ipHdr->saddr,
+                             (UINT32 *)&ipHdr->daddr,
+                             IPPROTO_UDP, (UINT16)l4Payload);
+        udpHdr->check = CalculateChecksumNB(curNb, (UINT16)l4Payload,
+                                            sizeof(EthHdr) + ipHdr->ihl * 4);
+        if (checkSum != udpHdr->check) {
+            OVS_LOG_TRACE("UDP checksum incorrect.");
+            return NDIS_STATUS_INVALID_PACKET;
+        }
+    }
+
+    csumInfo.Receive.UdpChecksumSucceeded = 1;
+    NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo) = csumInfo.Value;
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+
+/*
  * OvsApplySWChecksumOnNB --
  *
  * This function calculates and sets the required sofware offloads given by
diff --git a/datapath-windows/ovsext/Offload.h b/datapath-windows/ovsext/Offload.h
index b5cae2f..d3731b1 100644
--- a/datapath-windows/ovsext/Offload.h
+++ b/datapath-windows/ovsext/Offload.h
@@ -35,7 +35,11 @@ NDIS_STATUS OvsValidateIPChecksum(PNET_BUFFER_LIST curNbl,
                                   POVS_PACKET_HDR_INFO hdrInfo);
 NDIS_STATUS OvsValidateUDPChecksum(PNET_BUFFER_LIST curNbl,
                                    BOOLEAN udpCsumZero);
-
+NDIS_STATUS OvsCalculateUDPChecksum(PNET_BUFFER_LIST curNbl,
+                                    PNET_BUFFER curNb,
+                                    IPHdr *ipHdr,
+                                    UDPHdr *udpHdr,
+                                    UINT32 packetLength);
 
 ULONG OVSGetTcpMSS(PNET_BUFFER_LIST nbl);
 
diff --git a/datapath-windows/ovsext/Stt.c b/datapath-windows/ovsext/Stt.c
index dd7bf92..f08ca27 100644
--- a/datapath-windows/ovsext/Stt.c
+++ b/datapath-windows/ovsext/Stt.c
@@ -761,7 +761,7 @@ OvsDecapStt(POVS_SWITCH_CONTEXT switchContext,
     advanceCnt = hdrLen;
 
     ipHdr = NdisGetDataBuffer(curNb, sizeof *ipHdr, (PVOID) &ipBuf,
-                                                    1 /*no align*/, 0);
+                              1 /*no align*/, 0);
     ASSERT(ipHdr);
 
     TCPHdr *tcp = (TCPHdr *)((PCHAR)ipHdr + ipHdr->ihl * 4);
diff --git a/datapath-windows/ovsext/Tunnel.c b/datapath-windows/ovsext/Tunnel.c
index 97d2020..4f3ae3e 100644
--- a/datapath-windows/ovsext/Tunnel.c
+++ b/datapath-windows/ovsext/Tunnel.c
@@ -286,8 +286,7 @@ OvsInjectPacketThroughActions(PNET_BUFFER_LIST pNbl,
         SendFlags |= NDIS_SEND_FLAGS_DISPATCH_LEVEL;
 
         vport = OvsFindTunnelVportByDstPort(gOvsSwitchContext,
-                                            htons(tunnelKey.dst_port),
-                                            OVS_VPORT_TYPE_VXLAN);
+                                            htons(tunnelKey.dst_port));
 
         if (vport == NULL){
             status = STATUS_UNSUCCESSFUL;
diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h
index 4bcde3b..15793c0 100644
--- a/datapath-windows/ovsext/Util.h
+++ b/datapath-windows/ovsext/Util.h
@@ -38,6 +38,7 @@
 #define OVS_TUNFLT_POOL_TAG             'WSVO'
 #define OVS_RECIRC_POOL_TAG             'CSVO'
 #define OVS_CT_POOL_TAG                 'CTVO'
+#define OVS_GENEVE_POOL_TAG             'GNVO'
 
 VOID *OvsAllocateMemory(size_t size);
 VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag);
diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c
index 4299169..7e5cfc1 100644
--- a/datapath-windows/ovsext/Vport.c
+++ b/datapath-windows/ovsext/Vport.c
@@ -692,8 +692,7 @@ OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
 
 POVS_VPORT_ENTRY
 OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext,
-                            UINT16 dstPort,
-                            OVS_VPORT_TYPE ovsPortType)
+                            UINT16 dstPort)
 {
     POVS_VPORT_ENTRY vport;
     PLIST_ENTRY head, link;
@@ -702,8 +701,7 @@ OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext,
     head = &(switchContext->tunnelVportsArray[hash & OVS_VPORT_MASK]);
     LIST_FORALL(head, link) {
         vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, tunnelVportLink);
-        if (GetPortFromPriv(vport) == dstPort &&
-            vport->ovsType == ovsPortType) {
+        if (GetPortFromPriv(vport) == dstPort) {
             return vport;
         }
     }
@@ -1042,6 +1040,9 @@ OvsInitTunnelVport(PVOID userContext,
     case OVS_VPORT_TYPE_STT:
         status = OvsInitSttTunnel(vport, dstPort);
         break;
+    case OVS_VPORT_TYPE_GENEVE:
+        status = OvsInitGeneveTunnel(vport, dstPort);
+        break;
     default:
         ASSERT(0);
     }
@@ -1185,6 +1186,7 @@ InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext,
     case OVS_VPORT_TYPE_GRE:
     case OVS_VPORT_TYPE_VXLAN:
     case OVS_VPORT_TYPE_STT:
+    case OVS_VPORT_TYPE_GENEVE:
     {
         UINT16 dstPort = GetPortFromPriv(vport);
         hash = OvsJhashBytes(&dstPort,
@@ -1268,6 +1270,9 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext,
             return status;
         }
     }
+    case OVS_VPORT_TYPE_GENEVE:
+        OvsCleanupGeneveTunnel(vport);
+        break;
     case OVS_VPORT_TYPE_STT:
         OvsCleanupSttTunnel(vport);
         break;
@@ -1329,9 +1334,7 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext,
         InitializeListHead(&vport->ovsNameLink);
         RemoveEntryList(&vport->portNoLink);
         InitializeListHead(&vport->portNoLink);
-        if (OVS_VPORT_TYPE_VXLAN == vport->ovsType ||
-            OVS_VPORT_TYPE_STT == vport->ovsType   ||
-            OVS_VPORT_TYPE_GRE == vport->ovsType) {
+        if (OvsIsTunnelVportType(vport->ovsType)) {
             RemoveEntryList(&vport->tunnelVportLink);
             InitializeListHead(&vport->tunnelVportLink);
         }
@@ -2227,6 +2230,9 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
             case OVS_VPORT_TYPE_VXLAN:
                 transportPortDest = VXLAN_UDP_PORT;
                 break;
+            case OVS_VPORT_TYPE_GENEVE:
+                transportPortDest = GENEVE_UDP_PORT;
+                break;
             case OVS_VPORT_TYPE_STT:
                 transportPortDest = STT_TCP_PORT;
                 break;
@@ -2336,6 +2342,9 @@ Cleanup:
                     case OVS_VPORT_TYPE_STT:
                         OvsCleanupSttTunnel(vport);
                         break;
+                    case OVS_VPORT_TYPE_GENEVE:
+                        OvsCleanupGeneveTunnel(vport);
+                        break;
                     default:
                         ASSERT(!"Invalid tunnel port type");
                     }
diff --git a/datapath-windows/ovsext/Vport.h b/datapath-windows/ovsext/Vport.h
index 373896d..8f0b8a8 100644
--- a/datapath-windows/ovsext/Vport.h
+++ b/datapath-windows/ovsext/Vport.h
@@ -21,6 +21,7 @@
 #include "Stt.h"
 #include "Switch.h"
 #include "VxLan.h"
+#include "Geneve.h"
 
 #define OVS_MAX_DPPORTS             MAXUINT16
 #define OVS_DPPORT_NUMBER_INVALID   OVS_MAX_DPPORTS
@@ -146,8 +147,7 @@ POVS_VPORT_ENTRY OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchConte
                                                  NDIS_SWITCH_PORT_ID portId,
                                                  NDIS_SWITCH_NIC_INDEX index);
 POVS_VPORT_ENTRY OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext,
-                                             UINT16 dstPort,
-                                             OVS_VPORT_TYPE ovsVportType);
+                                             UINT16 dstPort);
 POVS_VPORT_ENTRY OvsFindTunnelVportByPortType(POVS_SWITCH_CONTEXT switchContext,
                                               OVS_VPORT_TYPE ovsPortType);
 
@@ -181,7 +181,8 @@ OvsIsTunnelVportType(OVS_VPORT_TYPE ovsType)
 {
     return ovsType == OVS_VPORT_TYPE_VXLAN ||
            ovsType == OVS_VPORT_TYPE_STT ||
-           ovsType == OVS_VPORT_TYPE_GRE;
+           ovsType == OVS_VPORT_TYPE_GRE ||
+           ovsType == OVS_VPORT_TYPE_GENEVE;
 }
 
 
@@ -267,6 +268,9 @@ GetPortFromPriv(POVS_VPORT_ENTRY vport)
     case OVS_VPORT_TYPE_VXLAN:
         dstPort = ((POVS_VXLAN_VPORT)vportPriv)->dstPort;
         break;
+    case OVS_VPORT_TYPE_GENEVE:
+        dstPort = ((POVS_GENEVE_VPORT)vportPriv)->dstPort;
+        break;
     default:
         ASSERT(! "Port is not a tunnel port");
     }
diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c
index 20214cb..d0529cd 100644
--- a/datapath-windows/ovsext/Vxlan.c
+++ b/datapath-windows/ovsext/Vxlan.c
@@ -353,48 +353,6 @@ OvsEncapVxlan(POVS_VPORT_ENTRY vport,
                            switchContext, newNbl);
 }
 
-/*
- *----------------------------------------------------------------------------
- * OvsCalculateUDPChecksum
- *     Calculate UDP checksum
- *----------------------------------------------------------------------------
- */
-static __inline NDIS_STATUS
-OvsCalculateUDPChecksum(PNET_BUFFER_LIST curNbl,
-                        PNET_BUFFER curNb,
-                        IPHdr *ipHdr,
-                        UDPHdr *udpHdr,
-                        UINT32 packetLength)
-{
-    NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
-    UINT16 checkSum;
-
-    csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo);
-
-    /* Next check if UDP checksum has been calculated. */
-    if (!csumInfo.Receive.UdpChecksumSucceeded) {
-        UINT32 l4Payload;
-
-        checkSum = udpHdr->check;
-
-        l4Payload = packetLength - sizeof(EthHdr) - ipHdr->ihl * 4;
-        udpHdr->check = 0;
-        udpHdr->check =
-            IPPseudoChecksum((UINT32 *)&ipHdr->saddr,
-                             (UINT32 *)&ipHdr->daddr,
-                             IPPROTO_UDP, (UINT16)l4Payload);
-        udpHdr->check = CalculateChecksumNB(curNb, (UINT16)l4Payload,
-            sizeof(EthHdr) + ipHdr->ihl * 4);
-        if (checkSum != udpHdr->check) {
-            OVS_LOG_TRACE("UDP checksum incorrect.");
-            return NDIS_STATUS_INVALID_PACKET;
-        }
-    }
-
-    csumInfo.Receive.UdpChecksumSucceeded = 1;
-    NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo) = csumInfo.Value;
-    return NDIS_STATUS_SUCCESS;
-}
 
 /*
  *----------------------------------------------------------------------------
@@ -414,7 +372,7 @@ OvsDecapVxlan(POVS_SWITCH_CONTEXT switchContext,
     IPHdr *ipHdr;
     UDPHdr *udpHdr;
     VXLANHdr *vxlanHdr;
-    UINT32 tunnelSize = 0, packetLength = 0;
+    UINT32 tunnelSize, packetLength, copySize;
     PUINT8 bufferStart;
     NDIS_STATUS status;
 
@@ -422,7 +380,8 @@ OvsDecapVxlan(POVS_SWITCH_CONTEXT switchContext,
     curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
     packetLength = NET_BUFFER_DATA_LENGTH(curNb);
     tunnelSize = OvsGetVxlanTunHdrSize();
-    if (packetLength <= tunnelSize) {
+    copySize = tunnelSize + OVS_DEFAULT_COPY_SIZE;
+    if (packetLength < copySize) {
         return NDIS_STATUS_INVALID_LENGTH;
     }
 
@@ -430,7 +389,7 @@ OvsDecapVxlan(POVS_SWITCH_CONTEXT switchContext,
      * Create a copy of the NBL so that we have all the headers in one MDL.
      */
     *newNbl = OvsPartialCopyNBL(switchContext, curNbl,
-                                tunnelSize + OVS_DEFAULT_COPY_SIZE, 0,
+                                copySize, 0,
                                 TRUE /*copy NBL info */);
 
     if (*newNbl == NULL) {
diff --git a/datapath-windows/ovsext/ovsext.vcxproj b/datapath-windows/ovsext/ovsext.vcxproj
index 0356ddf..02fa60c 100644
--- a/datapath-windows/ovsext/ovsext.vcxproj
+++ b/datapath-windows/ovsext/ovsext.vcxproj
@@ -81,6 +81,7 @@
     <ClInclude Include="Ethernet.h" />
     <ClInclude Include="Event.h" />
     <ClInclude Include="Flow.h" />
+    <ClInclude Include="Geneve.h" />
     <ClInclude Include="Gre.h" />
     <ClInclude Include="IpHelper.h" />
     <ClInclude Include="Jhash.h" />
@@ -182,6 +183,7 @@
     <ClCompile Include="Driver.c" />
     <ClCompile Include="Event.c" />
     <ClCompile Include="Flow.c" />
+    <ClCompile Include="Geneve.c" />
     <ClCompile Include="Gre.c" />
     <ClCompile Include="IpHelper.c" />
     <ClCompile Include="Jhash.c" />
diff --git a/manpages.mk b/manpages.mk
index d4d4f21..4629522 100644
--- a/manpages.mk
+++ b/manpages.mk
@@ -100,10 +100,6 @@ lib/common.man:
 lib/vlog-syn.man:
 lib/vlog.man:
 
-utilities/bugtool/ovs-bugtool.8: \
-	utilities/bugtool/ovs-bugtool.8.in
-utilities/bugtool/ovs-bugtool.8.in:
-
 utilities/ovs-appctl.8: \
 	utilities/ovs-appctl.8.in \
 	lib/common.man
-- 
2.8.0.windows.1




More information about the dev mailing list