[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