[ovs-dev] [PATCH v6 2/6] datapath-windows: Added recirculation support.

Nithin Raju nithin at vmware.com
Fri Mar 18 19:45:46 UTC 2016


Pls. disregard this. I hit the ‘send’ too soon. Will send out the full
list of comments.

-----Original Message-----
From: Nithin Raju <nithin at vmware.com>
Date: Friday, March 18, 2016 at 12:43 PM
To: Sorin Vinturis <svinturis at cloudbasesolutions.com>,
"dev at openvswitch.org" <dev at openvswitch.org>
Subject: Re: [ovs-dev] [PATCH v6 2/6] datapath-windows: Added
recirculation support.

>
>
>-----Original Message-----
>From: dev <dev-bounces at openvswitch.org> on behalf of Sorin Vinturis
><svinturis at cloudbasesolutions.com>
>Date: Friday, March 18, 2016 at 7:58 AM
>To: "dev at openvswitch.org" <dev at openvswitch.org>
>Subject: [ovs-dev] [PATCH v6 2/6] datapath-windows: Added
>recirculation	support.
>
>>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_openvswit
>>c
>>h_ovs-2Dissues_issues_104&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMN
>>t
>>Xt-uEs&r=pNHQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=OpMpvAAJDApIpx1rEL
>>D
>>Zz_PzL7S9hfkeHD2h-6_KTCg&s=oZxN8oCzUixc4GlkvE6n4m0RN2gf2XiL0OI-sVgXdus&e=
>>---
>>v2: Initialize flow key before using it.
>>v3: Synchronized access to deferred actions queue.
>>v4: Address comments.
>>v5: update flow key and layers in the recirc action, queue/execute packet
>>    per source port
>>v6: Added percpu deferred action queues.
>>---
>>---
>> datapath-windows/automake.mk              |   3 +
>> datapath-windows/ovsext/Actions.c         | 234
>>+++++++++++++++++++++++++++---
>> datapath-windows/ovsext/Actions.h         |  56 +++++++
>> datapath-windows/ovsext/Datapath.c        |   3 +
>> datapath-windows/ovsext/DpInternal.h      |   2 +-
>> datapath-windows/ovsext/Flow.c            |  78 ++++++++--
>> 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          | 224
>>++++++++++++++++++++++++++++
>> datapath-windows/ovsext/Recirc.h          |  90 ++++++++++++
>> datapath-windows/ovsext/Tunnel.c          |  15 +-
>> datapath-windows/ovsext/User.c            |  13 +-
>> datapath-windows/ovsext/Util.h            |   1 +
>> datapath-windows/ovsext/ovsext.vcxproj    |   3 +
>> 16 files changed, 696 insertions(+), 68 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..333d487 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;
>
>Unnecessary initialization.
>
>>     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,8 +1524,58 @@ OvsExecuteSetAction(OvsForwardingContext
>>*ovsFwdCtx,
>> 
>> /*
>>  * 
>>-------------------------------------------------------------------------
>>-
>>- * OvsActionsExecute --
>>- *     Interpret and execute the specified 'actions' on the specifed
>>packet
>>+ * OvsActionExecuteRecirc --
>>+ *     The function adds a deferred action to allow the current packet,
>>nbl,
>>+ *     to re-enter datapath packet processing.
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ */
>>+NDIS_STATUS
>>+OvsActionExecuteRecirc(OvsFlowKey *key,
>>+                       UINT64 *hashAction,
>>+                       const PNL_ATTR actions,
>>+                       int rem,
>>+                       OvsForwardingContext ovsFwdCtx)
>>+{
>>+    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(ovsFwdCtx.switchContext,
>>ovsFwdCtx.curNbl,
>>+                                   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 NDIS_STATUS_SUCCESS;
>>+        }
>>+        ovsFwdCtx.curNbl = newNbl;
>
>You¹ll probably want to do a OvsInitForwardingCtx() rather than just
>changing the curNbl pointer.
>
>>+    }
>>+
>>+    hash = hashAction ? *hashAction : OvsHashFlow(key);
>>+
>>+    deferredAction = OvsAddDeferredActions(ovsFwdCtx.curNbl, key, hash,
>>NULL);
>>+    if (deferredAction) {
>>+        deferredAction->key.recircId = NlAttrGetU32(actions);
>>+    } else {
>>+        if (newNbl) {
>>+            OvsCompleteNBL(ovsFwdCtx.switchContext, newNbl, TRUE);
>>+        }
>>+    }
>>+
>>+    return NDIS_STATUS_SUCCESS;
>>+}
>>+
>>+/*
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ * OvsDoExecuteActions --
>>+ *     Interpret and execute the specified 'actions' on the specified
>>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
>>  *     caller can complete the packet. If 'completionList' is NULL, the
>>NBL is
>>@@ -1537,16 +1591,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 +1749,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(key, hash,
>>+                                            (const PNL_ATTR)a, rem,
>>+                                            ovsFwdCtx);
>>+            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 +1860,112 @@ 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,
>>+                            UINT32 srcPortNo,
>>+                            OVS_PACKET_HDR_INFO *layers)
>>+{
>>+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
>>+    OvsFlow *flow = NULL;
>>+    OvsForwardingContext ovsFwdCtx = { 0 };
>>+    ASSERT(layers);
>>+
>>+    OvsInitForwardingCtx(&ovsFwdCtx, switchContext, curNbl,
>>+                         srcPortNo, 0,
>>+                
>>NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl),
>>+                         completionList, layers, TRUE);
>>+
>>+    status = OvsExtractFlow(ovsFwdCtx.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 {
>>+        POVS_VPORT_ENTRY vport = NULL;
>>+        LIST_ENTRY missedPackets;
>>+        UINT32 num = 0;
>>+
>>+        ovsFwdCtx.switchContext->datapath.misses++;
>>+        InitializeListHead(&missedPackets);
>>+        vport = OvsFindVportByPortNo(switchContext, srcPortNo);
>>+        if (vport == NULL || vport->ovsState != OVS_STATE_CONNECTED) {
>>+            OvsCompleteNBLForwardingCtx(&ovsFwdCtx,
>>+                L"OVS-Dropped due to port removal");
>>+            ovsActionStats.noVport++;
>>+            return NDIS_STATUS_SUCCESS;
>>+        }
>>+        status = OvsCreateAndAddPackets(NULL, 0, OVS_PACKET_CMD_MISS,
>>+                                        vport, key, ovsFwdCtx.curNbl,
>>+                                        srcPortNo ==
>>+                
>>switchContext->virtualExternalPortId,
>>+                                        &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..69a1f69
>>--- /dev/null
>>+++ b/datapath-windows/ovsext/Actions.h
>>@@ -0,0 +1,56 @@
>>+/*
>>+ * 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_licens
>>e
>>s_LICENSE-2D2.0&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=
>>p
>>NHQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=OpMpvAAJDApIpx1rELDZz_PzL7S9
>>h
>>fkeHD2h-6_KTCg&s=S30nm7dlEorfpeMZh2t0GL8LoSf_KXweQSeVsbNOCtg&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,
>>+                            UINT32 srcPortNo,
>>+                            OVS_PACKET_HDR_INFO *layers);
>>+
>>+#endif /* __ACTIONS_H_ */
>>diff --git a/datapath-windows/ovsext/Datapath.c
>>b/datapath-windows/ovsext/Datapath.c
>>index a9a218d..876d6bf 100644
>>--- a/datapath-windows/ovsext/Datapath.c
>>+++ b/datapath-windows/ovsext/Datapath.c
>>@@ -30,6 +30,7 @@
>> #include "Event.h"
>> #include "User.h"
>> #include "PacketIO.h"
>>+#include "Recirc.h"
>> #include "NetProto.h"
>> #include "Flow.h"
>> #include "User.h"
>>@@ -383,6 +384,7 @@ OvsInit()
>> {
>>     gOvsCtrlLock = &ovsCtrlLockObj;
>>     NdisAllocateSpinLock(gOvsCtrlLock);
>>+    OvsDeferredActionsQueueAlloc();
>>     OvsInitEventQueue();
>> }
>> 
>>@@ -394,6 +396,7 @@ OvsCleanup()
>>         NdisFreeSpinLock(gOvsCtrlLock);
>>         gOvsCtrlLock = NULL;
>>     }
>>+    OvsDeferredActionsQueueFree();
>> }
>> 
>> 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..2ceeb94 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;
>>+}
>>+
>> 
>> /*
>>  * 
>>-------------------------------------------------------------------------
>>-
>>--
>>@@ -2219,7 +2271,7 @@ ReportFlowInfo(OvsFlow *flow,
>>     if (getFlags & FLOW_GET_KEY) {
>>         // always copy the tunnel key part
>>         RtlCopyMemory(&info->key, &flow->key,
>>-                            flow->key.l2.keyLen + flow->key.l2.offset);
>>+                      flow->key.l2.keyLen + flow->key.l2.offset);
>>     }
>> 
>>     if (getFlags & FLOW_GET_STATS) {
>>@@ -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..56b6200
>>--- /dev/null
>>+++ b/datapath-windows/ovsext/Recirc.c
>>@@ -0,0 +1,224 @@
>>+/*
>>+ * 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_licens
>>e
>>s_LICENSE-2D2.0&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=
>>p
>>NHQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=OpMpvAAJDApIpx1rELDZz_PzL7S9
>>h
>>fkeHD2h-6_KTCg&s=S30nm7dlEorfpeMZh2t0GL8LoSf_KXweQSeVsbNOCtg&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 POVS_DEFERRED_ACTION_QUEUE ovsDeferredActionQueues = NULL;
>>+
>>+BOOLEAN
>>+OvsDeferredActionsQueueAlloc()
>>+{
>>+    ovsDeferredActionQueues =
>>+        OvsAllocateMemoryPerCpu(sizeof(OVS_DEFERRED_ACTION_QUEUE),
>>+                                OVS_RECIRC_POOL_TAG);
>>+    if (!ovsDeferredActionQueues) {
>>+        return FALSE;
>>+    }
>>+    return TRUE;
>>+}
>>+
>>+VOID
>>+OvsDeferredActionsQueueFree()
>>+{
>>+    OvsFreeMemoryWithTag(ovsDeferredActionQueues,
>>+                         OVS_RECIRC_POOL_TAG);
>>+    ovsDeferredActionQueues = NULL;
>>+}
>>+
>>+POVS_DEFERRED_ACTION_QUEUE
>>+OvsDeferredActionsQueueGet()
>>+{
>>+    POVS_DEFERRED_ACTION_QUEUE queue = NULL;
>>+    ULONG index = 0;
>>+    KIRQL oldIrql = KeGetCurrentIrql();
>>+
>>+    if (oldIrql < DISPATCH_LEVEL) {
>>+        KeRaiseIrqlToDpcLevel();
>>+    }
>>+
>>+    index = KeGetCurrentProcessorNumber();
>>+    queue = &ovsDeferredActionQueues[index];
>>+
>>+    if (oldIrql < DISPATCH_LEVEL) {
>>+        KeLowerIrql(oldIrql);
>>+    }
>>+
>>+    return queue;
>>+}
>>+
>>+/*
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ * 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;
>>+    KIRQL oldIrql = KeGetCurrentIrql();
>>+
>>+    if (oldIrql < DISPATCH_LEVEL) {
>>+        KeRaiseIrqlToDpcLevel();
>>+    }
>>+
>>+    if (OvsDeferredActionsQueueIsEmpty(queue)) {
>>+        /* Reset the queue for the next packet. */
>>+        OvsDeferredActionsQueueInit(queue);
>>+    } else {
>>+        deferredAction = &queue->queue[queue->tail++];
>>+    }
>>+
>>+    if (oldIrql < DISPATCH_LEVEL) {
>>+        KeLowerIrql(oldIrql);
>>+    }
>>+
>>+    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;
>>+    KIRQL oldIrql = KeGetCurrentIrql();
>>+
>>+    if (oldIrql < DISPATCH_LEVEL) {
>>+        KeRaiseIrqlToDpcLevel();
>>+    }
>>+
>>+    if (queue->head < DEFERRED_ACTION_QUEUE_SIZE) {
>>+        deferredAction = &queue->queue[queue->head++];
>>+    }
>>+
>>+    if (oldIrql < DISPATCH_LEVEL) {
>>+        KeLowerIrql(oldIrql);
>>+    }
>>+
>>+    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_QUEUE queue = OvsDeferredActionsQueueGet();
>>+    POVS_DEFERRED_ACTION deferredAction = NULL;
>>+
>>+    deferredAction = OvsDeferredActionsQueuePush(queue);
>>+    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.
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ */
>>+NDIS_STATUS
>>+OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
>>+                          OvsCompletionList *completionList,
>>+                          UINT32 portNo,
>>+                          ULONG sendFlags,
>>+                          OVS_PACKET_HDR_INFO *layers)
>>+{
>>+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
>>+    POVS_DEFERRED_ACTION_QUEUE queue = OvsDeferredActionsQueueGet();
>>+    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,
>>+                                                 portNo,
>>+                                                 layers);
>>+        }
>>+    }
>>+
>>+    return status;
>>+}
>>diff --git a/datapath-windows/ovsext/Recirc.h 
>>b/datapath-windows/ovsext/Recirc.h
>>new file mode 100644
>>index 0000000..8e6d125
>>--- /dev/null
>>+++ b/datapath-windows/ovsext/Recirc.h
>>@@ -0,0 +1,90 @@
>>+/*
>>+ * 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_licens
>>e
>>s_LICENSE-2D2.0&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=
>>p
>>NHQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=OpMpvAAJDApIpx1rELDZz_PzL7S9
>>h
>>fkeHD2h-6_KTCg&s=S30nm7dlEorfpeMZh2t0GL8LoSf_KXweQSeVsbNOCtg&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' structure is responsible for keeping 
>>track of
>>+ * all deferred actions. The maximum number of deferred actions should 
>>not
>>+ * exceed 'DEFERRED_ACTION_QUEUE_SIZE'.
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ */
>>+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
>>+ *     corresponding to the current CPU.
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ */
>>+NDIS_STATUS
>>+OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
>>+                          OvsCompletionList *completionList,
>>+                          UINT32 portNo,
>>+                          ULONG sendFlags,
>>+                          OVS_PACKET_HDR_INFO *layers);
>>+
>>+/*
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ * OvsAddDeferredActions --
>>+ *     This function adds the deferred action to the current CPU queue 
>>and
>>+ *     returns the new queue entry if the queue is not already full.
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ */
>>+POVS_DEFERRED_ACTION
>>+OvsAddDeferredActions(PNET_BUFFER_LIST packet,
>>+                      OvsFlowKey *key,
>>+                      UINT64 hash,
>>+                      const PNL_ATTR actions);
>>+
>>+/*
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ * OvsDeferredActionsQueueAlloc --
>>+ *     This function allocates an array of deferred action queues, one 
>>for
>>+ *     each CPU core.
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ */
>>+BOOLEAN
>>+OvsDeferredActionsQueueAlloc();
>>+
>>+/*
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ * OvsDeferredActionsQueueFree --
>>+ *     This function frees the array of deferred action queues.
>>+ * 
>>-------------------------------------------------------------------------
>>-
>>+ */
>>+VOID
>>+OvsDeferredActionsQueueFree();
>>+
>>+#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/Util.h 
>>b/datapath-windows/ovsext/Util.h
>>index b2ec798..038754d 100644
>>--- a/datapath-windows/ovsext/Util.h
>>+++ b/datapath-windows/ovsext/Util.h
>>@@ -36,6 +36,7 @@
>> #define OVS_STT_POOL_TAG                'RSVO'
>> #define OVS_GRE_POOL_TAG                'GSVO'
>> #define OVS_TUNFLT_POOL_TAG             'WSVO'
>>+#define OVS_RECIRC_POOL_TAG             'CSVO'
>> 
>> VOID *OvsAllocateMemory(size_t size);
>> VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag);
>>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</PreCompiledHeaderOu
>>t
>>putFile>
>>     </ClCompile>
>>+    <ClCompile Include="Recirc.c" />
>>     <ClCompile Include="Stt.c" />
>>     <ClCompile Include="Switch.c" />
>>     <ClCompile Include="Tunnel.c" />
>>-- 
>>1.9.0.msysgit.0
>>
>>_______________________________________________
>>dev mailing list
>>dev at openvswitch.org
>>https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailm
>>a
>>n_listinfo_dev&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=p
>>N
>>HQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=OpMpvAAJDApIpx1rELDZz_PzL7S9h
>>f
>>keHD2h-6_KTCg&s=B0JRbghGT_5kotOu2XQ_yegCP9Fj-DzzcfQ0dmmqKtU&e= 
>



More information about the dev mailing list