[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