Yin, I went ahead and sent out a patch for the updates w.r.t OvsFindTunnelVportByDstPort(). Pls have a look: https://patchwork.ozlabs.org/patch/628483/
I¹ll send out the comments for the remainder of the patch. Thanks, -- Nithin -----Original Message----- From: dev <dev-boun...@openvswitch.org> on behalf of Yin Lin <li...@vmware.com> Date: Tuesday, May 24, 2016 at 4:28 PM To: "dev@openvswitch.org" <dev@openvswitch.org> Subject: [ovs-dev] [PATCH 2/2] [PATCH v5] datapath-windows: Add Geneve support >Signed-off-by: Yin Lin <li...@vmware.com> >--- >Fixed checksum flag issue brought up by Jesse and automake.mk issue by >Nithin. >--- > datapath-windows/automake.mk | 2 + > datapath-windows/ovsext/Actions.c | 82 +++----- > datapath-windows/ovsext/Debug.h | 1 + > datapath-windows/ovsext/DpInternal.h | 29 ++- > datapath-windows/ovsext/Flow.c | 172 ++++++++++++++-- > datapath-windows/ovsext/Flow.h | 7 + > datapath-windows/ovsext/Geneve.c | 356 >+++++++++++++++++++++++++++++++++ > datapath-windows/ovsext/Geneve.h | 122 +++++++++++ > datapath-windows/ovsext/Gre.c | 7 +- > datapath-windows/ovsext/Stt.c | 2 +- > datapath-windows/ovsext/Tunnel.c | 3 +- > datapath-windows/ovsext/Util.h | 1 + > datapath-windows/ovsext/Vport.c | 23 ++- > datapath-windows/ovsext/Vport.h | 10 +- > datapath-windows/ovsext/ovsext.vcxproj | 2 + > 15 files changed, 727 insertions(+), 92 deletions(-) > create mode 100644 datapath-windows/ovsext/Geneve.c > create mode 100644 datapath-windows/ovsext/Geneve.h > >diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk >index c9af806..53fb5c5 100644 >--- a/datapath-windows/automake.mk >+++ b/datapath-windows/automake.mk >@@ -68,6 +68,8 @@ EXTRA_DIST += \ > datapath-windows/ovsext/Vport.h \ > datapath-windows/ovsext/Vxlan.c \ > datapath-windows/ovsext/Vxlan.h \ >+ datapath-windows/ovsext/Geneve.c \ >+ datapath-windows/ovsext/Geneve.h \ > datapath-windows/ovsext/ovsext.inf \ > datapath-windows/ovsext/ovsext.rc \ > datapath-windows/ovsext/ovsext.vcxproj \ >diff --git a/datapath-windows/ovsext/Actions.c >b/datapath-windows/ovsext/Actions.c >index 5ad29ee..560f7a1 100644 >--- a/datapath-windows/ovsext/Actions.c >+++ b/datapath-windows/ovsext/Actions.c >@@ -48,6 +48,8 @@ typedef struct _OVS_ACTION_STATS { > UINT64 txVxlan; > UINT64 rxStt; > UINT64 txStt; >+ UINT64 rxGeneve; >+ UINT64 txGeneve; > UINT64 flowMiss; > UINT64 flowUserspace; > UINT64 txTcp; >@@ -227,18 +229,22 @@ OvsDetectTunnelRxPkt(OvsForwardingContext >*ovsFwdCtx, > break; > case IPPROTO_TCP: > tunnelVport = >OvsFindTunnelVportByDstPort(ovsFwdCtx->switchContext, >- dstPort, >- >OVS_VPORT_TYPE_STT); >+ dstPort); > if (tunnelVport) { >+ ASSERT(tunnelVport->ovsType == OVS_VPORT_TYPE_STT); > ovsActionStats.rxStt++; > } > break; > case IPPROTO_UDP: > tunnelVport = >OvsFindTunnelVportByDstPort(ovsFwdCtx->switchContext, >- dstPort, >- >OVS_VPORT_TYPE_VXLAN); >+ dstPort); > if (tunnelVport) { >- ovsActionStats.rxVxlan++; >+ if (tunnelVport->ovsType == OVS_VPORT_TYPE_VXLAN) { >+ ovsActionStats.rxVxlan++; >+ } else { >+ ASSERT(tunnelVport->ovsType == >OVS_VPORT_TYPE_GENEVE); >+ ovsActionStats.rxGeneve++; >+ } > } > break; > } >@@ -333,6 +339,9 @@ OvsDetectTunnelPkt(OvsForwardingContext *ovsFwdCtx, > case OVS_VPORT_TYPE_STT: > ovsActionStats.txStt++; > break; >+ case OVS_VPORT_TYPE_GENEVE: >+ ovsActionStats.txGeneve++; >+ break; > } > ovsFwdCtx->tunnelTxNic = dstVport; > } >@@ -689,6 +698,11 @@ OvsTunnelPortTx(OvsForwardingContext *ovsFwdCtx) > &ovsFwdCtx->tunKey, >ovsFwdCtx->switchContext, > &ovsFwdCtx->layers, &newNbl); > break; >+ case OVS_VPORT_TYPE_GENEVE: >+ status = OvsEncapGeneve(ovsFwdCtx->tunnelTxNic, >ovsFwdCtx->curNbl, >+ &ovsFwdCtx->tunKey, >ovsFwdCtx->switchContext, >+ &ovsFwdCtx->layers, &newNbl); >+ break; > default: > ASSERT(! "Tx: Unhandled tunnel type"); > } >@@ -767,6 +781,10 @@ OvsTunnelPortRx(OvsForwardingContext *ovsFwdCtx) > dropReason = L"OVS-STT segment is cached"; > } > break; >+ case OVS_VPORT_TYPE_GENEVE: >+ status = OvsDecapGeneve(ovsFwdCtx->switchContext, >ovsFwdCtx->curNbl, >+ &ovsFwdCtx->tunKey, &newNbl); >+ break; > default: > OVS_LOG_ERROR("Rx: Unhandled tunnel type: %d\n", > tunnelRxVport->ovsType); >@@ -1233,57 +1251,6 @@ OvsActionMplsPush(OvsForwardingContext *ovsFwdCtx, > } > > /* >- * >-------------------------------------------------------------------------- >- * OvsTunnelAttrToIPv4TunnelKey -- >- * Convert tunnel attribute to OvsIPv4TunnelKey. >- * >-------------------------------------------------------------------------- >- */ >-static __inline NDIS_STATUS >-OvsTunnelAttrToIPv4TunnelKey(PNL_ATTR attr, >- OvsIPv4TunnelKey *tunKey) >-{ >- PNL_ATTR a; >- INT rem; >- >- tunKey->attr[0] = 0; >- tunKey->attr[1] = 0; >- tunKey->attr[2] = 0; >- ASSERT(NlAttrType(attr) == OVS_KEY_ATTR_TUNNEL); >- >- NL_ATTR_FOR_EACH_UNSAFE (a, rem, NlAttrData(attr), >- NlAttrGetSize(attr)) { >- switch (NlAttrType(a)) { >- case OVS_TUNNEL_KEY_ATTR_ID: >- tunKey->tunnelId = NlAttrGetBe64(a); >- tunKey->flags |= OVS_TNL_F_KEY; >- break; >- case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: >- tunKey->src = NlAttrGetBe32(a); >- break; >- case OVS_TUNNEL_KEY_ATTR_IPV4_DST: >- tunKey->dst = NlAttrGetBe32(a); >- break; >- case OVS_TUNNEL_KEY_ATTR_TOS: >- tunKey->tos = NlAttrGetU8(a); >- break; >- case OVS_TUNNEL_KEY_ATTR_TTL: >- tunKey->ttl = NlAttrGetU8(a); >- break; >- case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: >- tunKey->flags |= OVS_TNL_F_DONT_FRAGMENT; >- break; >- case OVS_TUNNEL_KEY_ATTR_CSUM: >- tunKey->flags |= OVS_TNL_F_CSUM; >- break; >- default: >- ASSERT(0); >- } >- } >- >- return NDIS_STATUS_SUCCESS; >-} >- >-/* > >*------------------------------------------------------------------------- >--- > * OvsUpdateEthHeader -- > * Updates the ethernet header in ovsFwdCtx.curNbl inline based on >the >@@ -1511,7 +1478,8 @@ OvsExecuteSetAction(OvsForwardingContext *ovsFwdCtx, > case OVS_KEY_ATTR_TUNNEL: > { > OvsIPv4TunnelKey tunKey; >- status = OvsTunnelAttrToIPv4TunnelKey((PNL_ATTR)a, &tunKey); >+ NTSTATUS convertStatus = >OvsTunnelAttrToIPv4TunnelKey((PNL_ATTR)a, &tunKey); >+ status = SUCCEEDED(convertStatus) ? NDIS_STATUS_SUCCESS : >NDIS_STATUS_FAILURE; > ASSERT(status == NDIS_STATUS_SUCCESS); > tunKey.flow_hash = (uint16)(hash ? *hash : OvsHashFlow(key)); > tunKey.dst_port = key->ipKey.l4.tpDst; >diff --git a/datapath-windows/ovsext/Debug.h >b/datapath-windows/ovsext/Debug.h >index e5ed963..935f858 100644 >--- a/datapath-windows/ovsext/Debug.h >+++ b/datapath-windows/ovsext/Debug.h >@@ -41,6 +41,7 @@ > #define OVS_DBG_TUNFLT BIT32(21) > #define OVS_DBG_STT BIT32(22) > #define OVS_DBG_CONTRK BIT32(23) >+#define OVS_DBG_GENEVE BIT32(24) > > #define OVS_DBG_RESERVED BIT32(31) > //Please add above OVS_DBG_RESERVED. >diff --git a/datapath-windows/ovsext/DpInternal.h >b/datapath-windows/ovsext/DpInternal.h >index a3ce311..a95467b 100644 >--- a/datapath-windows/ovsext/DpInternal.h >+++ b/datapath-windows/ovsext/DpInternal.h >@@ -128,10 +128,18 @@ typedef struct L2Key { > } L2Key; /* Size of 24 byte. */ > > /* Number of packet attributes required to store OVS tunnel key. */ >-#define NUM_PKT_ATTR_REQUIRED 3 >+#define NUM_PKT_ATTR_REQUIRED 35 >+#define TUN_OPT_MAX_LEN 255 > > typedef union OvsIPv4TunnelKey { >+ /* Options should always be the first member of tunnel key. >+ * They are stored at the end of the array if they are less than the >+ * maximum size. This allows us to get the benefits of variable >length >+ * matching for small options. >+ */ > struct { >+ UINT8 tunOpts[TUN_OPT_MAX_LEN]; /* Tunnel options. */ >+ UINT8 tunOptLen; /* Tunnel option length in byte. */ > ovs_be32 dst; > ovs_be32 src; > ovs_be64 tunnelId; >@@ -147,7 +155,22 @@ typedef union OvsIPv4TunnelKey { > }; > }; > uint64_t attr[NUM_PKT_ATTR_REQUIRED]; >-} OvsIPv4TunnelKey; /* Size of 24 byte. */ >+} OvsIPv4TunnelKey; /* Size of 280 byte. */ >+ >+__inline uint8_t TunnelKeyGetOptionsOffset(OvsIPv4TunnelKey *key) >+{ >+ return TUN_OPT_MAX_LEN - key->tunOptLen; >+} >+ >+__inline uint8_t* TunnelKeyGetOptions(OvsIPv4TunnelKey *key) >+{ >+ return key->tunOpts + TunnelKeyGetOptionsOffset(key); >+} >+ >+__inline uint16_t TunnelKeyGetRealSize(OvsIPv4TunnelKey *key) >+{ >+ return sizeof(OvsIPv4TunnelKey) - TunnelKeyGetOptionsOffset(key); >+} > > typedef struct MplsKey { > ovs_be32 lse; /* MPLS topmost label stack entry. */ >@@ -155,7 +178,7 @@ typedef struct MplsKey { > } MplsKey; /* Size of 8 bytes. */ > > typedef __declspec(align(8)) struct OvsFlowKey { >- OvsIPv4TunnelKey tunKey; /* 24 bytes */ >+ OvsIPv4TunnelKey tunKey; /* 280 bytes */ > L2Key l2; /* 24 bytes */ > union { > /* These headers are mutually exclusive. */ >diff --git a/datapath-windows/ovsext/Flow.c >b/datapath-windows/ovsext/Flow.c >index d957d39..b0a8f44 100644 >--- a/datapath-windows/ovsext/Flow.c >+++ b/datapath-windows/ovsext/Flow.c >@@ -21,6 +21,7 @@ > #include "Flow.h" > #include "PacketParser.h" > #include "Datapath.h" >+#include "Geneve.h" > > #ifdef OVS_DBG_MOD > #undef OVS_DBG_MOD >@@ -88,7 +89,7 @@ static NTSTATUS OvsDoDumpFlows(OvsFlowDumpInput >*dumpInput, > UINT32 *replyLen); > static NTSTATUS OvsProbeSupportedFeature(POVS_MESSAGE msgIn, > PNL_ATTR keyAttr); >- >+static UINT16 OvsGetFlowL2Offset(OvsIPv4TunnelKey *tunKey); > > #define OVS_FLOW_TABLE_SIZE 2048 > #define OVS_FLOW_TABLE_MASK (OVS_FLOW_TABLE_SIZE -1) >@@ -1029,6 +1030,13 @@ MapFlowTunKeyToNlKey(PNL_BUFFER nlBuf, > goto done; > } > >+ if (tunKey->tunOptLen > 0 && >+ !NlMsgPutTailUnspec(nlBuf, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, >+ (PCHAR)TunnelKeyGetOptions(tunKey), >tunKey->tunOptLen)) { >+ rc = STATUS_UNSUCCESSFUL; >+ goto done; >+ } >+ > done: > NlMsgEndNested(nlBuf, offset); > error_nested_start: >@@ -1635,6 +1643,116 @@ _MapKeyAttrToFlowPut(PNL_ATTR *keyAttrs, > > /* > >*------------------------------------------------------------------------- >--- >+ * OvsTunnelAttrToGeneveOptions -- >+ * Converts OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS attribute to >tunKey->tunOpts. >+ >*------------------------------------------------------------------------- >--- >+ */ >+static __inline NTSTATUS >+OvsTunnelAttrToGeneveOptions(PNL_ATTR attr, >+ OvsIPv4TunnelKey *tunKey) >+{ >+ UINT32 optLen = NlAttrGetSize(attr); >+ GeneveOptionHdr *option; >+ if (optLen > TUN_OPT_MAX_LEN) { >+ OVS_LOG_ERROR("Geneve option length err (len %d, max %Iu).", >+ optLen, TUN_OPT_MAX_LEN); >+ return STATUS_INFO_LENGTH_MISMATCH; >+ } else if (optLen % 4 != 0) { >+ OVS_LOG_ERROR("Geneve opt len %d is not a multiple of 4.", >optLen); >+ return STATUS_INFO_LENGTH_MISMATCH; >+ } >+ tunKey->tunOptLen = (UINT8)optLen; >+ option = (GeneveOptionHdr *)TunnelKeyGetOptions(tunKey); >+ memcpy(option, NlAttrData(attr), optLen); >+ while (optLen > 0) { >+ UINT32 len; >+ if (optLen < sizeof(*option)) { >+ return STATUS_INFO_LENGTH_MISMATCH; >+ } >+ len = sizeof(*option) + option->length * 4; >+ if (len > optLen) { >+ return STATUS_INFO_LENGTH_MISMATCH; >+ } >+ if (option->type & GENEVE_CRIT_OPT_TYPE) { >+ tunKey->flags |= OVS_TNL_F_CRT_OPT; >+ } >+ option = (GeneveOptionHdr *)((UINT8 *)option + len); >+ optLen -= len; >+ } >+ return STATUS_SUCCESS; >+} >+ >+ >+/* >+ >*------------------------------------------------------------------------- >--- >+ * OvsTunnelAttrToIPv4TunnelKey -- >+ * Converts OVS_KEY_ATTR_TUNNEL attribute to tunKey. >+ >*------------------------------------------------------------------------- >--- >+ */ >+NTSTATUS >+OvsTunnelAttrToIPv4TunnelKey(PNL_ATTR attr, >+ OvsIPv4TunnelKey *tunKey) >+{ >+ PNL_ATTR a; >+ INT rem; >+ INT hasOpt = 0; >+ NTSTATUS status; >+ >+ memset(tunKey, 0, OVS_WIN_TUNNEL_KEY_SIZE); >+ ASSERT(NlAttrType(attr) == OVS_KEY_ATTR_TUNNEL); >+ >+ NL_ATTR_FOR_EACH_UNSAFE(a, rem, NlAttrData(attr), >+ NlAttrGetSize(attr)) { >+ switch (NlAttrType(a)) { >+ case OVS_TUNNEL_KEY_ATTR_ID: >+ tunKey->tunnelId = NlAttrGetBe64(a); >+ tunKey->flags |= OVS_TNL_F_KEY; >+ break; >+ case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: >+ tunKey->src = NlAttrGetBe32(a); >+ break; >+ case OVS_TUNNEL_KEY_ATTR_IPV4_DST: >+ tunKey->dst = NlAttrGetBe32(a); >+ break; >+ case OVS_TUNNEL_KEY_ATTR_TOS: >+ tunKey->tos = NlAttrGetU8(a); >+ break; >+ case OVS_TUNNEL_KEY_ATTR_TTL: >+ tunKey->ttl = NlAttrGetU8(a); >+ break; >+ case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: >+ tunKey->flags |= OVS_TNL_F_DONT_FRAGMENT; >+ break; >+ case OVS_TUNNEL_KEY_ATTR_CSUM: >+ tunKey->flags |= OVS_TNL_F_CSUM; >+ break; >+ case OVS_TUNNEL_KEY_ATTR_OAM: >+ tunKey->flags |= OVS_TNL_F_OAM; >+ break; >+ case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS: >+ if (hasOpt) { >+ /* Duplicate options attribute is not allowed. */ >+ return NDIS_STATUS_FAILURE; >+ } >+ status = OvsTunnelAttrToGeneveOptions(a, tunKey); >+ if (!SUCCEEDED(status)) { >+ return status; >+ } >+ tunKey->flags |= OVS_TNL_F_GENEVE_OPT; >+ hasOpt = 1; >+ break; >+ default: >+ // XXX: Support OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS >+ return STATUS_INVALID_PARAMETER; >+ } >+ } >+ >+ return STATUS_SUCCESS; >+} >+ >+ >+/* >+ >*------------------------------------------------------------------------- >--- > * _MapTunAttrToFlowPut -- > * Converts FLOW_TUNNEL_KEY attribute to OvsFlowKey->tunKey. > >*------------------------------------------------------------------------- >--- >@@ -1644,8 +1762,10 @@ _MapTunAttrToFlowPut(PNL_ATTR *keyAttrs, > PNL_ATTR *tunAttrs, > OvsFlowKey *destKey) > { >+ memset(&destKey->tunKey, 0, OVS_WIN_TUNNEL_KEY_SIZE); > if (keyAttrs[OVS_KEY_ATTR_TUNNEL]) { >- >+ /* XXX: This blocks performs same functionality as >OvsTunnelAttrToIPv4TunnelKey. >+ Consider refactoring the code.*/ > if (tunAttrs[OVS_TUNNEL_KEY_ATTR_ID]) { > destKey->tunKey.tunnelId = NlAttrGetU64 > >(tunAttrs[OVS_TUNNEL_KEY_ATTR_ID]); >@@ -1680,13 +1800,18 @@ _MapTunAttrToFlowPut(PNL_ATTR *keyAttrs, > (tunAttrs[OVS_TUNNEL_KEY_ATTR_TTL]); > } > >- destKey->tunKey.pad = 0; >- destKey->l2.offset = 0; >+ if (tunAttrs[OVS_TUNNEL_KEY_ATTR_OAM]) { >+ destKey->tunKey.flags |= OVS_TNL_F_OAM; >+ } >+ >+ if (tunAttrs[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS]) { >+ >OvsTunnelAttrToGeneveOptions(tunAttrs[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS], >+ &destKey->tunKey); >+ destKey->tunKey.flags |= OVS_TNL_F_GENEVE_OPT; >+ } >+ destKey->l2.offset = OvsGetFlowL2Offset(&destKey->tunKey); > } else { >- destKey->tunKey.attr[0] = 0; >- destKey->tunKey.attr[1] = 0; >- destKey->tunKey.attr[2] = 0; >- destKey->l2.offset = sizeof destKey->tunKey; >+ destKey->l2.offset = OvsGetFlowL2Offset(NULL); > } > } > >@@ -1850,6 +1975,20 @@ OvsGetFlowMetadata(OvsFlowKey *key, > return status; > } > >+UINT16 >+OvsGetFlowL2Offset(OvsIPv4TunnelKey *tunKey) >+{ >+ if (tunKey != NULL) { >+ // Align with int64 boundary >+ if (tunKey->tunOptLen == 0) { >+ return (TUN_OPT_MAX_LEN + 1) / 8 * 8; >+ } >+ return TunnelKeyGetOptionsOffset(tunKey) / 8 * 8; >+ } else { >+ return OVS_WIN_TUNNEL_KEY_SIZE; >+ } >+} >+ > /* > >*------------------------------------------------------------------------- >--- > * Initializes 'flow' members from 'packet', 'skb_priority', 'tun_id', >and >@@ -1881,23 +2020,25 @@ OvsExtractFlow(const NET_BUFFER_LIST *packet, > OvsIPv4TunnelKey *tunKey) > { > struct Eth_Header *eth; >- UINT8 offset = 0; >+ UINT8 offset; > PVOID vlanTagValue; > > layers->value = 0; > > if (tunKey) { > ASSERT(tunKey->dst != 0); >- RtlMoveMemory(&flow->tunKey, tunKey, sizeof flow->tunKey); >- flow->l2.offset = 0; >+ offset = TunnelKeyGetOptionsOffset(tunKey); >+ RtlMoveMemory(((UINT8 *)&flow->tunKey) + offset, >+ ((UINT8 *)tunKey) + offset, >+ TunnelKeyGetRealSize(tunKey)); > } else { > flow->tunKey.dst = 0; >- flow->l2.offset = OVS_WIN_TUNNEL_KEY_SIZE; > } >- >+ flow->l2.offset = OvsGetFlowL2Offset(tunKey); > flow->l2.inPort = inPort; >+ offset = 0; > >- if ( OvsPacketLenNBL(packet) < ETH_HEADER_LEN_DIX) { >+ if (OvsPacketLenNBL(packet) < ETH_HEADER_LEN_DIX) { > flow->l2.keyLen = OVS_WIN_TUNNEL_KEY_SIZE + 8 - flow->l2.offset; > return NDIS_STATUS_SUCCESS; > } >@@ -2222,7 +2363,6 @@ OvsLookupFlow(OVS_DATAPATH *datapath, > UINT8 *start; > > ASSERT(key->tunKey.dst || offset == sizeof (OvsIPv4TunnelKey)); >- ASSERT(!key->tunKey.dst || offset == 0); > > start = (UINT8 *)key + offset; > >@@ -2278,7 +2418,7 @@ OvsHashFlow(const OvsFlowKey *key) > UINT16 size = key->l2.keyLen; > UINT8 *start; > >- ASSERT(key->tunKey.dst || offset == sizeof (OvsIPv4TunnelKey)); >+ ASSERT(key->tunKey.dst || offset == sizeof(OvsIPv4TunnelKey)); > ASSERT(!key->tunKey.dst || offset == 0); > start = (UINT8 *)key + offset; > return OvsJhashBytes(start, size, 0); >diff --git a/datapath-windows/ovsext/Flow.h >b/datapath-windows/ovsext/Flow.h >index 310c472..3722b5d 100644 >--- a/datapath-windows/ovsext/Flow.h >+++ b/datapath-windows/ovsext/Flow.h >@@ -83,10 +83,17 @@ NTSTATUS MapFlowTunKeyToNlKey(PNL_BUFFER nlBuf, >OvsIPv4TunnelKey *tunKey, > UINT16 tunKeyType); > UINT32 OvsFlowKeyAttrSize(void); > UINT32 OvsTunKeyAttrSize(void); >+NTSTATUS OvsTunnelAttrToIPv4TunnelKey(PNL_ATTR attr, OvsIPv4TunnelKey >*tunKey); > > /* Flags for tunneling */ > #define OVS_TNL_F_DONT_FRAGMENT (1 << 0) > #define OVS_TNL_F_CSUM (1 << 1) > #define OVS_TNL_F_KEY (1 << 2) >+#define OVS_TNL_F_OAM (1 << 3) >+#define OVS_TNL_F_CRT_OPT (1 << 4) >+#define OVS_TNL_F_GENEVE_OPT (1 << 5) >+#define OVS_TNL_F_VXLAN_OPT (1 << 6) >+ >+#define OVS_TNL_HAS_OPTIONS (OVS_TNL_F_GENEVE_OPT | >OVS_TNL_F_VXLAN_OPT) > > #endif /* __FLOW_H_ */ >diff --git a/datapath-windows/ovsext/Geneve.c >b/datapath-windows/ovsext/Geneve.c >new file mode 100644 >index 0000000..d59945d >--- /dev/null >+++ b/datapath-windows/ovsext/Geneve.c >@@ -0,0 +1,356 @@ >+/* >+ * Copyright (c) 2016 VMware, Inc. >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at: >+ * >+ * >https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_license >s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=p >NHQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=62Xt8BBpUG4AqJ0X8YjOtMfZRYm0C >1SOzdOxdvcn9ok&s=pd1fscKFk3BO3GSaqAVHqwpPhjWfuk9h4zFaTwkcPso&e= >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or >implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+#include "precomp.h" >+ >+#include "Atomic.h" >+#include "Debug.h" >+#include "Flow.h" >+#include "IpHelper.h" >+#include "Jhash.h" >+#include "NetProto.h" >+#include "Offload.h" >+#include "PacketIO.h" >+#include "PacketParser.h" >+#include "Geneve.h" >+#include "Switch.h" >+#include "User.h" >+#include "Util.h" >+#include "Vport.h" >+ >+#ifdef OVS_DBG_MOD >+#undef OVS_DBG_MOD >+#endif >+#define OVS_DBG_MOD OVS_DBG_GENEVE >+ >+ >+NTSTATUS OvsInitGeneveTunnel(POVS_VPORT_ENTRY vport, >+ UINT16 udpDestPort) >+{ >+ POVS_GENEVE_VPORT genevePort; >+ >+ genevePort = (POVS_GENEVE_VPORT) >OvsAllocateMemoryWithTag(sizeof(*genevePort), >+ >OVS_GENEVE_POOL_TAG); >+ if (!genevePort) { >+ OVS_LOG_ERROR("Insufficient memory, can't allocate >GENEVE_VPORT"); >+ return STATUS_INSUFFICIENT_RESOURCES; >+ } >+ >+ RtlZeroMemory(genevePort, sizeof(*genevePort)); >+ genevePort->dstPort = udpDestPort; >+ vport->priv = (PVOID) genevePort; >+ return STATUS_SUCCESS; >+} >+ >+VOID >+OvsCleanupGeneveTunnel(POVS_VPORT_ENTRY vport) >+{ >+ if (vport->ovsType != OVS_VPORT_TYPE_GENEVE || >+ vport->priv == NULL) { >+ return; >+ } >+ >+ OvsFreeMemoryWithTag(vport->priv, OVS_GENEVE_POOL_TAG); >+ vport->priv = NULL; >+} >+ >+NDIS_STATUS OvsEncapGeneve(POVS_VPORT_ENTRY vport, >+ PNET_BUFFER_LIST curNbl, >+ OvsIPv4TunnelKey *tunKey, >+ POVS_SWITCH_CONTEXT switchContext, >+ POVS_PACKET_HDR_INFO layers, >+ PNET_BUFFER_LIST *newNbl) >+{ >+ NTSTATUS status; >+ OVS_FWD_INFO fwdInfo; >+ PNET_BUFFER curNb; >+ PMDL curMdl; >+ PUINT8 bufferStart; >+ EthHdr *ethHdr; >+ IPHdr *ipHdr; >+ UDPHdr *udpHdr; >+ GeneveHdr *geneveHdr; >+ GeneveOptionHdr *optHdr; >+ POVS_GENEVE_VPORT vportGeneve; >+ UINT32 headRoom = OvsGetGeneveTunHdrMinSize() + tunKey->tunOptLen; >+ UINT32 packetLength; >+ ULONG mss = 0; >+ NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo; >+ >+ status = OvsLookupIPFwdInfo(tunKey->dst, &fwdInfo); >+ if (status != STATUS_SUCCESS) { >+ OvsFwdIPHelperRequest(NULL, 0, tunKey, NULL, NULL, NULL); >+ // return NDIS_STATUS_PENDING; >+ /* >+ * XXX: Don't know if the completionList will make any sense when >+ * accessed in the callback. Make sure the caveats are known. >+ * >+ * XXX: This code will work once we are able to grab locks in the >+ * callback. >+ */ >+ return NDIS_STATUS_FAILURE; >+ } >+ >+ /* >+ * XXX: the assumption currently is that the NBL is owned by OVS, and >+ * headroom has already been allocated as part of allocating the NBL >and >+ * MDL. >+ */ >+ curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); >+ packetLength = NET_BUFFER_DATA_LENGTH(curNb); >+ >+ if (layers->isTcp) { >+ mss = OVSGetTcpMSS(curNbl); >+ >+ OVS_LOG_TRACE("MSS %u packet len %u", mss, >+ packetLength); >+ if (mss) { >+ OVS_LOG_TRACE("l4Offset %d", layers->l4Offset); >+ *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers, >+ mss, headRoom); >+ if (*newNbl == NULL) { >+ OVS_LOG_ERROR("Unable to segment NBL"); >+ return NDIS_STATUS_FAILURE; >+ } >+ /* Clear out LSO flags after this point */ >+ NET_BUFFER_LIST_INFO(*newNbl, TcpLargeSendNetBufferListInfo) >= 0; >+ } >+ } >+ >+ vportGeneve = (POVS_GENEVE_VPORT) GetOvsVportPriv(vport); >+ ASSERT(vportGeneve != NULL); >+ >+ /* If we didn't split the packet above, make a copy now */ >+ if (*newNbl == NULL) { >+ *newNbl = OvsPartialCopyNBL(switchContext, curNbl, 0, headRoom, >+ FALSE /*NBL info*/); >+ if (*newNbl == NULL) { >+ OVS_LOG_ERROR("Unable to copy NBL"); >+ return NDIS_STATUS_FAILURE; >+ } >+ NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo; >+ csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl, >+ >TcpIpChecksumNetBufferListInfo); >+ status = OvsApplySWChecksumOnNB(layers, *newNbl, &csumInfo); >+ >+ if (status != NDIS_STATUS_SUCCESS) { >+ goto ret_error; >+ } >+ } >+ >+ curNbl = *newNbl; >+ for (curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); curNb != NULL; >+ curNb = curNb->Next) { >+ status = NdisRetreatNetBufferDataStart(curNb, headRoom, 0, NULL); >+ if (status != NDIS_STATUS_SUCCESS) { >+ goto ret_error; >+ } >+ >+ curMdl = NET_BUFFER_CURRENT_MDL(curNb); >+ bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, >LowPagePriority); >+ if (!bufferStart) { >+ status = NDIS_STATUS_RESOURCES; >+ goto ret_error; >+ } >+ >+ bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb); >+ if (NET_BUFFER_NEXT_NB(curNb)) { >+ OVS_LOG_TRACE("nb length %u next %u", >NET_BUFFER_DATA_LENGTH(curNb), >+ NET_BUFFER_DATA_LENGTH(curNb->Next)); >+ } >+ >+ /* L2 header */ >+ ethHdr = (EthHdr *)bufferStart; >+ ASSERT(((PCHAR)&fwdInfo.dstMacAddr + sizeof fwdInfo.dstMacAddr) >== >+ (PCHAR)&fwdInfo.srcMacAddr); >+ NdisMoveMemory(ethHdr->Destination, fwdInfo.dstMacAddr, >+ sizeof ethHdr->Destination + sizeof >ethHdr->Source); >+ ethHdr->Type = htons(ETH_TYPE_IPV4); >+ >+ /* IP header */ >+ ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr); >+ >+ ipHdr->ihl = sizeof *ipHdr / 4; >+ ipHdr->version = IPPROTO_IPV4; >+ ipHdr->tos = tunKey->tos; >+ ipHdr->tot_len = htons(NET_BUFFER_DATA_LENGTH(curNb) - sizeof >*ethHdr); >+ ipHdr->id = (uint16)atomic_add64(&vportGeneve->ipId, >+ NET_BUFFER_DATA_LENGTH(curNb)); >+ ipHdr->frag_off = (tunKey->flags & OVS_TNL_F_DONT_FRAGMENT) ? >+ IP_DF_NBO : 0; >+ ipHdr->ttl = tunKey->ttl ? tunKey->ttl : GENEVE_DEFAULT_TTL; >+ ipHdr->protocol = IPPROTO_UDP; >+ ASSERT(tunKey->dst == fwdInfo.dstIpAddr); >+ ASSERT(tunKey->src == fwdInfo.srcIpAddr || tunKey->src == 0); >+ ipHdr->saddr = fwdInfo.srcIpAddr; >+ ipHdr->daddr = fwdInfo.dstIpAddr; >+ >+ /* UDP header */ >+ udpHdr = (UDPHdr *)((PCHAR)ipHdr + sizeof *ipHdr); >+ udpHdr->source = htons(tunKey->flow_hash | MAXINT16); >+ udpHdr->dest = htons(vportGeneve->dstPort); >+ udpHdr->len = htons(NET_BUFFER_DATA_LENGTH(curNb) - headRoom + >+ sizeof *udpHdr + sizeof *geneveHdr + >tunKey->tunOptLen); >+ if (tunKey->flags & OVS_TNL_F_CSUM) { >+ UINT16 udpChksumLen = (UINT16) NET_BUFFER_DATA_LENGTH(curNb) >- >+ sizeof *ipHdr - sizeof *ethHdr; >+ udpHdr->check = IPPseudoChecksum(&ipHdr->saddr, >&ipHdr->daddr, >+ IPPROTO_UDP, udpChksumLen); >+ } else { >+ udpHdr->check = 0; >+ } >+ /* Geneve header */ >+ geneveHdr = (GeneveHdr *)((PCHAR)udpHdr + sizeof *udpHdr); >+ geneveHdr->version = GENEVE_VER; >+ geneveHdr->optLen = tunKey->tunOptLen / 4; >+ geneveHdr->oam = !!(tunKey->flags & OVS_TNL_F_OAM); >+ geneveHdr->critical = !!(tunKey->flags & OVS_TNL_F_CRT_OPT); >+ geneveHdr->reserved1 = 0; >+ geneveHdr->protocol = htons(ETH_P_TEB); >+ geneveHdr->vni = GENEVE_TUNNELID_TO_VNI(tunKey->tunnelId); >+ geneveHdr->reserved2 = 0; >+ >+ /* Geneve header options */ >+ optHdr = (GeneveOptionHdr *)(geneveHdr + 1); >+ memcpy(optHdr, TunnelKeyGetOptions(tunKey), tunKey->tunOptLen); >+ >+ csumInfo.Value = 0; >+ csumInfo.Transmit.IpHeaderChecksum = 1; >+ csumInfo.Transmit.IsIPv4 = 1; >+ if (tunKey->flags & OVS_TNL_F_CSUM) { >+ csumInfo.Transmit.UdpChecksum = 1; >+ } >+ NET_BUFFER_LIST_INFO(curNbl, >+ TcpIpChecksumNetBufferListInfo) = >csumInfo.Value; >+ } >+ return STATUS_SUCCESS; >+ >+ret_error: >+ OvsCompleteNBL(switchContext, *newNbl, TRUE); >+ *newNbl = NULL; >+ return status; >+} >+ >+NDIS_STATUS OvsDecapGeneve(POVS_SWITCH_CONTEXT switchContext, >+ PNET_BUFFER_LIST curNbl, >+ OvsIPv4TunnelKey *tunKey, >+ PNET_BUFFER_LIST *newNbl) >+{ >+ PNET_BUFFER curNb; >+ PMDL curMdl; >+ EthHdr *ethHdr; >+ IPHdr *ipHdr; >+ UDPHdr *udpHdr; >+ GeneveHdr *geneveHdr; >+ UINT32 tunnelSize; >+ UINT32 packetLength; >+ PUINT8 bufferStart; >+ PVOID optStart; >+ NDIS_STATUS status; >+ >+ /* Check the length of the UDP payload */ >+ curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); >+ tunnelSize = OvsGetGeneveTunHdrMinSize(); >+ packetLength = NET_BUFFER_DATA_LENGTH(curNb); >+ if (packetLength <= tunnelSize) { >+ return NDIS_STATUS_INVALID_LENGTH; >+ } >+ >+ /* >+ * Create a copy of the NBL so that we have all the headers in one >MDL. >+ */ >+ *newNbl = OvsPartialCopyNBL(switchContext, curNbl, >+ tunnelSize, 0, >+ TRUE /*copy NBL info */); >+ >+ if (*newNbl == NULL) { >+ return NDIS_STATUS_RESOURCES; >+ } >+ >+ /* XXX: Handle VLAN header. */ >+ curNbl = *newNbl; >+ curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); >+ curMdl = NET_BUFFER_CURRENT_MDL(curNb); >+ bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, >LowPagePriority) + >+ NET_BUFFER_CURRENT_MDL_OFFSET(curNb); >+ if (!bufferStart) { >+ status = NDIS_STATUS_RESOURCES; >+ goto dropNbl; >+ } >+ >+ ethHdr = (EthHdr *)bufferStart; >+ /* XXX: Handle IP options. */ >+ ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr); >+ tunKey->src = ipHdr->saddr; >+ tunKey->dst = ipHdr->daddr; >+ tunKey->tos = ipHdr->tos; >+ tunKey->ttl = ipHdr->ttl; >+ tunKey->pad = 0; >+ udpHdr = (UDPHdr *)((PCHAR)ipHdr + sizeof *ipHdr); >+ >+ /* Validate if NIC has indicated checksum failure. */ >+ status = OvsValidateUDPChecksum(curNbl, udpHdr->check == 0); >+ if (status != NDIS_STATUS_SUCCESS) { >+ goto dropNbl; >+ } >+ >+ /* Calculate and verify UDP checksum if NIC didn't do it. */ >+ if (udpHdr->check != 0) { >+ status = OvsCalculateUDPChecksum(curNbl, curNb, ipHdr, udpHdr, >packetLength); >+ tunKey->flags |= OVS_TNL_F_CSUM; >+ if (status != NDIS_STATUS_SUCCESS) { >+ goto dropNbl; >+ } >+ } >+ >+ geneveHdr = (GeneveHdr *)((PCHAR)udpHdr + sizeof *udpHdr); >+ if (geneveHdr->protocol != htons(ETH_P_TEB)) { >+ status = STATUS_NDIS_INVALID_PACKET; >+ goto dropNbl; >+ } >+ tunKey->flags = OVS_TNL_F_KEY; >+ if (geneveHdr->oam) { >+ tunKey->flags |= OVS_TNL_F_OAM; >+ } >+ tunKey->tunnelId = GENEVE_VNI_TO_TUNNELID(geneveHdr->vni); >+ tunKey->tunOptLen = (uint8)geneveHdr->optLen * 4; >+ if (tunKey->tunOptLen > TUN_OPT_MAX_LEN || >+ packetLength < tunnelSize + tunKey->tunOptLen) { >+ status = NDIS_STATUS_INVALID_LENGTH; >+ goto dropNbl; >+ } >+ /* Clear out the receive flag for the inner packet. */ >+ NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo) = 0; >+ >+ NdisAdvanceNetBufferDataStart(curNb, tunnelSize, FALSE, NULL); >+ if (tunKey->tunOptLen > 0) { >+ optStart = NdisGetDataBuffer(curNb, tunKey->tunOptLen, >+ TunnelKeyGetOptions(tunKey), 1 /*no >align*/, 0); >+ >+ /* If data is contiguous in the buffer, NdisGetDataBuffer will >not copy >+ data to the storage. Manual copy is needed. */ >+ if (optStart != TunnelKeyGetOptions(tunKey)) { >+ memcpy(TunnelKeyGetOptions(tunKey), optStart, >tunKey->tunOptLen); >+ } >+ NdisAdvanceNetBufferDataStart(curNb, tunKey->tunOptLen, FALSE, >NULL); >+ } >+ return NDIS_STATUS_SUCCESS; >+ >+dropNbl: >+ OvsCompleteNBL(switchContext, *newNbl, TRUE); >+ *newNbl = NULL; >+ return status; >+} >diff --git a/datapath-windows/ovsext/Geneve.h >b/datapath-windows/ovsext/Geneve.h >new file mode 100644 >index 0000000..74325a5 >--- /dev/null >+++ b/datapath-windows/ovsext/Geneve.h >@@ -0,0 +1,122 @@ >+/* >+ * Copyright (c) 2016 VMware, Inc. >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at: >+ * >+ * >https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_license >s_LICENSE-2D2.0&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=p >NHQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=62Xt8BBpUG4AqJ0X8YjOtMfZRYm0C >1SOzdOxdvcn9ok&s=pd1fscKFk3BO3GSaqAVHqwpPhjWfuk9h4zFaTwkcPso&e= >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or >implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+ >+#ifndef __GENEVE_H_ >+#define __GENEVE_H_ 1 >+ >+#include "NetProto.h" >+typedef struct _OVS_GENEVE_VPORT { >+ UINT16 dstPort; >+ UINT64 filterID; >+ UINT64 ipId; >+ /* >+ * To be filled >+ */ >+} OVS_GENEVE_VPORT, *POVS_GENEVE_VPORT; >+ >+/* Geneve Header: >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ * |Ver| Opt Len |O|C| Rsvd. | Protocol Type | >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ * | Virtual Network Identifier (VNI) | Reserved | >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ * | Variable Length Options | >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ * >+ * Option Header: >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ * | Option Class | Type |R|R|R| Length | >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ * | Variable Option Data | >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ */ >+typedef struct GeneveHdr { >+ /* Length of options fields in int32 excluding the common header */ >+ UINT32 optLen : 6; >+ /* Version. */ >+ UINT32 version:2; >+ /* Reserved. */ >+ UINT32 reserved1 : 6; >+ /* Critical options present */ >+ UINT32 critical : 1; >+ /* This packet contains a control message instead of a data payload >*/ >+ UINT32 oam:1; >+ /* Protocol Type. */ >+ UINT32 protocol:16; >+ /* VNI */ >+ UINT32 vni:24; >+ /* Reserved. */ >+ UINT32 reserved2:8; >+} GeneveHdr; >+ >+typedef struct GeneveOptionHdr { >+ /* Namespace for the 'type' field. */ >+ UINT32 optionClass:16; >+ /* Format of data contained in the option. */ >+ UINT32 type:8; >+ /* Reserved. */ >+ UINT32 reserved:3; >+ /* Length of option in int32 excluding the option header. */ >+ UINT32 length:5; >+} GeneveOptionHdr; >+ >+#define GENEVE_CRIT_OPT_TYPE (1 << 7) >+ >+NTSTATUS OvsInitGeneveTunnel(POVS_VPORT_ENTRY vport, >+ UINT16 udpDestPort); >+ >+VOID OvsCleanupGeneveTunnel(POVS_VPORT_ENTRY vport); >+ >+ >+NDIS_STATUS OvsEncapGeneve(POVS_VPORT_ENTRY vport, >+ PNET_BUFFER_LIST curNbl, >+ OvsIPv4TunnelKey *tunKey, >+ POVS_SWITCH_CONTEXT switchContext, >+ POVS_PACKET_HDR_INFO layers, >+ PNET_BUFFER_LIST *newNbl); >+ >+NDIS_STATUS OvsDecapGeneve(POVS_SWITCH_CONTEXT switchContext, >+ PNET_BUFFER_LIST curNbl, >+ OvsIPv4TunnelKey *tunKey, >+ PNET_BUFFER_LIST *newNbl); >+ >+static __inline UINT32 >+OvsGetGeneveTunHdrMinSize(VOID) >+{ >+ /* XXX: Can L2 include VLAN at all? */ >+ return sizeof (EthHdr) + sizeof (IPHdr) + sizeof (UDPHdr) + >+ sizeof (GeneveHdr); >+} >+ >+static __inline UINT32 >+OvsGetGeneveTunHdrMaxSize(VOID) >+{ >+ /* XXX: Can L2 include VLAN at all? */ >+ return OvsGetGeneveTunHdrMinSize() + TUN_OPT_MAX_LEN; >+} >+ >+#define GENEVE_UDP_PORT 6081 >+#define GENEVE_UDP_PORT_NBO 0xC117 >+#define GENEVE_VER 0 >+#define GENEVE_DEFAULT_TTL 64 >+#define GENEVE_ID_IS_VALID(geneveID) (0 < (geneveID) && (vxlanID) <= >0xffffff) >+#define GENEVE_TUNNELID_TO_VNI(_tID) (UINT32)(((UINT64)(_tID)) >> 40) >+#define GENEVE_VNI_TO_TUNNELID(_vni) (((UINT64)(_vni)) << 40) >+#define ETH_P_TEB 0x6558 /* Trans Ether Bridging */ >+ >+#endif /* __GENEVE_H_ */ >+ >diff --git a/datapath-windows/ovsext/Gre.c b/datapath-windows/ovsext/Gre.c >index cb41593..fbcbdb4 100644 >--- a/datapath-windows/ovsext/Gre.c >+++ b/datapath-windows/ovsext/Gre.c >@@ -299,7 +299,7 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext, > EthHdr *ethHdr; > IPHdr *ipHdr; > GREHdr *greHdr; >- UINT32 tunnelSize = 0, packetLength = 0; >+ UINT32 tunnelSize, packetLength; > UINT32 headRoom = 0; > PUINT8 bufferStart; > NDIS_STATUS status; >@@ -307,7 +307,8 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext, > curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); > packetLength = NET_BUFFER_DATA_LENGTH(curNb); > tunnelSize = GreTunHdrSize(tunKey->flags); >- if (packetLength <= tunnelSize) { >+ >+ if (packetLength < tunnelSize) { > return NDIS_STATUS_INVALID_LENGTH; > } > >@@ -315,7 +316,7 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext, > * Create a copy of the NBL so that we have all the headers in one >MDL. > */ > *newNbl = OvsPartialCopyNBL(switchContext, curNbl, >- tunnelSize + OVS_DEFAULT_COPY_SIZE, 0, >+ tunnelSize, 0, > TRUE /*copy NBL info */); > > if (*newNbl == NULL) { >diff --git a/datapath-windows/ovsext/Stt.c b/datapath-windows/ovsext/Stt.c >index dd7bf92..f08ca27 100644 >--- a/datapath-windows/ovsext/Stt.c >+++ b/datapath-windows/ovsext/Stt.c >@@ -761,7 +761,7 @@ OvsDecapStt(POVS_SWITCH_CONTEXT switchContext, > advanceCnt = hdrLen; > > ipHdr = NdisGetDataBuffer(curNb, sizeof *ipHdr, (PVOID) &ipBuf, >- 1 /*no align*/, 0); >+ 1 /*no align*/, 0); > ASSERT(ipHdr); > > TCPHdr *tcp = (TCPHdr *)((PCHAR)ipHdr + ipHdr->ihl * 4); >diff --git a/datapath-windows/ovsext/Tunnel.c >b/datapath-windows/ovsext/Tunnel.c >index 97d2020..4f3ae3e 100644 >--- a/datapath-windows/ovsext/Tunnel.c >+++ b/datapath-windows/ovsext/Tunnel.c >@@ -286,8 +286,7 @@ OvsInjectPacketThroughActions(PNET_BUFFER_LIST pNbl, > SendFlags |= NDIS_SEND_FLAGS_DISPATCH_LEVEL; > > vport = OvsFindTunnelVportByDstPort(gOvsSwitchContext, >- htons(tunnelKey.dst_port), >- OVS_VPORT_TYPE_VXLAN); >+ htons(tunnelKey.dst_port)); > > if (vport == NULL){ > status = STATUS_UNSUCCESSFUL; >diff --git a/datapath-windows/ovsext/Util.h >b/datapath-windows/ovsext/Util.h >index 4bcde3b..15793c0 100644 >--- a/datapath-windows/ovsext/Util.h >+++ b/datapath-windows/ovsext/Util.h >@@ -38,6 +38,7 @@ > #define OVS_TUNFLT_POOL_TAG 'WSVO' > #define OVS_RECIRC_POOL_TAG 'CSVO' > #define OVS_CT_POOL_TAG 'CTVO' >+#define OVS_GENEVE_POOL_TAG 'GNVO' > > VOID *OvsAllocateMemory(size_t size); > VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag); >diff --git a/datapath-windows/ovsext/Vport.c >b/datapath-windows/ovsext/Vport.c >index 4299169..7e5cfc1 100644 >--- a/datapath-windows/ovsext/Vport.c >+++ b/datapath-windows/ovsext/Vport.c >@@ -692,8 +692,7 @@ OvsFindVportByPortNo(POVS_SWITCH_CONTEXT >switchContext, > > POVS_VPORT_ENTRY > OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext, >- UINT16 dstPort, >- OVS_VPORT_TYPE ovsPortType) >+ UINT16 dstPort) > { > POVS_VPORT_ENTRY vport; > PLIST_ENTRY head, link; >@@ -702,8 +701,7 @@ OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT >switchContext, > head = &(switchContext->tunnelVportsArray[hash & OVS_VPORT_MASK]); > LIST_FORALL(head, link) { > vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, >tunnelVportLink); >- if (GetPortFromPriv(vport) == dstPort && >- vport->ovsType == ovsPortType) { >+ if (GetPortFromPriv(vport) == dstPort) { > return vport; > } > } >@@ -1042,6 +1040,9 @@ OvsInitTunnelVport(PVOID userContext, > case OVS_VPORT_TYPE_STT: > status = OvsInitSttTunnel(vport, dstPort); > break; >+ case OVS_VPORT_TYPE_GENEVE: >+ status = OvsInitGeneveTunnel(vport, dstPort); >+ break; > default: > ASSERT(0); > } >@@ -1185,6 +1186,7 @@ InitOvsVportCommon(POVS_SWITCH_CONTEXT >switchContext, > case OVS_VPORT_TYPE_GRE: > case OVS_VPORT_TYPE_VXLAN: > case OVS_VPORT_TYPE_STT: >+ case OVS_VPORT_TYPE_GENEVE: > { > UINT16 dstPort = GetPortFromPriv(vport); > hash = OvsJhashBytes(&dstPort, >@@ -1268,6 +1270,9 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext, > return status; > } > } >+ case OVS_VPORT_TYPE_GENEVE: >+ OvsCleanupGeneveTunnel(vport); >+ break; > case OVS_VPORT_TYPE_STT: > OvsCleanupSttTunnel(vport); > break; >@@ -1329,9 +1334,7 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext, > InitializeListHead(&vport->ovsNameLink); > RemoveEntryList(&vport->portNoLink); > InitializeListHead(&vport->portNoLink); >- if (OVS_VPORT_TYPE_VXLAN == vport->ovsType || >- OVS_VPORT_TYPE_STT == vport->ovsType || >- OVS_VPORT_TYPE_GRE == vport->ovsType) { >+ if (OvsIsTunnelVportType(vport->ovsType)) { > RemoveEntryList(&vport->tunnelVportLink); > InitializeListHead(&vport->tunnelVportLink); > } >@@ -2227,6 +2230,9 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT >usrParamsCtx, > case OVS_VPORT_TYPE_VXLAN: > transportPortDest = VXLAN_UDP_PORT; > break; >+ case OVS_VPORT_TYPE_GENEVE: >+ transportPortDest = GENEVE_UDP_PORT; >+ break; > case OVS_VPORT_TYPE_STT: > transportPortDest = STT_TCP_PORT; > break; >@@ -2336,6 +2342,9 @@ Cleanup: > case OVS_VPORT_TYPE_STT: > OvsCleanupSttTunnel(vport); > break; >+ case OVS_VPORT_TYPE_GENEVE: >+ OvsCleanupGeneveTunnel(vport); >+ break; > default: > ASSERT(!"Invalid tunnel port type"); > } >diff --git a/datapath-windows/ovsext/Vport.h >b/datapath-windows/ovsext/Vport.h >index 373896d..8f0b8a8 100644 >--- a/datapath-windows/ovsext/Vport.h >+++ b/datapath-windows/ovsext/Vport.h >@@ -21,6 +21,7 @@ > #include "Stt.h" > #include "Switch.h" > #include "VxLan.h" >+#include "Geneve.h" > > #define OVS_MAX_DPPORTS MAXUINT16 > #define OVS_DPPORT_NUMBER_INVALID OVS_MAX_DPPORTS >@@ -146,8 +147,7 @@ POVS_VPORT_ENTRY >OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchConte > NDIS_SWITCH_PORT_ID >portId, > NDIS_SWITCH_NIC_INDEX >index); > POVS_VPORT_ENTRY OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT >switchContext, >- UINT16 dstPort, >- OVS_VPORT_TYPE >ovsVportType); >+ UINT16 dstPort); > POVS_VPORT_ENTRY OvsFindTunnelVportByPortType(POVS_SWITCH_CONTEXT >switchContext, > OVS_VPORT_TYPE >ovsPortType); > >@@ -181,7 +181,8 @@ OvsIsTunnelVportType(OVS_VPORT_TYPE ovsType) > { > return ovsType == OVS_VPORT_TYPE_VXLAN || > ovsType == OVS_VPORT_TYPE_STT || >- ovsType == OVS_VPORT_TYPE_GRE; >+ ovsType == OVS_VPORT_TYPE_GRE || >+ ovsType == OVS_VPORT_TYPE_GENEVE; > } > > >@@ -267,6 +268,9 @@ GetPortFromPriv(POVS_VPORT_ENTRY vport) > case OVS_VPORT_TYPE_VXLAN: > dstPort = ((POVS_VXLAN_VPORT)vportPriv)->dstPort; > break; >+ case OVS_VPORT_TYPE_GENEVE: >+ dstPort = ((POVS_GENEVE_VPORT)vportPriv)->dstPort; >+ break; > default: > ASSERT(! "Port is not a tunnel port"); > } >diff --git a/datapath-windows/ovsext/ovsext.vcxproj >b/datapath-windows/ovsext/ovsext.vcxproj >index 0356ddf..02fa60c 100644 >--- a/datapath-windows/ovsext/ovsext.vcxproj >+++ b/datapath-windows/ovsext/ovsext.vcxproj >@@ -81,6 +81,7 @@ > <ClInclude Include="Ethernet.h" /> > <ClInclude Include="Event.h" /> > <ClInclude Include="Flow.h" /> >+ <ClInclude Include="Geneve.h" /> > <ClInclude Include="Gre.h" /> > <ClInclude Include="IpHelper.h" /> > <ClInclude Include="Jhash.h" /> >@@ -182,6 +183,7 @@ > <ClCompile Include="Driver.c" /> > <ClCompile Include="Event.c" /> > <ClCompile Include="Flow.c" /> >+ <ClCompile Include="Geneve.c" /> > <ClCompile Include="Gre.c" /> > <ClCompile Include="IpHelper.c" /> > <ClCompile Include="Jhash.c" /> >-- >2.8.0.windows.1 > >_______________________________________________ >dev mailing list >dev@openvswitch.org >https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailma >n_listinfo_dev&d=CwIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=pN >HQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=62Xt8BBpUG4AqJ0X8YjOtMfZRYm0C1 >SOzdOxdvcn9ok&s=tl9Z_geYFFKX3JcT35a7Aj5CdmcG9m0Xjcovds_NlNE&e= _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev