[ovs-dev] [PATCH 3/3] datapath-windows: Add GRE TEB support for windows datapath

Alin Serdean aserdean at cloudbasesolutions.com
Fri Dec 11 15:31:34 UTC 2015


Thanks for the review Sai.

Regarding the DBG check I want to verify that the length gets consumed in debug mode and not for release as well.

I will incorporate your comments in v3.

> -----Mesaj original-----
> De la: Sairam Venugopal [mailto:vsairam at vmware.com]
> Trimis: Wednesday, December 2, 2015 10:25 PM
> Către: Alin Serdean <aserdean at cloudbasesolutions.com>;
> dev at openvswitch.org
> Subiect: Re: [ovs-dev] [PATCH 3/3] datapath-windows: Add GRE TEB support
> for windows datapath
> 
> 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" <aserdean at 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=Dcruz40P
> >ROJ
> >40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-
> lbhauUks_UnSyw6KxJOowOdmMYr-jCKU
> >EPW 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=Sqcl0Ez6M0X8aeM67LKIiDJAX
> >VeA
> >w-YihVMNtXt-
> uEs&r=Dcruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-lbh
> >auU
> >ks_UnSyw6KxJOowOdmMYr-
> jCKUEPWSJuQ&s=zRPkfIHroZtzdBG9Ra3sIfgFd-CYLaPUWfd
> >lN4
> >ik_xg&e= )
> >              (ICMP, TCP, UDP) with various packet lengths
> >              IPERF3
> >
> >(https://urldefense.proofpoint.com/v2/url?u=https-3A__iperf.fr_iperf-2D
> >dow
> >nload.php&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-
> uEs&r=Dcru
> >z40
> >PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-
> lbhauUks_UnSyw6KxJOowOdmMYr-
> >jCK UEPWSJuQ&s=0nEEutWRlVJKJzQXNE7K6RNl3lE-K6DKKb3vDLPEjwk&e= )
> >              (TCP, UDP) with various options
> >
> >Signed-off-by: Alin Gabriel Serdean <aserdean at 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_lice
> >nse
> >s_LICENSE-2D2.0&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-
> YihVMNtXt-uEs&
> >r=D
> >cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-
> lbhauUks_UnSyw6KxJOowO
> >dmM 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_lice
> >nse
> >s_LICENSE-2D2.0&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-
> YihVMNtXt-uEs&
> >r=D
> >cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-
> lbhauUks_UnSyw6KxJOowO
> >dmM 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=Dcruz40P
> >ROJ
> >40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-
> lbhauUks_UnSyw6KxJOowOdmMYr-jCKU
> >EPW 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 at openvswitch.org
> >https://urldefense.proofpoint.com/v2/url?u=http-
> 3A__openvswitch.org_mai
> >lma
> >n_listinfo_dev&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-
> YihVMNtXt-uEs&r
> >=Dc
> >ruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=hKn-
> lbhauUks_UnSyw6KxJOowOd
> >mMY r-
> jCKUEPWSJuQ&s=GWOuuSDXOUhTiBbHBfRkPrQuu0uy5JAuevHIKxNwDsc&e
> =





More information about the dev mailing list