I wasn't sure how to interpret this.  Does this mean that you will
review this patch later, or does it mean something else?

Thanks,

Ben.

On Wed, Jun 01, 2016 at 04:48:58AM +0000, Nithin Raju wrote:
> 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-boun...@openvswitch.org> on behalf of Yin Lin
> <li...@vmware.com>
> Date: Tuesday, May 24, 2016 at 4:28 PM
> To: "dev@openvswitch.org" <dev@openvswitch.org>
> Subject: [ovs-dev] [PATCH 2/2] [PATCH v5] datapath-windows: Add
> Geneve        support
> 
> >Signed-off-by: Yin Lin <li...@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@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= 
> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to