Thanks for the patch Alin. I had very minor comments that I have added inline. Looks good otherwise.
Sairam On 12/2/15, 9:50 AM, "Alin Serdean" <aserd...@cloudbasesolutions.com> wrote: >This patch introduces the support for GRE TEB (trasparent ethernet >bridging) >for the windows datapath. > >The GRE support is based on >https://urldefense.proofpoint.com/v2/url?u=http-3A__tools.ietf.org_html_rf >c2890&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dcruz40PROJ >40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-lbhauUks_UnSyw6KxJOowOdmMYr-jCKUEPW >SJuQ&s=nJEtVHbdSVVYPTPVjZUZbaEWG2D7lx0u5y6VpKCbbGM&e= and supports >only the GRE protocol type 6558 (trasparent ethernet bridging) like its >linux >counterpart. > >Util.h: define the GRE pool tag >Vport.c/h: sort the includes alphabetically > add the function OvsFindTunnelVportByPortType which searches >the > tunnelVportsArray for a given port type >Actions.c : sort the includes alphabetically > call the GRE encapsulation / decapsulation functions when >needed >Gre.c/h : add GRE type defines > add initialization/cleanup functions > add encapsulation / decapsulation functions with software >offloads > (hardware offloads will be added in a separate patch) with >LSO(TSO) > support > >Tested using: PSPING > >(https://urldefense.proofpoint.com/v2/url?u=https-3A__technet.microsoft.co >m_en-2Dus_sysinternals_psping.aspx&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeA >w-YihVMNtXt-uEs&r=Dcruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-lbhauU >ks_UnSyw6KxJOowOdmMYr-jCKUEPWSJuQ&s=zRPkfIHroZtzdBG9Ra3sIfgFd-CYLaPUWfdlN4 >ik_xg&e= ) > (ICMP, TCP, UDP) with various packet lengths > IPERF3 > >(https://urldefense.proofpoint.com/v2/url?u=https-3A__iperf.fr_iperf-2Ddow >nload.php&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dcruz40 >PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-lbhauUks_UnSyw6KxJOowOdmMYr-jCK >UEPWSJuQ&s=0nEEutWRlVJKJzQXNE7K6RNl3lE-K6DKKb3vDLPEjwk&e= ) > (TCP, UDP) with various options > >Signed-off-by: Alin Gabriel Serdean <aserd...@cloudbasesolutions.com> >--- > datapath-windows/ovsext/Actions.c | 71 +++-- > datapath-windows/ovsext/Gre.c | 456 >+++++++++++++++++++++++++++++++++ > datapath-windows/ovsext/Gre.h | 113 ++++++++ > datapath-windows/ovsext/Util.h | 1 + > datapath-windows/ovsext/Vport.c | 43 +++- > datapath-windows/ovsext/Vport.h | 14 +- > datapath-windows/ovsext/ovsext.vcxproj | 2 + > 7 files changed, 665 insertions(+), 35 deletions(-) > create mode 100644 datapath-windows/ovsext/Gre.c > create mode 100644 datapath-windows/ovsext/Gre.h > >diff --git a/datapath-windows/ovsext/Actions.c >b/datapath-windows/ovsext/Actions.c >index e902983..6b2a191 100644 >--- a/datapath-windows/ovsext/Actions.c >+++ b/datapath-windows/ovsext/Actions.c >@@ -16,16 +16,17 @@ > > #include "precomp.h" > >-#include "Switch.h" >-#include "Vport.h" >+#include "Checksum.h" > #include "Event.h" >-#include "User.h" >-#include "NetProto.h" > #include "Flow.h" >-#include "Vxlan.h" >-#include "Stt.h" >-#include "Checksum.h" >+#include "Gre.h" >+#include "NetProto.h" > #include "PacketIO.h" >+#include "Stt.h" >+#include "Switch.h" >+#include "User.h" >+#include "Vport.h" >+#include "Vxlan.h" > > #ifdef OVS_DBG_MOD > #undef OVS_DBG_MOD >@@ -34,6 +35,8 @@ > #include "Debug.h" > > typedef struct _OVS_ACTION_STATS { >+ UINT64 rxGre; >+ UINT64 txGre; > UINT64 rxVxlan; > UINT64 txVxlan; > UINT64 rxStt; >@@ -205,27 +208,35 @@ OvsDetectTunnelRxPkt(OvsForwardingContext >*ovsFwdCtx, > /* XXX: we should also check for the length of the UDP payload to >pick > * packets only if they are at least VXLAN header size. > */ >- if (!flowKey->ipKey.nwFrag && >- flowKey->ipKey.nwProto == IPPROTO_UDP) { >- UINT16 dstPort = ntohs(flowKey->ipKey.l4.tpDst); >- tunnelVport = >OvsFindTunnelVportByDstPort(ovsFwdCtx->switchContext, >- dstPort, >- OVS_VPORT_TYPE_VXLAN); >- if (tunnelVport) { >- ovsActionStats.rxVxlan++; >- } >- } else if (!flowKey->ipKey.nwFrag && >- flowKey->ipKey.nwProto == IPPROTO_TCP) { >+ if (!flowKey->ipKey.nwFrag) { > UINT16 dstPort = htons(flowKey->ipKey.l4.tpDst); >- tunnelVport = >OvsFindTunnelVportByDstPort(ovsFwdCtx->switchContext, >- dstPort, >- OVS_VPORT_TYPE_STT); >- if (tunnelVport) { >- ovsActionStats.rxStt++; >+ switch (flowKey->ipKey.nwProto) { >+ case IPPROTO_GRE: >+ tunnelVport = >OvsFindTunnelVportByPortType(ovsFwdCtx->switchContext, >+ >OVS_VPORT_TYPE_GRE); >+ if (tunnelVport) { >+ ovsActionStats.rxGre++; >+ } >+ break; >+ case IPPROTO_TCP: >+ tunnelVport = >OvsFindTunnelVportByDstPort(ovsFwdCtx->switchContext, >+ dstPort, >+ >OVS_VPORT_TYPE_STT); >+ if (tunnelVport) { >+ ovsActionStats.rxStt++; >+ } >+ break; >+ case IPPROTO_UDP: >+ tunnelVport = >OvsFindTunnelVportByDstPort(ovsFwdCtx->switchContext, >+ dstPort, >+ >OVS_VPORT_TYPE_VXLAN); >+ if (tunnelVport) { >+ ovsActionStats.rxVxlan++; >+ } >+ break; > } > } > >- > // We might get tunnel packets even before the tunnel gets >initialized. > if (tunnelVport) { > ASSERT(ovsFwdCtx->tunnelRxNic == NULL); >@@ -306,6 +317,9 @@ OvsDetectTunnelPkt(OvsForwardingContext *ovsFwdCtx, > /* Tunnel the packet only if tunnel context is set. */ > if (ovsFwdCtx->tunKey.dst != 0) { > switch(dstVport->ovsType) { >+ case OVS_VPORT_TYPE_GRE: >+ ovsActionStats.txGre++; >+ break; > case OVS_VPORT_TYPE_VXLAN: > ovsActionStats.txVxlan++; > break; >@@ -652,6 +666,11 @@ OvsTunnelPortTx(OvsForwardingContext *ovsFwdCtx) > > /* Do the encap. Encap function does not consume the NBL. */ > switch(ovsFwdCtx->tunnelTxNic->ovsType) { >+ case OVS_VPORT_TYPE_GRE: >+ status = OvsEncapGre(ovsFwdCtx->tunnelTxNic, ovsFwdCtx->curNbl, >+ &ovsFwdCtx->tunKey, >ovsFwdCtx->switchContext, >+ &ovsFwdCtx->layers, &newNbl); >+ break; > case OVS_VPORT_TYPE_VXLAN: > status = OvsEncapVxlan(ovsFwdCtx->tunnelTxNic, ovsFwdCtx->curNbl, > &ovsFwdCtx->tunKey, >ovsFwdCtx->switchContext, >@@ -724,6 +743,10 @@ OvsTunnelPortRx(OvsForwardingContext *ovsFwdCtx) > */ > > switch(tunnelRxVport->ovsType) { >+ case OVS_VPORT_TYPE_GRE: >+ status = OvsDecapGre(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl, >+ &ovsFwdCtx->tunKey, &newNbl); >+ break; > case OVS_VPORT_TYPE_VXLAN: > status = OvsDecapVxlan(ovsFwdCtx->switchContext, >ovsFwdCtx->curNbl, > &ovsFwdCtx->tunKey, &newNbl); >diff --git a/datapath-windows/ovsext/Gre.c b/datapath-windows/ovsext/Gre.c >new file mode 100644 >index 0000000..de914be >--- /dev/null >+++ b/datapath-windows/ovsext/Gre.c >@@ -0,0 +1,456 @@ >+/* >+ * Copyright (c) 2015 Cloudbase Solutions Srl >+ * >+ * 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=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=D >cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-lbhauUks_UnSyw6KxJOowOdmM >Yr-jCKUEPWSJuQ&s=USxahQvNwjOnvM2lnXoJw3Uy8JlTur3IYjRfI49-zZM&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 "Checksum.h" >+#include "Flow.h" >+#include "Gre.h" >+#include "IpHelper.h" >+#include "NetProto.h" >+#include "PacketIO.h" >+#include "PacketParser.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_GRE >+#include "Debug.h" >+ >+static NDIS_STATUS >+OvsDoEncapGre(POVS_VPORT_ENTRY vport, PNET_BUFFER_LIST curNbl, >+ const OvsIPv4TunnelKey *tunKey, >+ const POVS_FWD_INFO fwdInfo, >+ POVS_PACKET_HDR_INFO layers, >+ POVS_SWITCH_CONTEXT switchContext, >+ PNET_BUFFER_LIST *newNbl); >+ >+/* >+ * >-------------------------------------------------------------------------- >+ * OvsInitGreTunnel -- >+ * Initialize GRE tunnel module. >+ * >-------------------------------------------------------------------------- >+ */ >+NTSTATUS >+OvsInitGreTunnel(POVS_VPORT_ENTRY vport, >+ UINT16 udpDestPort) >+{ >+ POVS_GRE_VPORT grePort; >+ >+ grePort = (POVS_GRE_VPORT)OvsAllocateMemoryWithTag(sizeof(*grePort), >+ OVS_GRE_POOL_TAG); >+ if (!grePort) { >+ OVS_LOG_ERROR("Insufficient memory, can't allocate >OVS_GRE_VPORT"); >+ return STATUS_INSUFFICIENT_RESOURCES; >+ } >+ >+ RtlZeroMemory(grePort, sizeof(*grePort)); >+ grePort->dstPort = udpDestPort; >+ vport->priv = (PVOID)grePort; >+ return STATUS_SUCCESS; >+} >+ >+/* >+ * >-------------------------------------------------------------------------- >+ * OvsCleanupGreTunnel -- >+ * Cleanup GRE Tunnel module. >+ * >-------------------------------------------------------------------------- >+ */ >+void >+OvsCleanupGreTunnel(POVS_VPORT_ENTRY vport) >+{ >+ if (vport->ovsType != OVS_VPORT_TYPE_GRE || >+ vport->priv == NULL) { >+ return; >+ } >+ >+ OvsFreeMemoryWithTag(vport->priv, OVS_GRE_POOL_TAG); >+ vport->priv = NULL; >+} >+ >+/* >+ * >-------------------------------------------------------------------------- >+ * OvsEncapGre -- >+ * Encapsulates a packet with an GRE header. >+ * >-------------------------------------------------------------------------- >+ */ >+NDIS_STATUS >+OvsEncapGre(POVS_VPORT_ENTRY vport, >+ PNET_BUFFER_LIST curNbl, >+ OvsIPv4TunnelKey *tunKey, >+ POVS_SWITCH_CONTEXT switchContext, >+ POVS_PACKET_HDR_INFO layers, >+ PNET_BUFFER_LIST *newNbl) >+{ >+ OVS_FWD_INFO fwdInfo; >+ NDIS_STATUS status; >+ switchContext isn¹t an UNREFERENCED_PARAMTER in this case: >+ UNREFERENCED_PARAMETER(switchContext); >+ status = OvsLookupIPFwdInfo(tunKey->dst, &fwdInfo); >+ if (status != STATUS_SUCCESS) { >+ OvsFwdIPHelperRequest(NULL, 0, tunKey, NULL, NULL, NULL); >+ return NDIS_STATUS_FAILURE; >+ } >+ >+ status = OvsDoEncapGre(vport, curNbl, tunKey, &fwdInfo, layers, >+ switchContext, newNbl); >+ return status; >+} >+ >+/* >+ * >-------------------------------------------------------------------------- >+ * OvsDoEncapGre -- >+ * Internal utility function which actually does the GRE encap. >+ * >-------------------------------------------------------------------------- >+ */ >+NDIS_STATUS >+OvsDoEncapGre(POVS_VPORT_ENTRY vport, >+ PNET_BUFFER_LIST curNbl, >+ const OvsIPv4TunnelKey *tunKey, >+ const POVS_FWD_INFO fwdInfo, >+ POVS_PACKET_HDR_INFO layers, >+ POVS_SWITCH_CONTEXT switchContext, >+ PNET_BUFFER_LIST *newNbl) >+{ >+ NDIS_STATUS status; >+ PNET_BUFFER curNb; >+ PMDL curMdl; >+ PUINT8 bufferStart; >+ EthHdr *ethHdr; >+ IPHdr *ipHdr; >+ PGREHdr greHdr; >+ POVS_GRE_VPORT vportGre; >+ UINT32 headRoom = GreTunHdrSize(tunKey->flags); Do we still need the if-dgb check? >+#if DBG >+ UINT32 counterHeadRoom; >+#endif >+ UINT32 packetLength; >+ >+ curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); >+ packetLength = NET_BUFFER_DATA_LENGTH(curNb); >+ >+ if (layers->isTcp) { >+ NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO tsoInfo; >+ >+ tsoInfo.Value = NET_BUFFER_LIST_INFO(curNbl, >+ >TcpLargeSendNetBufferListInfo); >+ OVS_LOG_TRACE("MSS %u packet len %u", tsoInfo.LsoV1Transmit.MSS, >+ packetLength); >+ if (tsoInfo.LsoV1Transmit.MSS) { >+ OVS_LOG_TRACE("l4Offset %d", layers->l4Offset); >+ *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers, >+ tsoInfo.LsoV1Transmit.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; >+ } >+ } >+ >+ vportGre = (POVS_GRE_VPORT)GetOvsVportPriv(vport); >+ ASSERT(vportGre); >+ >+ /* 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; >+ } >+ /* >+ * To this point we do not have VXLAN offloading. >+ * Apply defined checksums >+ */ >+ curNb = NET_BUFFER_LIST_FIRST_NB(*newNbl); >+ curMdl = NET_BUFFER_CURRENT_MDL(curNb); >+ bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, >+ >LowPagePriority); >+ if (!bufferStart) { >+ status = NDIS_STATUS_RESOURCES; >+ goto ret_error; >+ } >+ >+ NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo; >+ csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl, >+ >TcpIpChecksumNetBufferListInfo); >+ >+ bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb); >+ >+ if (layers->isIPv4) { >+ IPHdr *ip = (IPHdr *)(bufferStart + layers->l3Offset); >+ >+ if (csumInfo.Transmit.IpHeaderChecksum) { >+ ip->check = 0; >+ ip->check = IPChecksum((UINT8 *)ip, 4 * ip->ihl, 0); >+ } >+ >+ if (layers->isTcp && csumInfo.Transmit.TcpChecksum) { >+ UINT16 csumLength = (UINT16)(packetLength - >layers->l4Offset); >+ TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset); >+ tcp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr, >+ IPPROTO_TCP, csumLength); >+ tcp->check = CalculateChecksumNB(curNb, csumLength, >+ >(UINT32)(layers->l4Offset)); >+ } else if (layers->isUdp && csumInfo.Transmit.UdpChecksum) { >+ UINT16 csumLength = (UINT16)(packetLength - >layers->l4Offset); >+ UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip); >+ udp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr, >+ IPPROTO_UDP, csumLength); >+ udp->check = CalculateChecksumNB(curNb, csumLength, >+ >(UINT32)(layers->l4Offset)); >+ } >+ } else if (layers->isIPv6) { >+ IPv6Hdr *ip = (IPv6Hdr *)(bufferStart + layers->l3Offset); >+ >+ if (layers->isTcp && csumInfo.Transmit.TcpChecksum) { >+ UINT16 csumLength = (UINT16)(packetLength - >layers->l4Offset); >+ TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset); >+ tcp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr, >+ (UINT32 *) &ip->daddr, >+ IPPROTO_TCP, csumLength); >+ tcp->check = CalculateChecksumNB(curNb, csumLength, >+ >(UINT32)(layers->l4Offset)); >+ } else if (layers->isUdp && csumInfo.Transmit.UdpChecksum) { >+ UINT16 csumLength = (UINT16)(packetLength - >layers->l4Offset); >+ UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip); >+ udp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr, >+ (UINT32 *) &ip->daddr, >+ IPPROTO_UDP, csumLength); >+ udp->check = CalculateChecksumNB(curNb, csumLength, >+ >(UINT32)(layers->l4Offset)); >+ } >+ } >+ /* Clear out TcpIpChecksumNetBufferListInfo flag */ >+ NET_BUFFER_LIST_INFO(*newNbl, TcpIpChecksumNetBufferListInfo) = >0; >+ } >+ >+ curNbl = *newNbl; >+ for (curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); curNb != NULL; >+ curNb = curNb->Next) { >+#if DBG >+ counterHeadRoom = headRoom; >+#endif >+ 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); >+#if DBG >+ counterHeadRoom -= sizeof *ethHdr; >+#endif >+ >+ /* IP header */ >+ ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr); >+ >+ ipHdr->ihl = sizeof *ipHdr / 4; >+ ipHdr->version = IPPROTO_IPV4; >+ ipHdr->tos = tunKey->tos; I found the NET_BUFFER_DATA_LENGTH(curNb) command to erroneously return more bits than what was originally present. However, I couldn¹t find an alternative while implementing this in Stt.c. Since this is encap, it shouldn¹t be an issue. >+ ipHdr->tot_len = htons(NET_BUFFER_DATA_LENGTH(curNb) - sizeof >*ethHdr); >+ ipHdr->id = (uint16)atomic_add64(&vportGre->ipId, >+ NET_BUFFER_DATA_LENGTH(curNb)); >+ ipHdr->frag_off = (tunKey->flags & OVS_TNL_F_DONT_FRAGMENT) ? >+ IP_DF_NBO : 0; Can you define 64 as TUNNEL_DEFAULT_TTL and reuse it? >+ ipHdr->ttl = tunKey->ttl ? tunKey->ttl : 64; >+ ipHdr->protocol = IPPROTO_GRE; >+ ASSERT(tunKey->dst == fwdInfo->dstIpAddr); >+ ASSERT(tunKey->src == fwdInfo->srcIpAddr || tunKey->src == 0); >+ ipHdr->saddr = fwdInfo->srcIpAddr; >+ ipHdr->daddr = fwdInfo->dstIpAddr; >+ >+ ipHdr->check = 0; >+ ipHdr->check = IPChecksum((UINT8 *)ipHdr, sizeof *ipHdr, 0); >+#if DBG >+ counterHeadRoom -= sizeof *ipHdr; >+#endif >+ >+ /* GRE header */ >+ greHdr = (GREHdr *)((PCHAR)ipHdr + sizeof *ipHdr); >+ greHdr->flags = OvsTunnelFlagsToGreFlags(tunKey->flags); >+ greHdr->protocolType = GRE_NET_TEB; >+#if DBG >+ counterHeadRoom -= sizeof *greHdr; >+#endif >+ >+ PCHAR currentOffset = (PCHAR)greHdr + sizeof *greHdr; >+ >+ if (tunKey->flags & OVS_TNL_F_CSUM) { >+ RtlZeroMemory(currentOffset, 4); >+ currentOffset += 4; >+#if DBG >+ counterHeadRoom -= 4; >+#endif >+ } >+ >+ if (tunKey->flags & OVS_TNL_F_KEY) { >+ RtlZeroMemory(currentOffset, 4); >+ UINT32 key = (tunKey->tunnelId >> 32); >+ RtlCopyMemory(currentOffset, &key, sizeof key); >+ currentOffset += 4; >+#if DBG >+ counterHeadRoom -= 4; >+#endif >+ } >+ >+ if (tunKey->flags & OVS_TNL_F_SEQ) { >+ RtlZeroMemory(currentOffset, 4); >+ currentOffset += 4; >+#if DBG >+ counterHeadRoom -= 4; >+#endif >+ } >+ >+#if DBG >+ ASSERT(counterHeadRoom == 0); >+#endif >+ >+ } >+ return STATUS_SUCCESS; >+ >+ret_error: >+ OvsCompleteNBL(switchContext, *newNbl, TRUE); >+ *newNbl = NULL; >+ return status; >+} >+ >+NDIS_STATUS >+OvsDecapGre(POVS_SWITCH_CONTEXT switchContext, >+ PNET_BUFFER_LIST curNbl, >+ OvsIPv4TunnelKey *tunKey, >+ PNET_BUFFER_LIST *newNbl) >+{ >+ PNET_BUFFER curNb; >+ PMDL curMdl; >+ EthHdr *ethHdr; >+ IPHdr *ipHdr; >+ GREHdr *greHdr; >+ UINT32 tunnelSize = 0, packetLength = 0; >+ UINT32 headRoom = 0; >+ PUINT8 bufferStart; >+ NDIS_STATUS status; >+ >+ curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); >+ packetLength = NET_BUFFER_DATA_LENGTH(curNb); >+ tunnelSize = GreTunHdrSize(tunKey->flags); >+ 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 + OVS_DEFAULT_COPY_SIZE, 0, >+ TRUE /*copy NBL info */); >+ >+ if (*newNbl == NULL) { >+ return NDIS_STATUS_RESOURCES; >+ } >+ >+ 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; >+ headRoom += sizeof *ethHdr; >+ >+ 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; >+ headRoom += sizeof *ipHdr; >+ >+ greHdr = (GREHdr *)((PCHAR)ipHdr + sizeof *ipHdr); >+ headRoom += sizeof *greHdr; >+ >+ /* Validate if GRE header protocol type. */ >+ if (greHdr->protocolType != GRE_NET_TEB) { >+ status = STATUS_NDIS_INVALID_PACKET; >+ goto dropNbl; >+ } >+ >+ PCHAR currentOffset = (PCHAR)greHdr + sizeof *greHdr; >+ >+ if (greHdr->flags & GRE_CSUM) { >+ tunKey->flags |= OVS_TNL_F_CSUM; >+ currentOffset += 4; >+ headRoom += 4; >+ } >+ >+ if (greHdr->flags & GRE_KEY) { >+ tunKey->flags |= OVS_TNL_F_KEY; >+ UINT32 key = 0; >+ RtlCopyMemory(&key, currentOffset, 4); >+ tunKey->tunnelId = (UINT64)key << 32; >+ currentOffset += 4; >+ headRoom += 4; >+ } >+ >+ if (greHdr->flags & GRE_SEQ) { >+ tunKey->flags |= OVS_TNL_F_SEQ; >+ currentOffset += 4; >+ headRoom += 4; >+ } >+ >+ /* Clear out the receive flag for the inner packet. */ >+ NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo) = 0; >+ NdisAdvanceNetBufferDataStart(curNb, GreTunHdrSize(tunKey->flags), >FALSE, >+ NULL); >+ ASSERT(headRoom == GreTunHdrSize(tunKey->flags)); >+ return NDIS_STATUS_SUCCESS; >+ >+dropNbl: >+ OvsCompleteNBL(switchContext, *newNbl, TRUE); >+ *newNbl = NULL; >+ return status; >+} >diff --git a/datapath-windows/ovsext/Gre.h b/datapath-windows/ovsext/Gre.h >new file mode 100644 >index 0000000..71ff05e >--- /dev/null >+++ b/datapath-windows/ovsext/Gre.h >@@ -0,0 +1,113 @@ >+/* >+ * Copyright (c) 2015 Cloudbase Solutions Srl >+ * >+ * 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=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=D >cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-lbhauUks_UnSyw6KxJOowOdmM >Yr-jCKUEPWSJuQ&s=USxahQvNwjOnvM2lnXoJw3Uy8JlTur3IYjRfI49-zZM&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 __GRE_H_ >+#define __GRE_H_ 1 >+ >+#include "NetProto.h" >+#include "Flow.h" >+ >+typedef struct _OVS_GRE_VPORT { >+ UINT16 dstPort; >+ UINT64 inPkts; >+ UINT64 outPkts; >+ UINT64 slowInPkts; >+ UINT64 slowOutPkts; Can call this filterId to keep things consistent- >+ UINT64 filterID; >+ UINT64 ipId; >+ /* >+ * To be filled >+ */ >+} OVS_GRE_VPORT, *POVS_GRE_VPORT; >+ >+ >+/* GRE RFC 2890 header based on >https://urldefense.proofpoint.com/v2/url?u=http-3A__tools.ietf.org_html_rf >c2890&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dcruz40PROJ >40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-lbhauUks_UnSyw6KxJOowOdmMYr-jCKUEPW >SJuQ&s=nJEtVHbdSVVYPTPVjZUZbaEWG2D7lx0u5y6VpKCbbGM&e= >+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ * |C| |K|S| Reserved0 | Ver | Protocol Type | >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ * | Checksum (optional) | Reserved1 (Optional) | >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ * | Key (optional) | >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ * | Sequence Number (Optional) | >+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ >+ */ >+ >+typedef struct GREHdr { >+ UINT16 flags; >+ UINT16 protocolType; >+} GREHdr, *PGREHdr; >+ >+/* Transparent Ethernet Bridging */ >+#define GRE_NET_TEB 0x5865 >+/* GRE Flags*/ >+#define GRE_CSUM 0x0080 >+#define GRE_KEY 0x0020 >+#define GRE_SEQ 0x0010 >+ >+NTSTATUS OvsInitGreTunnel(POVS_VPORT_ENTRY vport, >+ UINT16 udpDestPort); >+ >+VOID OvsCleanupGreTunnel(POVS_VPORT_ENTRY vport); >+ >+ >+void OvsCleanupGreTunnel(POVS_VPORT_ENTRY vport); >+ >+NDIS_STATUS OvsEncapGre(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 OvsDecapGre(POVS_SWITCH_CONTEXT switchContext, >+ PNET_BUFFER_LIST curNbl, >+ OvsIPv4TunnelKey *tunKey, >+ PNET_BUFFER_LIST *newNbl); >+ >+static __inline UINT16 >+OvsTunnelFlagsToGreFlags(UINT16 tunnelflags) >+{ >+ UINT16 flags = 0; >+ >+ if (tunnelflags & OVS_TNL_F_CSUM) >+ flags |= GRE_CSUM; >+ >+ if (tunnelflags & OVS_TNL_F_KEY) >+ flags |= GRE_KEY; >+ >+ if (tunnelflags & OVS_TNL_F_SEQ) >+ flags |= GRE_SEQ; >+ >+ return flags; >+} >+ >+static __inline UINT32 >+GreTunHdrSize(UINT16 flags) >+{ >+ UINT32 sum = sizeof(EthHdr) + sizeof(IPHdr) + sizeof(GREHdr); >+ sum += (flags & OVS_TNL_F_CSUM) ? >+ 4 : 0; >+ sum += (flags & OVS_TNL_F_KEY) ? >+ 4 : 0; >+ sum += (flags & OVS_TNL_F_SEQ) ? >+ 4 : 0; >+ >+ return sum; >+} >+ >+#endif /*__GRE_H_ */ >diff --git a/datapath-windows/ovsext/Util.h >b/datapath-windows/ovsext/Util.h >index e5ba72b..a81c723 100644 >--- a/datapath-windows/ovsext/Util.h >+++ b/datapath-windows/ovsext/Util.h >@@ -34,6 +34,7 @@ > #define OVS_USER_POOL_TAG 'USVO' > #define OVS_VPORT_POOL_TAG 'PSVO' > #define OVS_STT_POOL_TAG 'RSVO' >+#define OVS_GRE_POOL_TAG 'GSVO' > #define OVS_TUNFLT_POOL_TAG 'WSVO' > > VOID *OvsAllocateMemory(size_t size); >diff --git a/datapath-windows/ovsext/Vport.c >b/datapath-windows/ovsext/Vport.c >index a7576d3..11737a8 100644 >--- a/datapath-windows/ovsext/Vport.c >+++ b/datapath-windows/ovsext/Vport.c >@@ -15,16 +15,18 @@ > */ > > #include "precomp.h" >+ >+#include "Datapath.h" >+#include "Event.h" >+#include "Gre.h" >+#include "IpHelper.h" > #include "Jhash.h" >+#include "Oid.h" >+#include "Stt.h" > #include "Switch.h" >-#include "Vport.h" >-#include "Event.h" > #include "User.h" >+#include "Vport.h" > #include "Vxlan.h" >-#include "Stt.h" >-#include "IpHelper.h" >-#include "Oid.h" >-#include "Datapath.h" > > #ifdef OVS_DBG_MOD > #undef OVS_DBG_MOD >@@ -700,6 +702,26 @@ OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT >switchContext, > return NULL; > } > >+POVS_VPORT_ENTRY >+OvsFindTunnelVportByPortType(POVS_SWITCH_CONTEXT switchContext, >+ OVS_VPORT_TYPE ovsPortType) >+{ >+ POVS_VPORT_ENTRY vport; >+ PLIST_ENTRY head, link; >+ UINT16 dstPort = 0; >+ UINT32 hash = OvsJhashBytes((const VOID *)&dstPort, sizeof(dstPort), >+ OVS_HASH_BASIS); >+ head = &(switchContext->tunnelVportsArray[hash & OVS_VPORT_MASK]); >+ LIST_FORALL(head, link) { >+ vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, >tunnelVportLink); >+ if (vport->ovsType == ovsPortType) { >+ return vport; >+ } >+ } >+ return NULL; >+} >+ >+ > > POVS_VPORT_ENTRY > OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext, >@@ -983,6 +1005,7 @@ OvsInitTunnelVport(PVOID userContext, > vport->ovsState = OVS_STATE_PORT_CREATED; > switch (ovsType) { > case OVS_VPORT_TYPE_GRE: >+ status = OvsInitGreTunnel(vport, dstPort); > break; > case OVS_VPORT_TYPE_VXLAN: > { >@@ -1153,6 +1176,7 @@ InitOvsVportCommon(POVS_SWITCH_CONTEXT >switchContext, > UINT32 hash; > > switch(vport->ovsType) { >+ case OVS_VPORT_TYPE_GRE: > case OVS_VPORT_TYPE_VXLAN: > case OVS_VPORT_TYPE_STT: > { >@@ -1242,6 +1266,7 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext, > OvsCleanupSttTunnel(vport); > break; > case OVS_VPORT_TYPE_GRE: >+ OvsCleanupGreTunnel(vport); > break; > case OVS_VPORT_TYPE_NETDEV: > if (vport->isExternal) { >@@ -1299,7 +1324,8 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext, > RemoveEntryList(&vport->portNoLink); > InitializeListHead(&vport->portNoLink); > if (OVS_VPORT_TYPE_VXLAN == vport->ovsType || >- OVS_VPORT_TYPE_STT == vport->ovsType) { >+ OVS_VPORT_TYPE_STT == vport->ovsType || >+ OVS_VPORT_TYPE_GRE == vport->ovsType) { > RemoveEntryList(&vport->tunnelVportLink); > InitializeListHead(&vport->tunnelVportLink); > } >@@ -2190,6 +2216,9 @@ OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT >usrParamsCtx, > UINT16 transportPortDest = 0; > > switch (portType) { >+ case OVS_VPORT_TYPE_GRE: >+ OvsCleanupGreTunnel(vport); >+ break; > case OVS_VPORT_TYPE_VXLAN: > transportPortDest = VXLAN_UDP_PORT; > break; >diff --git a/datapath-windows/ovsext/Vport.h >b/datapath-windows/ovsext/Vport.h >index e9f3b03..b11cf79 100644 >--- a/datapath-windows/ovsext/Vport.h >+++ b/datapath-windows/ovsext/Vport.h >@@ -17,9 +17,10 @@ > #ifndef __VPORT_H_ > #define __VPORT_H_ 1 > >+#include "Gre.h" >+#include "Stt.h" > #include "Switch.h" > #include "VxLan.h" >-#include "Stt.h" > > #define OVS_MAX_DPPORTS MAXUINT16 > #define OVS_DPPORT_NUMBER_INVALID OVS_MAX_DPPORTS >@@ -147,6 +148,8 @@ POVS_VPORT_ENTRY >OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchConte > POVS_VPORT_ENTRY OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT >switchContext, > UINT16 dstPort, > OVS_VPORT_TYPE >ovsVportType); >+POVS_VPORT_ENTRY OvsFindTunnelVportByPortType(POVS_SWITCH_CONTEXT >switchContext, >+ OVS_VPORT_TYPE >ovsPortType); > > NDIS_STATUS OvsAddConfiguredSwitchPorts(struct _OVS_SWITCH_CONTEXT >*switchContext); > NDIS_STATUS OvsInitConfiguredSwitchNics(struct _OVS_SWITCH_CONTEXT >*switchContext); >@@ -256,16 +259,19 @@ GetPortFromPriv(POVS_VPORT_ENTRY vport) > /* XXX would better to have a commom tunnel "parent" structure */ > ASSERT(vportPriv); > switch(vport->ovsType) { >- case OVS_VPORT_TYPE_VXLAN: >- dstPort = ((POVS_VXLAN_VPORT)vportPriv)->dstPort; >+ case OVS_VPORT_TYPE_GRE: >+ dstPort = ((POVS_GRE_VPORT)vportPriv)->dstPort; > break; > case OVS_VPORT_TYPE_STT: > dstPort = ((POVS_STT_VPORT)vportPriv)->dstPort; > break; >+ case OVS_VPORT_TYPE_VXLAN: >+ dstPort = ((POVS_VXLAN_VPORT)vportPriv)->dstPort; >+ break; > default: > ASSERT(! "Port is not a tunnel port"); > } >- ASSERT(dstPort); >+ ASSERT(dstPort || vport->ovsType == OVS_VPORT_TYPE_GRE); > return dstPort; > } > >diff --git a/datapath-windows/ovsext/ovsext.vcxproj >b/datapath-windows/ovsext/ovsext.vcxproj >index 616f688..231ac83 100644 >--- a/datapath-windows/ovsext/ovsext.vcxproj >+++ b/datapath-windows/ovsext/ovsext.vcxproj >@@ -80,6 +80,7 @@ > <ClInclude Include="Ethernet.h" /> > <ClInclude Include="Event.h" /> > <ClInclude Include="Flow.h" /> >+ <ClInclude Include="Gre.h" /> > <ClInclude Include="IpHelper.h" /> > <ClInclude Include="Jhash.h" /> > <ClInclude Include="Netlink/Netlink.h" /> >@@ -172,6 +173,7 @@ > <ClCompile Include="Driver.c" /> > <ClCompile Include="Event.c" /> > <ClCompile Include="Flow.c" /> >+ <ClCompile Include="Gre.c" /> > <ClCompile Include="IpHelper.c" /> > <ClCompile Include="Jhash.c" /> > <ClCompile Include="Netlink/Netlink.c" /> >-- >1.9.5.msysgit.0 >_______________________________________________ >dev mailing list >dev@openvswitch.org >https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailma >n_listinfo_dev&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dc >ruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-lbhauUks_UnSyw6KxJOowOdmMY >r-jCKUEPWSJuQ&s=GWOuuSDXOUhTiBbHBfRkPrQuu0uy5JAuevHIKxNwDsc&e= _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev