[ovs-dev] [PATCH 2/2] [PATCH v5] datapath-windows: Add Geneve support

Nithin Raju nithin at vmware.com
Wed Jun 1 04:48:58 UTC 2016


Yin,
I went ahead and sent out a patch for the updates w.r.t
OvsFindTunnelVportByDstPort(). Pls have a look:
https://patchwork.ozlabs.org/patch/628483/

I¹ll send out the comments for the remainder of the patch.

Thanks,
-- Nithin


-----Original Message-----
From: dev <dev-bounces at openvswitch.org> on behalf of Yin Lin
<linyi at vmware.com>
Date: Tuesday, May 24, 2016 at 4:28 PM
To: "dev at openvswitch.org" <dev at openvswitch.org>
Subject: [ovs-dev] [PATCH 2/2] [PATCH v5] datapath-windows: Add
Geneve	support

>Signed-off-by: Yin Lin <linyi at vmware.com>
>---
>Fixed checksum flag issue brought up by Jesse and automake.mk issue by
>Nithin.
>---
> datapath-windows/automake.mk           |   2 +
> datapath-windows/ovsext/Actions.c      |  82 +++-----
> datapath-windows/ovsext/Debug.h        |   1 +
> datapath-windows/ovsext/DpInternal.h   |  29 ++-
> datapath-windows/ovsext/Flow.c         | 172 ++++++++++++++--
> datapath-windows/ovsext/Flow.h         |   7 +
> datapath-windows/ovsext/Geneve.c       | 356
>+++++++++++++++++++++++++++++++++
> datapath-windows/ovsext/Geneve.h       | 122 +++++++++++
> datapath-windows/ovsext/Gre.c          |   7 +-
> 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/ovsext.vcxproj |   2 +
> 15 files changed, 727 insertions(+), 92 deletions(-)
> create mode 100644 datapath-windows/ovsext/Geneve.c
> create mode 100644 datapath-windows/ovsext/Geneve.h
>
>diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk
>index c9af806..53fb5c5 100644
>--- a/datapath-windows/automake.mk
>+++ b/datapath-windows/automake.mk
>@@ -68,6 +68,8 @@ EXTRA_DIST += \
> 	datapath-windows/ovsext/Vport.h \
> 	datapath-windows/ovsext/Vxlan.c \
> 	datapath-windows/ovsext/Vxlan.h \
>+	datapath-windows/ovsext/Geneve.c \
>+	datapath-windows/ovsext/Geneve.h \
> 	datapath-windows/ovsext/ovsext.inf \
> 	datapath-windows/ovsext/ovsext.rc \
> 	datapath-windows/ovsext/ovsext.vcxproj \
>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..b0a8f44 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,116 @@ _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;
>+        }
>+        option = (GeneveOptionHdr *)((UINT8 *)option + len);
>+        optLen -= len;
>+    }
>+    return STATUS_SUCCESS;
>+}
>+
>+
>+/*
>+ 
>*-------------------------------------------------------------------------
>---
>+ *  OvsTunnelAttrToIPv4TunnelKey --
>+ *    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 +1762,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 +1800,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 +1975,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 +2020,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 +2363,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 +2418,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..d59945d
>--- /dev/null
>+++ b/datapath-windows/ovsext/Geneve.c
>@@ -0,0 +1,356 @@
>+/*
>+ * 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=62Xt8BBpUG4AqJ0X8YjOtMfZRYm0C
>1SOzdOxdvcn9ok&s=pd1fscKFk3BO3GSaqAVHqwpPhjWfuk9h4zFaTwkcPso&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;
>+    NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
>+
>+    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;
>+
>+        /* 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);
>+        if (tunKey->flags & OVS_TNL_F_CSUM) {
>+            UINT16 udpChksumLen = (UINT16) NET_BUFFER_DATA_LENGTH(curNb)
>-
>+                                   sizeof *ipHdr - sizeof *ethHdr;
>+            udpHdr->check = IPPseudoChecksum(&ipHdr->saddr,
>&ipHdr->daddr,
>+                                             IPPROTO_UDP, udpChksumLen);
>+        } else {
>+            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);
>+
>+        csumInfo.Value = 0;
>+        csumInfo.Transmit.IpHeaderChecksum = 1;
>+        csumInfo.Transmit.IsIPv4 = 1;
>+        if (tunKey->flags & OVS_TNL_F_CSUM) {
>+            csumInfo.Transmit.UdpChecksum = 1;
>+        }
>+        NET_BUFFER_LIST_INFO(curNbl,
>+                             TcpIpChecksumNetBufferListInfo) =
>csumInfo.Value;
>+    }
>+    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);
>+        tunKey->flags |= OVS_TNL_F_CSUM;
>+        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..74325a5
>--- /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=62Xt8BBpUG4AqJ0X8YjOtMfZRYm0C
>1SOzdOxdvcn9ok&s=pd1fscKFk3BO3GSaqAVHqwpPhjWfuk9h4zFaTwkcPso&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 {
>+    /* Length of options fields in int32 excluding the common header */
>+    UINT32   optLen : 6;
>+    /* Version. */
>+    UINT32   version:2;
>+    /* Reserved. */
>+    UINT32   reserved1 : 6;
>+    /* Critical options present */
>+    UINT32   critical : 1;
>+    /* This packet contains a control message instead of a data payload 
>*/
>+    UINT32   oam:1;
>+    /* 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..fbcbdb4 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;
>     UINT32 headRoom = 0;
>     PUINT8 bufferStart;
>     NDIS_STATUS status;
>@@ -307,7 +307,8 @@ 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) {
>+
>+    if (packetLength < tunnelSize) {
>         return NDIS_STATUS_INVALID_LENGTH;
>     }
> 
>@@ -315,7 +316,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,
>+                                tunnelSize, 0,
>                                 TRUE /*copy NBL info */);
> 
>     if (*newNbl == NULL) {
>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/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=62Xt8BBpUG4AqJ0X8YjOtMfZRYm0C1
>SOzdOxdvcn9ok&s=tl9Z_geYFFKX3JcT35a7Aj5CdmcG9m0Xjcovds_NlNE&e= 




More information about the dev mailing list