[ovs-dev] [PATCH v4 1/6] datapath-windows: Added recirculation support.
Sairam Venugopal
vsairam at vmware.com
Wed Mar 9 23:15:32 UTC 2016
Hi Alin/Sorin,
The OvsDoRecircFlowLookupOutput function currently assumes that the
srcVport is always the Internal VPort. It also does not distinguish
between Receive vs Transmit in the OvsCreateAndAddPackets call.
Shouldn¹t the source VPORT point to the actual source VPORT instead of the
InternalVport? It seems like this function mimics the
OvsDoFlowLookupOutput without modifying the logic.
Thanks,
Sairam
On 3/7/16, 5:05 PM, "Alin Serdean" <aserdean at cloudbasesolutions.com> wrote:
>Recirculation support for the OVS extension.
>
>Tested using PING and iperf with Driver Verifier enabled.
>
>Signed-off-by: Sorin Vinturis <svinturis at cloudbasesolutions.com>
>Co-authored-by: Alin Gabriel Serdean <aserdean at cloudbasesolutions.com>
>Reported-by: Sorin Vinturis <svinturis at cloudbasesolutions.com>
>Reported-at:
>https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_openvswitc
>h_ovs-2Dissues_issues_104&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNt
>Xt-uEs&r=Dcruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=zX0Ryyebl5fXG0lRkFO
>-Q6W5UdQPxxNlGC175uYMUbg&s=VAhMByQWum0zcE6u0R03R-mIyQNrhfns6A572Eo4CPI&e=
>---
>v2: Initialize flow key before using it.
>v3: Synchronized access to deferred actions queue.
>v4: Address comments.
>---
> datapath-windows/automake.mk | 3 +
> datapath-windows/ovsext/Actions.c | 224
>+++++++++++++++++++++++++++---
> datapath-windows/ovsext/Actions.h | 54 +++++++
> datapath-windows/ovsext/Datapath.c | 4 +
> datapath-windows/ovsext/DpInternal.h | 2 +-
> datapath-windows/ovsext/Flow.c | 76 ++++++++--
> datapath-windows/ovsext/Flow.h | 5 +-
> datapath-windows/ovsext/Netlink/Netlink.h | 11 ++
> datapath-windows/ovsext/PacketIO.c | 16 ++-
> datapath-windows/ovsext/PacketIO.h | 10 --
> datapath-windows/ovsext/Recirc.c | 171 +++++++++++++++++++++++
> datapath-windows/ovsext/Recirc.h | 82 +++++++++++
> datapath-windows/ovsext/Tunnel.c | 15 +-
> datapath-windows/ovsext/User.c | 13 +-
> datapath-windows/ovsext/ovsext.vcxproj | 3 +
> 15 files changed, 623 insertions(+), 66 deletions(-)
> create mode 100644 datapath-windows/ovsext/Actions.h
> create mode 100644 datapath-windows/ovsext/Recirc.c
> create mode 100644 datapath-windows/ovsext/Recirc.h
>
>diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk
>index f29f548..04fc97f 100644
>--- a/datapath-windows/automake.mk
>+++ b/datapath-windows/automake.mk
>@@ -9,6 +9,7 @@ EXTRA_DIST += \
> datapath-windows/misc/uninstall.cmd \
> datapath-windows/ovsext.sln \
> datapath-windows/ovsext/Actions.c \
>+ datapath-windows/ovsext/Actions.h \
> datapath-windows/ovsext/Atomic.h \
> datapath-windows/ovsext/BufferMgmt.c \
> datapath-windows/ovsext/BufferMgmt.h \
>@@ -45,6 +46,8 @@ EXTRA_DIST += \
> datapath-windows/ovsext/PacketIO.h \
> datapath-windows/ovsext/PacketParser.c \
> datapath-windows/ovsext/PacketParser.h \
>+ datapath-windows/ovsext/Recirc.c \
>+ datapath-windows/ovsext/Recirc.h \
> datapath-windows/ovsext/Stt.c \
> datapath-windows/ovsext/Stt.h \
> datapath-windows/ovsext/Switch.c \
>diff --git a/datapath-windows/ovsext/Actions.c
>b/datapath-windows/ovsext/Actions.c
>index 5a04541..e2d4ba8 100644
>--- a/datapath-windows/ovsext/Actions.c
>+++ b/datapath-windows/ovsext/Actions.c
>@@ -16,6 +16,7 @@
>
> #include "precomp.h"
>
>+#include "Actions.h"
> #include "Debug.h"
> #include "Event.h"
> #include "Flow.h"
>@@ -24,6 +25,7 @@
> #include "NetProto.h"
> #include "Offload.h"
> #include "PacketIO.h"
>+#include "Recirc.h"
> #include "Stt.h"
> #include "Switch.h"
> #include "User.h"
>@@ -35,6 +37,8 @@
> #endif
> #define OVS_DBG_MOD OVS_DBG_ACTION
>
>+#define OVS_DEST_PORTS_ARRAY_MIN_SIZE 2
>+
> typedef struct _OVS_ACTION_STATS {
> UINT64 rxGre;
> UINT64 txGre;
>@@ -66,7 +70,6 @@ OVS_ACTION_STATS ovsActionStats;
> * exercised while adding new members to the structure - only add ones
>that get
> * used across multiple stages in the pipeline/get used in multiple
>functions.
> */
>-#define OVS_DEST_PORTS_ARRAY_MIN_SIZE 2
> typedef struct OvsForwardingContext {
> POVS_SWITCH_CONTEXT switchContext;
> /* The NBL currently used in the pipeline. */
>@@ -99,7 +102,7 @@ typedef struct OvsForwardingContext {
> */
> OvsIPv4TunnelKey tunKey;
>
>- /*
>+ /*
> * Tunneling - Tx:
> * To store the output port, when it is a tunneled port. We don't
>foresee
> * multiple tunneled ports as outport for any given NBL.
>@@ -117,7 +120,6 @@ typedef struct OvsForwardingContext {
> OVS_PACKET_HDR_INFO layers;
> } OvsForwardingContext;
>
>-
> /*
> *
>--------------------------------------------------------------------------
> * OvsInitForwardingCtx --
>@@ -564,10 +566,10 @@ OvsCompleteNBLForwardingCtx(OvsForwardingContext
>*ovsFwdCtx,
> static __inline NDIS_STATUS
> OvsDoFlowLookupOutput(OvsForwardingContext *ovsFwdCtx)
> {
>- OvsFlowKey key;
>- OvsFlow *flow;
>- UINT64 hash;
>- NDIS_STATUS status;
>+ OvsFlowKey key = { 0 };
>+ OvsFlow *flow = NULL;
>+ UINT64 hash = 0;
>+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
> POVS_VPORT_ENTRY vport =
> OvsFindVportByPortNo(ovsFwdCtx->switchContext,
>ovsFwdCtx->srcVportNo);
> if (vport == NULL || vport->ovsState != OVS_STATE_CONNECTED) {
>@@ -595,11 +597,13 @@ OvsDoFlowLookupOutput(OvsForwardingContext
>*ovsFwdCtx)
> if (flow) {
> OvsFlowUsed(flow, ovsFwdCtx->curNbl, &ovsFwdCtx->layers);
> ovsFwdCtx->switchContext->datapath.hits++;
>- status = OvsActionsExecute(ovsFwdCtx->switchContext,
>- ovsFwdCtx->completionList,
>ovsFwdCtx->curNbl,
>- ovsFwdCtx->srcVportNo,
>ovsFwdCtx->sendFlags,
>- &key, &hash, &ovsFwdCtx->layers,
>- flow->actions, flow->actionsLen);
>+ status = OvsDoExecuteActions(ovsFwdCtx->switchContext,
>+ ovsFwdCtx->completionList,
>+ ovsFwdCtx->curNbl,
>+ ovsFwdCtx->srcVportNo,
>+ ovsFwdCtx->sendFlags,
>+ &key, &hash, &ovsFwdCtx->layers,
>+ flow->actions, flow->actionsLen);
> ovsFwdCtx->curNbl = NULL;
> } else {
> LIST_ENTRY missedPackets;
>@@ -1520,7 +1524,58 @@ OvsExecuteSetAction(OvsForwardingContext
>*ovsFwdCtx,
>
> /*
> *
>--------------------------------------------------------------------------
>- * OvsActionsExecute --
>+ * OvsActionExecuteRecirc --
>+ * The function adds a deferred action to allow the current packet,
>nbl,
>+ * to re-enter datapath packet processing.
>+ *
>--------------------------------------------------------------------------
>+ */
>+NTSTATUS
>+OvsActionExecuteRecirc(POVS_SWITCH_CONTEXT switchContext,
>+ PNET_BUFFER_LIST nbl,
>+ OvsFlowKey *key,
>+ UINT64 *hashAction,
>+ const PNL_ATTR actions,
>+ int rem)
>+{
>+ POVS_DEFERRED_ACTION deferredAction = NULL;
>+ PNET_BUFFER_LIST newNbl = NULL;
>+ UINT64 hash = 0;
>+
>+ if (!NlAttrIsLast(actions, rem)) {
>+ /*
>+ * Recirc action is the not the last action of the action list,
>so we
>+ * need to clone the packet.
>+ */
>+ newNbl = OvsPartialCopyNBL(switchContext, nbl,
>+ 0, 0, TRUE /*copy NBL info*/);
>+ /*
>+ * Skip the recirc action when out of memory, but continue on
>with the
>+ * rest of the action list.
>+ */
>+ if (newNbl == NULL) {
>+ ovsActionStats.noCopiedNbl++;
>+ return STATUS_SUCCESS;
>+ }
>+ nbl = newNbl;
>+ }
>+
>+ hash = hashAction ? *hashAction : OvsHashFlow(key);
>+
>+ deferredAction = OvsAddDeferredActions(nbl, key, hash, NULL);
>+ if (deferredAction) {
>+ deferredAction->key.recircId = NlAttrGetU32(actions);
>+ } else {
>+ if (newNbl) {
>+ OvsCompleteNBL(switchContext, newNbl, TRUE);
>+ }
>+ }
>+
>+ return STATUS_SUCCESS;
>+}
>+
>+/*
>+ *
>--------------------------------------------------------------------------
>+ * OvsDoExecuteActions --
> * Interpret and execute the specified 'actions' on the specifed
>packet
> * 'curNbl'. The expectation is that if the packet needs to be
>dropped
> * (completed) for some reason, it is added to 'completionList' so
>that the
>@@ -1537,16 +1592,16 @@ OvsExecuteSetAction(OvsForwardingContext
>*ovsFwdCtx,
> *
>--------------------------------------------------------------------------
> */
> NDIS_STATUS
>-OvsActionsExecute(POVS_SWITCH_CONTEXT switchContext,
>- OvsCompletionList *completionList,
>- PNET_BUFFER_LIST curNbl,
>- UINT32 portNo,
>- ULONG sendFlags,
>- OvsFlowKey *key,
>- UINT64 *hash,
>- OVS_PACKET_HDR_INFO *layers,
>- const PNL_ATTR actions,
>- INT actionsLen)
>+OvsDoExecuteActions(POVS_SWITCH_CONTEXT switchContext,
>+ OvsCompletionList *completionList,
>+ PNET_BUFFER_LIST curNbl,
>+ UINT32 portNo,
>+ ULONG sendFlags,
>+ OvsFlowKey *key,
>+ UINT64 *hash,
>+ OVS_PACKET_HDR_INFO *layers,
>+ const PNL_ATTR actions,
>+ INT actionsLen)
> {
> PNL_ATTR a;
> INT rem;
>@@ -1695,6 +1750,31 @@ OvsActionsExecute(POVS_SWITCH_CONTEXT
>switchContext,
> break;
> }
>
>+ case OVS_ACTION_ATTR_RECIRC:
>+ {
>+ if (ovsFwdCtx.destPortsSizeOut > 0 || ovsFwdCtx.tunnelTxNic
>!= NULL
>+ || ovsFwdCtx.tunnelRxNic != NULL) {
>+ status = OvsOutputBeforeSetAction(&ovsFwdCtx);
>+ if (status != NDIS_STATUS_SUCCESS) {
>+ dropReason = L"OVS-adding destination failed";
>+ goto dropit;
>+ }
>+ }
>+
>+ status = OvsActionExecuteRecirc(ovsFwdCtx.switchContext,
>+ ovsFwdCtx.curNbl, key, hash,
>+ (const PNL_ATTR)a, rem);
>+ if (status != NDIS_STATUS_SUCCESS) {
>+ dropReason = L"OVS-recirculation action failed";
>+ goto dropit;
>+ }
>+
>+ if (NlAttrIsLast(a, rem)) {
>+ goto exit;
>+ }
>+ break;
>+ }
>+
> case OVS_ACTION_ATTR_USERSPACE:
> {
> PNL_ATTR userdataAttr;
>@@ -1781,5 +1861,103 @@ dropit:
> OvsCompleteNBLForwardingCtx(&ovsFwdCtx, dropReason);
> }
>
>+exit:
>+ return status;
>+}
>+
>+NDIS_STATUS
>+OvsActionsExecute(POVS_SWITCH_CONTEXT switchContext,
>+ OvsCompletionList *completionList,
>+ PNET_BUFFER_LIST curNbl,
>+ UINT32 portNo,
>+ ULONG sendFlags,
>+ OvsFlowKey *key,
>+ UINT64 *hash,
>+ OVS_PACKET_HDR_INFO *layers,
>+ const PNL_ATTR actions,
>+ INT actionsLen)
>+{
>+ NDIS_STATUS status = STATUS_SUCCESS;
>+
>+ status = OvsDoExecuteActions(switchContext, completionList, curNbl,
>+ portNo, sendFlags, key, hash, layers,
>+ actions, actionsLen);
>+
>+ if (status == STATUS_SUCCESS) {
>+ status = OvsProcessDeferredActions(switchContext, completionList,
>+ portNo, sendFlags, layers);
>+ }
>+
>+ return status;
>+}
>+
>+NDIS_STATUS
>+OvsDoRecircFlowLookupOutput(POVS_SWITCH_CONTEXT switchContext,
>+ OvsCompletionList *completionList,
>+ PNET_BUFFER_LIST curNbl,
>+ OvsFlowKey *key,
>+ UINT64 *hash)
>+{
>+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
>+ OvsFlow *flow = NULL;
>+ OvsForwardingContext ovsFwdCtx = { 0 };
>+ POVS_VPORT_ENTRY internalVport = switchContext->internalVport;
>+
>+ ASSERT(switchContext->internalVport);
>+ ASSERT(internalVport->nicState == NdisSwitchNicStateConnected);
>+
>+ OvsInitForwardingCtx(&ovsFwdCtx, switchContext, curNbl,
>+ internalVport->portNo, 0,
>+
>NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl),
>+ completionList, NULL, TRUE);
>+
>+ status = OvsExtractFlow(curNbl, ovsFwdCtx.srcVportNo, key,
>+ &ovsFwdCtx.layers, NULL);
>+ if (status != NDIS_STATUS_SUCCESS) {
>+ OvsCompleteNBLForwardingCtx(&ovsFwdCtx,
>+ L"OVS-Dropped due to extract flow failure");
>+ status = NDIS_STATUS_FAILURE;
>+ ovsActionStats.failedFlowMiss++;
>+ }
>+
>+ flow = OvsLookupFlowRecirc(&ovsFwdCtx.switchContext->datapath,
>+ key, hash);
>+
>+ if (flow) {
>+ OvsFlowUsed(flow, ovsFwdCtx.curNbl, &ovsFwdCtx.layers);
>+ ovsFwdCtx.switchContext->datapath.hits++;
>+ status = OvsActionsExecute(ovsFwdCtx.switchContext,
>+ ovsFwdCtx.completionList,
>ovsFwdCtx.curNbl,
>+ ovsFwdCtx.srcVportNo,
>ovsFwdCtx.sendFlags,
>+ key, hash, &ovsFwdCtx.layers,
>+ flow->actions, flow->actionsLen);
>+ ovsFwdCtx.curNbl = NULL;
>+ } else {
>+ LIST_ENTRY missedPackets;
>+ UINT32 num = 0;
>+ ovsFwdCtx.switchContext->datapath.misses++;
>+ InitializeListHead(&missedPackets);
>+ status = OvsCreateAndAddPackets(NULL, 0, OVS_PACKET_CMD_MISS,
>+ internalVport,
>key,ovsFwdCtx.curNbl,
>+ FALSE, &ovsFwdCtx.layers,
>+ ovsFwdCtx.switchContext,
>+ &missedPackets, &num);
>+ if (num) {
>+ OvsQueuePackets(&missedPackets, num);
>+ }
>+ if (status == NDIS_STATUS_SUCCESS) {
>+ /* Complete the packet since it was copied to user buffer. */
>+ OvsCompleteNBLForwardingCtx(&ovsFwdCtx,
>+ L"OVS-Dropped since packet was copied to userspace");
>+ ovsActionStats.flowMiss++;
>+ status = NDIS_STATUS_SUCCESS;
>+ } else {
>+ OvsCompleteNBLForwardingCtx(&ovsFwdCtx,
>+ L"OVS-Dropped due to failure to queue to userspace");
>+ status = NDIS_STATUS_FAILURE;
>+ ovsActionStats.failedFlowMiss++;
>+ }
>+ }
>+
> return status;
> }
>diff --git a/datapath-windows/ovsext/Actions.h
>b/datapath-windows/ovsext/Actions.h
>new file mode 100644
>index 0000000..d2fe166
>--- /dev/null
>+++ b/datapath-windows/ovsext/Actions.h
>@@ -0,0 +1,54 @@
>+/*
>+ * Copyright (c) 2016 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=zX0Ryyebl5fXG0lRkFO-Q6W5UdQPx
>xNlGC175uYMUbg&s=8-8jQLtcdQnH2aIOMSl8nbTQxj7mRKE2UkqlcJuRUcA&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 __ACTIONS_H_
>+#define __ACTIONS_H_ 1
>+
>+#include "Switch.h"
>+#include "PacketIO.h"
>+
>+NDIS_STATUS
>+OvsActionsExecute(POVS_SWITCH_CONTEXT switchContext,
>+ OvsCompletionList *completionList,
>+ PNET_BUFFER_LIST curNbl,
>+ UINT32 srcVportNo,
>+ ULONG sendFlags,
>+ OvsFlowKey *key,
>+ UINT64 *hash,
>+ OVS_PACKET_HDR_INFO *layers,
>+ const PNL_ATTR actions,
>+ int actionsLen);
>+
>+NDIS_STATUS
>+OvsDoExecuteActions(POVS_SWITCH_CONTEXT switchContext,
>+ OvsCompletionList *completionList,
>+ PNET_BUFFER_LIST curNbl,
>+ UINT32 srcVportNo,
>+ ULONG sendFlags,
>+ OvsFlowKey *key,
>+ UINT64 *hash,
>+ OVS_PACKET_HDR_INFO *layers,
>+ const PNL_ATTR actions,
>+ int actionsLen);
>+
>+NDIS_STATUS
>+OvsDoRecircFlowLookupOutput(POVS_SWITCH_CONTEXT switchContext,
>+ OvsCompletionList *completionList,
>+ PNET_BUFFER_LIST curNbl,
>+ OvsFlowKey *key,
>+ UINT64 *hash);
>+
>+#endif /* __ACTIONS_H_ */
>diff --git a/datapath-windows/ovsext/Datapath.c
>b/datapath-windows/ovsext/Datapath.c
>index a9a218d..9e7d6a4 100644
>--- a/datapath-windows/ovsext/Datapath.c
>+++ b/datapath-windows/ovsext/Datapath.c
>@@ -346,6 +346,8 @@ extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
> NDIS_SPIN_LOCK ovsCtrlLockObj;
> PNDIS_SPIN_LOCK gOvsCtrlLock;
>
>+NDIS_SPIN_LOCK ovsRecircLockObj;
>+
> NTSTATUS
> InitUserDumpState(POVS_OPEN_INSTANCE instance,
> POVS_MESSAGE ovsMsg)
>@@ -383,6 +385,7 @@ OvsInit()
> {
> gOvsCtrlLock = &ovsCtrlLockObj;
> NdisAllocateSpinLock(gOvsCtrlLock);
>+ NdisAllocateSpinLock(&ovsRecircLockObj);
> OvsInitEventQueue();
> }
>
>@@ -394,6 +397,7 @@ OvsCleanup()
> NdisFreeSpinLock(gOvsCtrlLock);
> gOvsCtrlLock = NULL;
> }
>+ NdisFreeSpinLock(&ovsRecircLockObj);
> }
>
> VOID
>diff --git a/datapath-windows/ovsext/DpInternal.h
>b/datapath-windows/ovsext/DpInternal.h
>index c094f32..845c132 100644
>--- a/datapath-windows/ovsext/DpInternal.h
>+++ b/datapath-windows/ovsext/DpInternal.h
>@@ -20,7 +20,6 @@
> #include <netioapi.h>
> #define IFNAMSIZ IF_NAMESIZE
> #include "../ovsext/Netlink/Netlink.h"
>-#include "Mpls.h"
>
> #define OVS_DP_NUMBER ((uint32_t) 0)
>
>@@ -166,6 +165,7 @@ typedef __declspec(align(8)) struct OvsFlowKey {
> Icmp6Key icmp6Key; /* size 72 */
> MplsKey mplsKey; /* size 8 */
> };
>+ UINT32 recircId; /* Recirculation ID. */
> } OvsFlowKey;
>
> #define OVS_WIN_TUNNEL_KEY_SIZE (sizeof (OvsIPv4TunnelKey))
>diff --git a/datapath-windows/ovsext/Flow.c
>b/datapath-windows/ovsext/Flow.c
>index 5eec513..baf8422 100644
>--- a/datapath-windows/ovsext/Flow.c
>+++ b/datapath-windows/ovsext/Flow.c
>@@ -110,9 +110,7 @@ const NL_POLICY nlFlowPolicy[] = {
> [OVS_FLOW_ATTR_PROBE] = {.type = NL_A_FLAG, .optional = TRUE}
> };
>
>-/* For Parsing nested OVS_FLOW_ATTR_KEY attributes.
>- * Some of the attributes like OVS_KEY_ATTR_RECIRC_ID
>- * are not supported yet. */
>+/* For Parsing nested OVS_FLOW_ATTR_KEY attributes. */
>
> const NL_POLICY nlFlowKeyPolicy[] = {
> [OVS_KEY_ATTR_ENCAP] = {.type = NL_A_VAR_LEN, .optional = TRUE},
>@@ -252,7 +250,7 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT
>usrParamsCtx,
> UINT32 *replyLen)
> {
> NTSTATUS rc = STATUS_SUCCESS;
>- BOOLEAN ok;
>+ BOOLEAN ok = FALSE;
> POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
> POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
> PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg);
>@@ -260,11 +258,11 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT
>usrParamsCtx,
> POVS_HDR ovsHdr = &(msgIn->ovsHdr);
> PNL_ATTR flowAttrs[__OVS_FLOW_ATTR_MAX];
> UINT32 attrOffset = NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN;
>- OvsFlowPut mappedFlow;
>- OvsFlowStats stats;
>- struct ovs_flow_stats replyStats;
>+ OvsFlowPut mappedFlow = { 0 };
>+ OvsFlowStats stats = { 0 };
>+ struct ovs_flow_stats replyStats = { 0 };
> NL_ERROR nlError = NL_ERROR_SUCCESS;
>- NL_BUFFER nlBuf;
>+ NL_BUFFER nlBuf = { 0 };
>
> RtlZeroMemory(&mappedFlow, sizeof(OvsFlowPut));
> RtlZeroMemory(&stats, sizeof(stats));
>@@ -594,9 +592,9 @@ _FlowNlDumpCmdHandler(POVS_USER_PARAMS_CONTEXT
>usrParamsCtx,
> UINT32 hdrOffset = 0;
>
> /* Get Next */
>- OvsFlowDumpOutput dumpOutput;
>- OvsFlowDumpInput dumpInput;
>- NL_BUFFER nlBuf;
>+ OvsFlowDumpOutput dumpOutput = { 0 };
>+ OvsFlowDumpInput dumpInput = { 0 };
>+ NL_BUFFER nlBuf = { 0 };
>
> NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
> usrParamsCtx->outputLength);
>@@ -826,6 +824,12 @@ MapFlowKeyToNlKey(PNL_BUFFER nlBuf,
> goto error_nested_start;
> }
>
>+ if (!NlMsgPutTailU32(nlBuf, OVS_KEY_ATTR_RECIRC_ID,
>+ flowKey->recircId)) {
>+ rc = STATUS_UNSUCCESSFUL;
>+ goto done;
>+ }
>+
> /* Ethernet header */
> RtlCopyMemory(&(ethKey.eth_src), flowKey->l2.dlSrc, ETH_ADDR_LEN);
> RtlCopyMemory(&(ethKey.eth_dst), flowKey->l2.dlDst, ETH_ADDR_LEN);
>@@ -1348,6 +1352,10 @@ _MapKeyAttrToFlowPut(PNL_ATTR *keyAttrs,
> {
> _MapTunAttrToFlowPut(keyAttrs, tunnelAttrs, destKey);
>
>+ if (keyAttrs[OVS_KEY_ATTR_RECIRC_ID]) {
>+ destKey->recircId =
>NlAttrGetU32(keyAttrs[OVS_KEY_ATTR_RECIRC_ID]);
>+ }
>+
> /* ===== L2 headers ===== */
> destKey->l2.inPort = NlAttrGetU32(keyAttrs[OVS_KEY_ATTR_IN_PORT]);
>
>@@ -2072,6 +2080,9 @@ OvsLookupFlow(OVS_DATAPATH *datapath,
>
> if (!hashValid) {
> *hash = OvsJhashBytes(start, size, 0);
>+ if (key->recircId) {
>+ *hash = OvsJhashWords((UINT32*)hash, 1, key->recircId);
>+ }
> }
>
> head = &datapath->flowTable[HASH_BUCKET(*hash)];
>@@ -2090,6 +2101,47 @@ OvsLookupFlow(OVS_DATAPATH *datapath,
> return NULL;
> }
>
>+/*
>+ *
>--------------------------------------------------------------------------
>--
>+ * OvsLookupFlowRecirc --
>+ *
>+ * Find flow from flow table based on flow key and recircId, if
>available.
>+ * Caller should either hold portset handle or should
>+ * have a flowRef in datapath or Acquired datapath.
>+ *
>+ * Results:
>+ * Flow pointer if lookup successful.
>+ * NULL if not exists.
>+ *
>--------------------------------------------------------------------------
>--
>+ */
>+OvsFlow *
>+OvsLookupFlowRecirc(OVS_DATAPATH *datapath,
>+ const OvsFlowKey *key,
>+ UINT64 *hash)
>+{
>+ OvsFlow* flow = NULL;
>+
>+ if (!hash || !(*hash)) {
>+ flow = OvsLookupFlow(datapath, key, hash, FALSE);
>+ } else {
>+ /*
>+ * Pre and post recirculation flows usually have the same hash
>+ * value. To avoid hash collisions, rehash the 'hash' with
>+ * 'recircId'.
>+ */
>+ if (key->recircId) {
>+ *hash = OvsJhashWords((UINT32*)hash, 1, key->recircId);
>+ }
>+
>+ flow = OvsLookupFlow(datapath, key, hash, FALSE);
>+ if (flow) {
>+ flow->hash = *hash;
>+ }
>+ }
>+
>+ return flow;
>+}
>+
>
> /*
> *
>--------------------------------------------------------------------------
>--
>@@ -2239,6 +2291,8 @@ ReportFlowInfo(OvsFlow *flow,
> }
> }
>
>+ info->key.recircId = flow->key.recircId;
>+
> return status;
> }
>
>diff --git a/datapath-windows/ovsext/Flow.h
>b/datapath-windows/ovsext/Flow.h
>index 74b9dfb..78bf7cc 100644
>--- a/datapath-windows/ovsext/Flow.h
>+++ b/datapath-windows/ovsext/Flow.h
>@@ -54,8 +54,11 @@ NDIS_STATUS OvsAllocateFlowTable(OVS_DATAPATH
>*datapath,
> NDIS_STATUS OvsExtractFlow(const NET_BUFFER_LIST *pkt, UINT32 inPort,
> OvsFlowKey *flow, POVS_PACKET_HDR_INFO layers,
> OvsIPv4TunnelKey *tunKey);
>-OvsFlow *OvsLookupFlow(OVS_DATAPATH *datapath, const OvsFlowKey *key,
>+OvsFlow* OvsLookupFlow(OVS_DATAPATH *datapath, const OvsFlowKey *key,
> UINT64 *hash, BOOLEAN hashValid);
>+OvsFlow* OvsLookupFlowRecirc(OVS_DATAPATH *datapath,
>+ const OvsFlowKey *key,
>+ UINT64 *hash);
> UINT64 OvsHashFlow(const OvsFlowKey *key);
> VOID OvsFlowUsed(OvsFlow *flow, const NET_BUFFER_LIST *pkt,
> const POVS_PACKET_HDR_INFO layers);
>diff --git a/datapath-windows/ovsext/Netlink/Netlink.h
>b/datapath-windows/ovsext/Netlink/Netlink.h
>index 99665fb..8f6a5be 100644
>--- a/datapath-windows/ovsext/Netlink/Netlink.h
>+++ b/datapath-windows/ovsext/Netlink/Netlink.h
>@@ -173,6 +173,17 @@ static __inline NlAttrTotalSize(UINT32 payloadSize)
> return NLA_ALIGN(NlAttrSize(payloadSize));
> }
>
>+/*
>+ *
>--------------------------------------------------------------------------
>-
>+ * Returns true if the last attribute is reached.
>+ *
>--------------------------------------------------------------------------
>-
>+ */
>+BOOLEAN
>+static __inline NlAttrIsLast(const PNL_ATTR nla, int rem)
>+{
>+ return nla->nlaLen == rem;
>+}
>+
> /* Netlink attribute validation */
> BOOLEAN NlAttrValidate(const PNL_ATTR, const PNL_POLICY);
>
>diff --git a/datapath-windows/ovsext/PacketIO.c
>b/datapath-windows/ovsext/PacketIO.c
>index cfbae34..a0ddc3d 100644
>--- a/datapath-windows/ovsext/PacketIO.c
>+++ b/datapath-windows/ovsext/PacketIO.c
>@@ -20,6 +20,8 @@
> */
>
> #include "precomp.h"
>+
>+#include "Actions.h"
> #include "Switch.h"
> #include "Vport.h"
> #include "NetProto.h"
>@@ -234,14 +236,14 @@ OvsStartNBLIngress(POVS_SWITCH_CONTEXT
>switchContext,
> OvsInitCompletionList(&completionList, switchContext,
>sendCompleteFlags);
>
> for (curNbl = netBufferLists; curNbl != NULL; curNbl = nextNbl) {
>- POVS_VPORT_ENTRY vport;
>- UINT32 portNo;
>+ POVS_VPORT_ENTRY vport = NULL;
>+ UINT32 portNo = 0;
> OVS_DATAPATH *datapath = &switchContext->datapath;
>- OVS_PACKET_HDR_INFO layers;
>- OvsFlowKey key;
>- UINT64 hash;
>- PNET_BUFFER curNb;
>- POVS_BUFFER_CONTEXT ctx;
>+ OVS_PACKET_HDR_INFO layers = { 0 };
>+ OvsFlowKey key = { 0 };
>+ UINT64 hash = 0;
>+ PNET_BUFFER curNb = NULL;
>+ POVS_BUFFER_CONTEXT ctx = NULL;
>
> nextNbl = curNbl->Next;
> curNbl->Next = NULL;
>diff --git a/datapath-windows/ovsext/PacketIO.h
>b/datapath-windows/ovsext/PacketIO.h
>index 7247869..a7c1f76 100644
>--- a/datapath-windows/ovsext/PacketIO.h
>+++ b/datapath-windows/ovsext/PacketIO.h
>@@ -48,14 +48,4 @@ VOID OvsSendNBLIngress(POVS_SWITCH_CONTEXT
>switchContext,
> PNET_BUFFER_LIST netBufferLists,
> ULONG sendFlags);
>
>-NDIS_STATUS OvsActionsExecute(POVS_SWITCH_CONTEXT switchContext,
>- OvsCompletionList *completionList,
>- PNET_BUFFER_LIST curNbl, UINT32 srcVportNo,
>- ULONG sendFlags, OvsFlowKey *key, UINT64
>*hash,
>- OVS_PACKET_HDR_INFO *layers,
>- const PNL_ATTR actions, int actionsLen);
>-
>-VOID OvsLookupFlowOutput(POVS_SWITCH_CONTEXT switchContext,
>- VOID *compList, PNET_BUFFER_LIST curNbl);
>-
> #endif /* __PACKETIO_H_ */
>diff --git a/datapath-windows/ovsext/Recirc.c
>b/datapath-windows/ovsext/Recirc.c
>new file mode 100644
>index 0000000..4c009f4
>--- /dev/null
>+++ b/datapath-windows/ovsext/Recirc.c
>@@ -0,0 +1,171 @@
>+/*
>+ * Copyright (c) 2016 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=zX0Ryyebl5fXG0lRkFO-Q6W5UdQPx
>xNlGC175uYMUbg&s=8-8jQLtcdQnH2aIOMSl8nbTQxj7mRKE2UkqlcJuRUcA&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 "Recirc.h"
>+#include "Flow.h"
>+#include "Jhash.h"
>+
>+static OVS_DEFERRED_ACTION_QUEUE ovsDeferredActionsQueue = { 0 };
>+extern NDIS_SPIN_LOCK ovsRecircLockObj;
>+
>+/*
>+ *
>--------------------------------------------------------------------------
>+ * OvsDeferredActionsQueueInit --
>+ * The function resets the queue to be ready for the next packet.
>+ *
>--------------------------------------------------------------------------
>+ */
>+static
>+VOID
>+OvsDeferredActionsQueueInit(POVS_DEFERRED_ACTION_QUEUE queue)
>+{
>+ queue->head = 0;
>+ queue->tail = 0;
>+}
>+
>+/*
>+ *
>--------------------------------------------------------------------------
>+ * OvsDeferredActionsQueueIsEmpty --
>+ * The function verifies if the queue is empty.
>+ *
>--------------------------------------------------------------------------
>+ */
>+static
>+BOOLEAN
>+OvsDeferredActionsQueueIsEmpty(const POVS_DEFERRED_ACTION_QUEUE queue)
>+{
>+ return (queue->head == queue->tail);
>+}
>+
>+/*
>+ *
>--------------------------------------------------------------------------
>+ * OvsDeferredActionsQueuePop --
>+ * The function pops the next queue element.
>+ *
>--------------------------------------------------------------------------
>+ */
>+static
>+POVS_DEFERRED_ACTION
>+OvsDeferredActionsQueuePop(POVS_DEFERRED_ACTION_QUEUE queue)
>+{
>+ POVS_DEFERRED_ACTION deferredAction = NULL;
>+
>+ NdisAcquireSpinLock(&ovsRecircLockObj);
>+
>+ if (OvsDeferredActionsQueueIsEmpty(queue)) {
>+ /* Reset the queue for the next packet. */
>+ OvsDeferredActionsQueueInit(queue);
>+ } else {
>+ deferredAction = &queue->queue[queue->tail++];
>+ }
>+
>+ NdisReleaseSpinLock(&ovsRecircLockObj);
>+
>+ return deferredAction;
>+}
>+
>+/*
>+ *
>--------------------------------------------------------------------------
>+ * OvsDeferredActionsQueuePush --
>+ * The function pushes the current element in the deferred actions
>queue.
>+ *
>--------------------------------------------------------------------------
>+ */
>+static
>+POVS_DEFERRED_ACTION
>+OvsDeferredActionsQueuePush(POVS_DEFERRED_ACTION_QUEUE queue)
>+{
>+ POVS_DEFERRED_ACTION deferredAction = NULL;
>+
>+ NdisAcquireSpinLock(&ovsRecircLockObj);
>+
>+ if (queue->head < DEFERRED_ACTION_QUEUE_SIZE) {
>+ deferredAction = &queue->queue[queue->head++];
>+ }
>+
>+ NdisReleaseSpinLock(&ovsRecircLockObj);
>+
>+ return deferredAction;
>+}
>+
>+/*
>+ *
>--------------------------------------------------------------------------
>+ * OvsAddDeferredActions --
>+ * This function returns the new queue entry if the queue is not
>already
>+ * full.
>+ *
>+ * Note:
>+ * The function is thread-safe.
>+ *
>--------------------------------------------------------------------------
>+ */
>+POVS_DEFERRED_ACTION
>+OvsAddDeferredActions(PNET_BUFFER_LIST packet,
>+ OvsFlowKey *key,
>+ UINT64 hash,
>+ const PNL_ATTR actions)
>+{
>+ POVS_DEFERRED_ACTION deferredAction = NULL;
>+
>+ deferredAction =
>OvsDeferredActionsQueuePush(&ovsDeferredActionsQueue);
>+ if (deferredAction) {
>+ deferredAction->packet = packet;
>+ deferredAction->actions = actions;
>+ deferredAction->key = *key;
>+ deferredAction->hash = hash;
>+ }
>+
>+ return deferredAction;
>+}
>+
>+/*
>+ *
>--------------------------------------------------------------------------
>+ * OvsProcessDeferredActions --
>+ * This function processes all deferred actions contained in the
>queue.
>+ *
>+ * Note:
>+ * The function is thread-safe.
>+ *
>--------------------------------------------------------------------------
>+ */
>+NTSTATUS
>+OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
>+ OvsCompletionList *completionList,
>+ UINT32 portNo,
>+ ULONG sendFlags,
>+ OVS_PACKET_HDR_INFO *layers)
>+{
>+ NTSTATUS status = STATUS_SUCCESS;
>+ POVS_DEFERRED_ACTION_QUEUE queue = &ovsDeferredActionsQueue;
>+ POVS_DEFERRED_ACTION deferredAction = NULL;
>+
>+ /* Process all deferred actions. */
>+ while ((deferredAction = OvsDeferredActionsQueuePop(queue)) != NULL)
>{
>+ if (deferredAction->actions) {
>+ status = OvsDoExecuteActions(switchContext,
>+ completionList,
>+ deferredAction->packet,
>+ portNo,
>+ sendFlags,
>+ &deferredAction->key,
>+ &deferredAction->hash,
>+ layers, deferredAction->actions,
>+
>NlAttrGetSize(deferredAction->actions));
>+ } else {
>+ status = OvsDoRecircFlowLookupOutput(switchContext,
>+ completionList,
>+ deferredAction->packet,
>+ &deferredAction->key,
>+ &deferredAction->hash);
>+ }
>+ }
>+
>+ return status;
>+}
>diff --git a/datapath-windows/ovsext/Recirc.h
>b/datapath-windows/ovsext/Recirc.h
>new file mode 100644
>index 0000000..597ecf4
>--- /dev/null
>+++ b/datapath-windows/ovsext/Recirc.h
>@@ -0,0 +1,82 @@
>+/*
>+ * Copyright (c) 2016 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=zX0Ryyebl5fXG0lRkFO-Q6W5UdQPx
>xNlGC175uYMUbg&s=8-8jQLtcdQnH2aIOMSl8nbTQxj7mRKE2UkqlcJuRUcA&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 __RECIRC_H_
>+#define __RECIRC_H_ 1
>+
>+#include "Actions.h"
>+
>+#define DEFERRED_ACTION_QUEUE_SIZE 10
>+
>+typedef struct _OVS_DEFERRED_ACTION {
>+ PNET_BUFFER_LIST packet;
>+ PNL_ATTR actions;
>+ OvsFlowKey key;
>+ UINT64 hash;
>+} OVS_DEFERRED_ACTION, *POVS_DEFERRED_ACTION;
>+
>+/*
>+ *
>--------------------------------------------------------------------------
>+ * '_OVS_DEFERRED_ACTION_QUEUE' is responsible for keeping track of all
>+ * deferred actions. The maximum number of deferred actions should not
>exceed
>+ * 'DEFERRED_ACTION_QUEUE_SIZE'.
>+ *
>+ * Note:
>+ * Adding/removing a deferred action to/from the queue is only safe
>while
>+ * holding a proper lock.
>+ *
>--------------------------------------------------------------------------
>+ */
>+typedef struct _OVS_DEFERRED_ACTION_QUEUE {
>+ UINT32 head;
>+ UINT32 tail;
>+ OVS_DEFERRED_ACTION queue[DEFERRED_ACTION_QUEUE_SIZE];
>+} OVS_DEFERRED_ACTION_QUEUE, *POVS_DEFERRED_ACTION_QUEUE;
>+
>+/*
>+ *
>--------------------------------------------------------------------------
>+ * OvsProcessDeferredActions --
>+ * This function processes all deferred actions contained in the
>queue.
>+ *
>+ * Note:
>+ * The function is not thread-safe. It is the resposibility of the
>caller
>+ * to hold a proper lock.
>+ *
>--------------------------------------------------------------------------
>+ */
>+NTSTATUS
>+OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
>+ OvsCompletionList *completionList,
>+ UINT32 portNo,
>+ ULONG sendFlags,
>+ OVS_PACKET_HDR_INFO *layers);
>+
>+/*
>+ *
>--------------------------------------------------------------------------
>+ * OvsAddDeferredActions --
>+ * This function returns the new queue entry if the queue is not
>already
>+ * full.
>+ *
>+ * Note:
>+ * The function is not thread-safe. It is the resposibility of the
>caller
>+ * to hold a proper lock.
>+ *
>--------------------------------------------------------------------------
>+ */
>+POVS_DEFERRED_ACTION
>+OvsAddDeferredActions(PNET_BUFFER_LIST packet,
>+ OvsFlowKey *key,
>+ UINT64 hash,
>+ const PNL_ATTR actions);
>+
>+#endif /* __RECIRC_H_ */
>diff --git a/datapath-windows/ovsext/Tunnel.c
>b/datapath-windows/ovsext/Tunnel.c
>index eea4a84..e957aaf 100644
>--- a/datapath-windows/ovsext/Tunnel.c
>+++ b/datapath-windows/ovsext/Tunnel.c
>@@ -39,6 +39,7 @@
> #include "PacketIO.h"
> #include "NetProto.h"
> #include "Flow.h"
>+#include "Actions.h"
>
> extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
>
>@@ -258,13 +259,13 @@ OvsInjectPacketThroughActions(PNET_BUFFER_LIST pNbl,
> sendCompleteFlags);
>
> {
>- POVS_VPORT_ENTRY vport;
>- UINT32 portNo;
>- OVS_PACKET_HDR_INFO layers;
>- OvsFlowKey key;
>- UINT64 hash;
>- PNET_BUFFER curNb;
>- OvsFlow *flow;
>+ POVS_VPORT_ENTRY vport = NULL;
>+ UINT32 portNo = 0;
>+ OVS_PACKET_HDR_INFO layers = { 0 };
>+ OvsFlowKey key = { 0 };
>+ UINT64 hash = 0;
>+ PNET_BUFFER curNb = NULL;
>+ OvsFlow *flow = NULL;
>
> fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pNbl);
>
>diff --git a/datapath-windows/ovsext/User.c
>b/datapath-windows/ovsext/User.c
>index e97f2b2..cadffda 100644
>--- a/datapath-windows/ovsext/User.c
>+++ b/datapath-windows/ovsext/User.c
>@@ -22,6 +22,7 @@
>
> #include "precomp.h"
>
>+#include "Actions.h"
> #include "Datapath.h"
> #include "Debug.h"
> #include "Event.h"
>@@ -388,14 +389,14 @@ NTSTATUS
> OvsExecuteDpIoctl(OvsPacketExecute *execute)
> {
> NTSTATUS status = STATUS_SUCCESS;
>- NTSTATUS ndisStatus;
>+ NTSTATUS ndisStatus = STATUS_SUCCESS;
> LOCK_STATE_EX lockState;
>- PNET_BUFFER_LIST pNbl;
>- PNL_ATTR actions;
>+ PNET_BUFFER_LIST pNbl = NULL;
>+ PNL_ATTR actions = NULL;
> PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail;
>- OvsFlowKey key;
>- OVS_PACKET_HDR_INFO layers;
>- POVS_VPORT_ENTRY vport;
>+ OvsFlowKey key = { 0 };
>+ OVS_PACKET_HDR_INFO layers = { 0 };
>+ POVS_VPORT_ENTRY vport = NULL;
>
> if (execute->packetLen == 0) {
> status = STATUS_INVALID_PARAMETER;
>diff --git a/datapath-windows/ovsext/ovsext.vcxproj
>b/datapath-windows/ovsext/ovsext.vcxproj
>index e3aea97..af718f7 100644
>--- a/datapath-windows/ovsext/ovsext.vcxproj
>+++ b/datapath-windows/ovsext/ovsext.vcxproj
>@@ -71,6 +71,7 @@
> </ImportGroup>
> <ItemGroup Label="WrappedTaskItems">
> <ClInclude Include="..\include\OvsDpInterfaceExt.h" />
>+ <ClInclude Include="Actions.h" />
> <ClInclude Include="Atomic.h" />
> <ClInclude Include="BufferMgmt.h" />
> <ClInclude Include="Datapath.h" />
>@@ -93,6 +94,7 @@
> <ClInclude Include="PacketIO.h" />
> <ClInclude Include="PacketParser.h" />
> <ClInclude Include="precomp.h" />
>+ <ClInclude Include="Recirc.h" />
> <ClInclude Include="resource.h" />
> <ClInclude Include="Stt.h" />
> <ClInclude Include="Switch.h" />
>@@ -193,6 +195,7 @@
> <PreCompiledHeader>Create</PreCompiledHeader>
>
><PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOut
>putFile>
> </ClCompile>
>+ <ClCompile Include="Recirc.c" />
> <ClCompile Include="Stt.c" />
> <ClCompile Include="Switch.c" />
> <ClCompile Include="Tunnel.c" />
>--
>1.9.5.msysgit.0
>
>_______________________________________________
>dev mailing list
>dev at 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=zX0Ryyebl5fXG0lRkFO-Q6W5UdQPxx
>NlGC175uYMUbg&s=JPmHCJABGDK1SjfoN5FRD6806OLrIJrrZeQZ2wu_3g4&e=
More information about the dev
mailing list