summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--datapath-windows/automake.mk2
-rw-r--r--datapath-windows/ovsext/Actions.c72
-rw-r--r--datapath-windows/ovsext/Debug.h1
-rw-r--r--datapath-windows/ovsext/DpInternal.h29
-rw-r--r--datapath-windows/ovsext/Flow.c179
-rw-r--r--datapath-windows/ovsext/Flow.h7
-rw-r--r--datapath-windows/ovsext/Geneve.c356
-rw-r--r--datapath-windows/ovsext/Geneve.h121
-rw-r--r--datapath-windows/ovsext/Util.h1
-rw-r--r--datapath-windows/ovsext/Vport.c20
-rw-r--r--datapath-windows/ovsext/ovsext.vcxproj2
11 files changed, 715 insertions, 75 deletions
diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk
index 668cf2c14..604cebd6d 100644
--- a/datapath-windows/automake.mk
+++ b/datapath-windows/automake.mk
@@ -69,6 +69,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 7ac6bb711..722a2a878 100644
--- a/datapath-windows/ovsext/Actions.c
+++ b/datapath-windows/ovsext/Actions.c
@@ -33,6 +33,7 @@
#include "User.h"
#include "Vport.h"
#include "Vxlan.h"
+#include "Geneve.h"
#ifdef OVS_DBG_MOD
#undef OVS_DBG_MOD
@@ -48,6 +49,8 @@ typedef struct _OVS_ACTION_STATS {
UINT64 txVxlan;
UINT64 rxStt;
UINT64 txStt;
+ UINT64 rxGeneve;
+ UINT64 txGeneve;
UINT64 flowMiss;
UINT64 flowUserspace;
UINT64 txTcp;
@@ -237,6 +240,9 @@ OvsDetectTunnelRxPkt(OvsForwardingContext *ovsFwdCtx,
case OVS_VPORT_TYPE_VXLAN:
ovsActionStats.rxVxlan++;
break;
+ case OVS_VPORT_TYPE_GENEVE:
+ ovsActionStats.rxGeneve++;
+ break;
case OVS_VPORT_TYPE_GRE:
ovsActionStats.rxGre++;
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 e5ed963c5..935f8584a 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 07bc1804b..42b5ec942 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(const 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 595518f39..bc0bb37fb 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
@@ -85,7 +86,7 @@ static NTSTATUS OvsDoDumpFlows(OvsFlowDumpInput *dumpInput,
UINT32 *replyLen);
static NTSTATUS OvsProbeSupportedFeature(POVS_MESSAGE msgIn,
PNL_ATTR keyAttr);
-
+static UINT16 OvsGetFlowL2Offset(const OvsIPv4TunnelKey *tunKey);
#define OVS_FLOW_TABLE_SIZE 2048
#define OVS_FLOW_TABLE_MASK (OVS_FLOW_TABLE_SIZE -1)
@@ -1029,6 +1030,14 @@ 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:
@@ -1638,6 +1647,120 @@ _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;
+ BOOLEAN isCritical = FALSE;
+ 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 *)NlAttrData(attr);
+ 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) {
+ isCritical = TRUE;
+ }
+ option = (GeneveOptionHdr *)((UINT8 *)option + len);
+ optLen -= len;
+ }
+ memcpy(TunnelKeyGetOptions(tunKey), option, optLen);
+ if (isCritical) {
+ tunKey->flags |= OVS_TNL_F_CRT_OPT;
+ }
+ 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.
*----------------------------------------------------------------------------
@@ -1647,8 +1770,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]);
@@ -1683,13 +1808,21 @@ MapTunAttrToFlowPut(PNL_ATTR *keyAttrs,
NlAttrGetU8(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]) {
+ NTSTATUS status = OvsTunnelAttrToGeneveOptions(
+ tunAttrs[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS],
+ &destKey->tunKey);
+ if (SUCCEEDED(status)) {
+ 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);
}
}
@@ -1853,6 +1986,19 @@ OvsGetFlowMetadata(OvsFlowKey *key,
return status;
}
+UINT16
+OvsGetFlowL2Offset(const 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;
+ }
+}
/*
*----------------------------------------------------------------------------
@@ -2057,16 +2203,17 @@ OvsExtractFlow(const NET_BUFFER_LIST *packet,
if (tunKey) {
ASSERT(tunKey->dst != 0);
- RtlMoveMemory(&flow->tunKey, tunKey, sizeof flow->tunKey);
- flow->l2.offset = 0;
+ UINT8 optOffset = TunnelKeyGetOptionsOffset(tunKey);
+ RtlMoveMemory(((UINT8 *)&flow->tunKey) + optOffset,
+ ((UINT8 *)tunKey) + optOffset,
+ TunnelKeyGetRealSize(tunKey));
} else {
flow->tunKey.dst = 0;
- flow->l2.offset = OVS_WIN_TUNNEL_KEY_SIZE;
}
-
+ flow->l2.offset = OvsGetFlowL2Offset(tunKey);
flow->l2.inPort = inPort;
- 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;
}
@@ -2390,8 +2537,8 @@ OvsLookupFlow(OVS_DATAPATH *datapath,
UINT16 size = key->l2.keyLen;
UINT8 *start;
- ASSERT(key->tunKey.dst || offset == sizeof (OvsIPv4TunnelKey));
- ASSERT(!key->tunKey.dst || offset == 0);
+ ASSERT(key->tunKey.dst || offset == sizeof(OvsIPv4TunnelKey));
+ ASSERT(!key->tunKey.dst || offset == OvsGetFlowL2Offset(&key->tunKey));
start = (UINT8 *)key + offset;
@@ -2447,7 +2594,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 d39db453c..0744d30e9 100644
--- a/datapath-windows/ovsext/Flow.h
+++ b/datapath-windows/ovsext/Flow.h
@@ -87,10 +87,17 @@ VOID MapTunAttrToFlowPut(PNL_ATTR *keyAttrs, PNL_ATTR *tunAttrs,
OvsFlowKey *destKey);
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 000000000..5712e4daa
--- /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:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "precomp.h"
+
+#include "Atomic.h"
+#include "Debug.h"
+#include "Flow.h"
+#include "IpHelper.h"
+#include "Jhash.h"
+#include "NetProto.h"
+#include "Offload.h"
+#include "PacketIO.h"
+#include "PacketParser.h"
+#include "Geneve.h"
+#include "Switch.h"
+#include "User.h"
+#include "Util.h"
+#include "Vport.h"
+
+#ifdef OVS_DBG_MOD
+#undef OVS_DBG_MOD
+#endif
+#define OVS_DBG_MOD OVS_DBG_GENEVE
+
+
+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;
+ }
+
+ 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;
+ }
+ csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl,
+ TcpIpChecksumNetBufferListInfo);
+ status = OvsApplySWChecksumOnNB(layers, *newNbl, &csumInfo);
+
+ if (status != NDIS_STATUS_SUCCESS) {
+ goto ret_error;
+ }
+ }
+
+ curNbl = *newNbl;
+ for (curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); curNb != NULL;
+ curNb = curNb->Next) {
+ status = NdisRetreatNetBufferDataStart(curNb, headRoom, 0, NULL);
+ if (status != NDIS_STATUS_SUCCESS) {
+ goto ret_error;
+ }
+
+ curMdl = NET_BUFFER_CURRENT_MDL(curNb);
+ bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl,
+ LowPagePriority);
+ if (!bufferStart) {
+ status = NDIS_STATUS_RESOURCES;
+ goto ret_error;
+ }
+
+ bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
+ if (NET_BUFFER_NEXT_NB(curNb)) {
+ OVS_LOG_TRACE("nb length %u next %u",
+ NET_BUFFER_DATA_LENGTH(curNb),
+ NET_BUFFER_DATA_LENGTH(curNb->Next));
+ }
+
+ /* L2 header */
+ ethHdr = (EthHdr *)bufferStart;
+ ASSERT(((PCHAR)&fwdInfo.dstMacAddr + sizeof fwdInfo.dstMacAddr) ==
+ (PCHAR)&fwdInfo.srcMacAddr);
+ NdisMoveMemory(ethHdr->Destination, fwdInfo.dstMacAddr,
+ sizeof ethHdr->Destination + sizeof ethHdr->Source);
+ ethHdr->Type = htons(ETH_TYPE_IPV4);
+
+ /* IP header */
+ ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr);
+
+ ipHdr->ihl = sizeof *ipHdr / 4;
+ ipHdr->version = IPPROTO_IPV4;
+ ipHdr->tos = tunKey->tos;
+ ipHdr->tot_len = htons(NET_BUFFER_DATA_LENGTH(curNb) - sizeof *ethHdr);
+ ipHdr->id = (uint16)atomic_add64(&vportGeneve->ipId,
+ NET_BUFFER_DATA_LENGTH(curNb));
+ ipHdr->frag_off = (tunKey->flags & OVS_TNL_F_DONT_FRAGMENT) ?
+ IP_DF_NBO : 0;
+ ipHdr->ttl = tunKey->ttl ? tunKey->ttl : GENEVE_DEFAULT_TTL;
+ ipHdr->protocol = IPPROTO_UDP;
+ ASSERT(tunKey->dst == fwdInfo.dstIpAddr);
+ ASSERT(tunKey->src == fwdInfo.srcIpAddr || tunKey->src == 0);
+ ipHdr->saddr = fwdInfo.srcIpAddr;
+ ipHdr->daddr = fwdInfo.dstIpAddr;
+ ipHdr->check = 0;
+
+ /* 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 = ETH_P_TEB_NBO;
+ 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 != ETH_P_TEB_NBO) {
+ 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, 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 000000000..057f80a05
--- /dev/null
+++ b/datapath-windows/ovsext/Geneve.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef __GENEVE_H_
+#define __GENEVE_H_ 1
+
+#include "NetProto.h"
+typedef struct _OVS_GENEVE_VPORT {
+ UINT16 dstPort;
+ UINT64 filterID;
+ UINT64 ipId;
+ /*
+ * To be filled
+ */
+} OVS_GENEVE_VPORT, *POVS_GENEVE_VPORT;
+
+/* Geneve Header:
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |Ver| Opt Len |O|C| Rsvd. | Protocol Type |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Virtual Network Identifier (VNI) | Reserved |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Variable Length Options |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Option Header:
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Option Class | Type |R|R|R| Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Variable Option Data |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+typedef struct GeneveHdr {
+ /* 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_NBO 0x5865 /* Trans Ether Bridging */
+
+#endif /* __GENEVE_H_ */
diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h
index bcd38ddc0..e666e748d 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 b69360e84..146245345 100644
--- a/datapath-windows/ovsext/Vport.c
+++ b/datapath-windows/ovsext/Vport.c
@@ -27,6 +27,7 @@
#include "User.h"
#include "Vport.h"
#include "Vxlan.h"
+#include "Geneve.h"
#ifdef OVS_DBG_MOD
#undef OVS_DBG_MOD
@@ -1075,6 +1076,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);
}
@@ -1218,6 +1222,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,
@@ -1301,6 +1306,9 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext,
return status;
}
}
+ case OVS_VPORT_TYPE_GENEVE:
+ OvsCleanupGeneveTunnel(vport);
+ break;
case OVS_VPORT_TYPE_STT:
OvsCleanupSttTunnel(vport);
break;
@@ -1362,9 +1370,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);
}
@@ -2255,7 +2261,7 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
if (OvsIsTunnelVportType(portType)) {
UINT16 transportPortDest = 0;
- UINT8 nwProto;
+ UINT8 nwProto = IPPROTO_NONE;
POVS_VPORT_ENTRY dupVport;
switch (portType) {
@@ -2266,6 +2272,9 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
transportPortDest = VXLAN_UDP_PORT;
nwProto = IPPROTO_UDP;
break;
+ case OVS_VPORT_TYPE_GENEVE:
+ transportPortDest = GENEVE_UDP_PORT;
+ break;
case OVS_VPORT_TYPE_STT:
transportPortDest = STT_TCP_PORT;
nwProto = IPPROTO_TCP;
@@ -2393,6 +2402,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/ovsext.vcxproj b/datapath-windows/ovsext/ovsext.vcxproj
index 0ad4c5817..2921a9817 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" />
@@ -183,6 +184,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" />