On 24 June 2016 at 11:49, Yin Lin <li...@vmware.com> wrote: > Signed-off-by: Yin Lin <li...@vmware.com> > is this just a rebase for the patch that Nithin Acked?
> --- > datapath-windows/automake.mk | 2 + > datapath-windows/ovsext/Actions.c | 72 ++----- > datapath-windows/ovsext/Debug.h | 1 + > datapath-windows/ovsext/DpInternal.h | 29 ++- > datapath-windows/ovsext/Flow.c | 179 +++++++++++++++-- > datapath-windows/ovsext/Flow.h | 7 + > datapath-windows/ovsext/Geneve.c | 356 > +++++++++++++++++++++++++++++++++ > datapath-windows/ovsext/Geneve.h | 122 +++++++++++ > datapath-windows/ovsext/Util.h | 1 + > datapath-windows/ovsext/Vport.c | 20 +- > datapath-windows/ovsext/ovsext.vcxproj | 2 + > 11 files changed, 716 insertions(+), 75 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 7ac6bb7..722a2a8 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 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 07bc180..42b5ec9 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 595518f..bc0bb37 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 d39db45..0744d30 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 0000000..53a9bce > --- /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 0000000..0535e79 > --- /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: > + * > + * 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 bcd38dd..e666e74 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 b69360e..1462453 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 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 > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev