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

Nithin Raju nithin at vmware.com
Wed May 18 06:02:07 UTC 2016


Yin,
Thanks for sending the patch for review.

A few things before I take a detailed look:
1. Add a version number to the patch, eg. "[PATCH v2] Add Geneve support Š
³ with each iteration. Also, it would be beneficial if you can annotate
what changed in v2 compared to previous versions.
2. I see that you have changes in multiple files, some of them may be
fixes that are unrelated to Geneve. Can you isolate them into smaller
patches? It makes it easier to review, IMO. This is my personal opinion
though. Some examples of smaller patches are the changes in Offload.c or
changes to FindVport function etc. As you¹ll soon realize, it would be
harder to keep track of all the review comments for big patches esp. if
not all of them are for a particular purpose.
3. If there¹s anything missing w.r.t to Geneve support that you already
know of, please mention it in the commit message.

Other than that, welcome to the club!

I¹ll provide more technical comments.

-- Nithin


-----Original Message-----
From: dev <dev-bounces at openvswitch.org> on behalf of Yin Lin
<linyi at vmware.com>
Date: Tuesday, May 17, 2016 at 8:27 PM
To: "dev at openvswitch.org" <dev at openvswitch.org>
Cc: Yin Lin <linyi at vmware.com>
Subject: [ovs-dev] [PATCH] Add Geneve support on Windows datapath.

>---
> datapath-windows/ovsext/Actions.c      |  82 +++-----
> datapath-windows/ovsext/Debug.h        |   1 +
> datapath-windows/ovsext/DpInternal.h   |  29 ++-
> datapath-windows/ovsext/Flow.c         | 171 +++++++++++++++--
> datapath-windows/ovsext/Flow.h         |   7 +
> datapath-windows/ovsext/Geneve.c       | 342
>+++++++++++++++++++++++++++++++++
> 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 +
> 17 files changed, 765 insertions(+), 138 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..ccdca64 100644
>--- a/datapath-windows/ovsext/Flow.c
>+++ b/datapath-windows/ovsext/Flow.c
>@@ -21,6 +21,7 @@
> #include "Flow.h"
> #include "PacketParser.h"
> #include "Datapath.h"
>+#include "Geneve.h"
> 
> #ifdef OVS_DBG_MOD
> #undef OVS_DBG_MOD
>@@ -88,7 +89,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 +1030,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 +1643,115 @@ _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);
>+    GeneveOptionHdr *option;
>+    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;
>+    option = (GeneveOptionHdr *)TunnelKeyGetOptions(tunKey);
>+    memcpy(option, NlAttrData(attr), optLen);
>+    while(optLen > 0) {
>+        UINT32 len;
>+        if (optLen < sizeof(*option)) {
>+            return STATUS_INFO_LENGTH_MISMATCH;
>+        }
>+        len = sizeof(*option) + option->length * 4;
>+        if (len > optLen) {
>+            return STATUS_INFO_LENGTH_MISMATCH;
>+        }
>+        if (option->type & GENEVE_CRIT_OPT_TYPE) {
>+            tunKey->flags |= OVS_TNL_F_CRT_OPT;
>+        }
>+        optLen -= len;
>+    }
>+    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 +1761,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 +1799,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 +1974,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 +2019,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 +2362,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 +2417,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..3722b5d 100644
>--- a/datapath-windows/ovsext/Flow.h
>+++ b/datapath-windows/ovsext/Flow.h
>@@ -83,10 +83,17 @@ 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_CRT_OPT               (1 << 4)
>+#define OVS_TNL_F_GENEVE_OPT            (1 << 5)
>+#define OVS_TNL_F_VXLAN_OPT             (1 << 6)
>+
>+#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..ce2148f
>--- /dev/null
>+++ b/datapath-windows/ovsext/Geneve.c
>@@ -0,0 +1,342 @@
>+/*
>+ * 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:
>+ *
>+ *     
>https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_license
>s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=p
>NHQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=_ycXPRhVOsNFnWKejXF8L8ACscpwd
>ByhLrs3HZvOl7Q&s=K9MbgxtDA6OgjqyVIXpJak4H-a5TbH0rNcM8_TG9Oks&e=
>+ *
>+ * 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
>+
>+
>+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;
>+
>+    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 = !!(tunKey->flags & OVS_TNL_F_CRT_OPT);
>+        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);
>+    }
>+    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:
>+ *
>+ *     
>https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_license
>s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=p
>NHQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=_ycXPRhVOsNFnWKejXF8L8ACscpwd
>ByhLrs3HZvOl7Q&s=K9MbgxtDA6OgjqyVIXpJak4H-a5TbH0rNcM8_TG9Oks&e= 
>+ *
>+ * 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" />
>-- 
>2.8.0.windows.1
>
>_______________________________________________
>dev mailing list
>dev at openvswitch.org
>https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailma
>n_listinfo_dev&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=pN
>HQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=_ycXPRhVOsNFnWKejXF8L8ACscpwdB
>yhLrs3HZvOl7Q&s=Umd0FrdWcgAyiggcpPW-2EdUmqfIs4BNPwqVDeAFHec&e= 




More information about the dev mailing list