Hey Sorin,

Thanks for sending this out. I am currently working on a feature that
relies on recirculation. I tried applying the patch and encountered the
following errors in the log:

NlAttrParse:1103 Required attr:1 missing
_FlowNlGetCmdHandler:460 Attr Parsing failed for msg: FFFFE0000796E400
NlAttrParse:1103 Required attr:1 missing
_FlowNlGetCmdHandler:460 Attr Parsing failed for msg: FFFFE0000796E400
NlAttrParse:1103 Required attr:1 missing
_FlowNlGetCmdHandler:460 Attr Parsing failed for msg: FFFFE000035EA240
NlAttrParse:1103 Required attr:1 missing
_FlowNlGetCmdHandler:460 Attr Parsing failed for msg: FFFFE00002F17E40
NlAttrParse:1103 Required attr:1 missing
_FlowNlGetCmdHandler:460 Attr Parsing failed for msg: FFFFE00002F17E40
NlAttrParse:1103 Required attr:1 missing
_FlowNlGetCmdHandler:460 Attr Parsing failed for msg: FFFFE00002F17E40

Moreover, pings seem to fail after applying this. Are you encountering
something similar?


Thanks,
Sairam Venugopal

On 12/3/15, 1:14 AM, "Sorin Vinturis" <svintu...@cloudbasesolutions.com>
wrote:

>Recirculation support for the OVS extension.
>
>Signed-off-by: Sorin Vinturis <svintu...@cloudbasesolutions.com>
>Reported-by: Sorin Vinturis <svintu...@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=Zs90ntv9lKYhlT7rupj
>F5zlQhJthjBirTyHJcaPmaVM&s=RrejKSD4SCjSvjEmKmYkDxL_mqrp1jC7iCDZCpUmqQM&e=
>---
> datapath-windows/ovsext/Actions.c         | 202
>+++++++++++++++++++++++++++---
> datapath-windows/ovsext/Actions.h         |  54 ++++++++
> datapath-windows/ovsext/DpInternal.h      |   1 +
> datapath-windows/ovsext/Flow.c            |  49 ++++++++
> datapath-windows/ovsext/Flow.h            |   5 +-
> datapath-windows/ovsext/Netlink/Netlink.h |  11 ++
> datapath-windows/ovsext/PacketIO.c        |   1 +
> datapath-windows/ovsext/PacketIO.h        |  10 --
> datapath-windows/ovsext/Recirc.c          | 140 +++++++++++++++++++++
> datapath-windows/ovsext/Recirc.h          | 106 ++++++++++++++++
> datapath-windows/ovsext/Tunnel.c          |   1 +
> datapath-windows/ovsext/User.c            |   1 +
> datapath-windows/ovsext/ovsext.vcxproj    |   3 +
> 13 files changed, 553 insertions(+), 31 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/ovsext/Actions.c
>b/datapath-windows/ovsext/Actions.c
>index e902983..fbc34de 100644
>--- a/datapath-windows/ovsext/Actions.c
>+++ b/datapath-windows/ovsext/Actions.c
>@@ -14,7 +14,7 @@
>  * limitations under the License.
>  */
> 
>-#include "precomp.h"
>+#include "Actions.h"
> 
> #include "Switch.h"
> #include "Vport.h"
>@@ -26,6 +26,7 @@
> #include "Stt.h"
> #include "Checksum.h"
> #include "PacketIO.h"
>+#include "Recirc.h"
> 
> #ifdef OVS_DBG_MOD
> #undef OVS_DBG_MOD
>@@ -33,6 +34,8 @@
> #define OVS_DBG_MOD OVS_DBG_ACTION
> #include "Debug.h"
> 
>+#define OVS_DEST_PORTS_ARRAY_MIN_SIZE 2
>+
> typedef struct _OVS_ACTION_STATS {
>     UINT64 rxVxlan;
>     UINT64 txVxlan;
>@@ -62,7 +65,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. */
>@@ -95,7 +97,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.
>@@ -113,7 +115,6 @@ typedef struct OvsForwardingContext {
>     OVS_PACKET_HDR_INFO layers;
> } OvsForwardingContext;
> 
>-
> /*
>  * 
>--------------------------------------------------------------------------
>  * OvsInitForwardingCtx --
>@@ -581,11 +582,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;
>@@ -1379,10 +1382,58 @@ OvsExecuteSetAction(OvsForwardingContext
>*ovsFwdCtx,
>     }
>     return status;
> }
>+
>+/*
>+ * 
>--------------------------------------------------------------------------
>+ * 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 *hash,
>+                       const PNL_ATTR actions,
>+                       int rem)
>+{
>+    POVS_DEFERRED_ACTION deferredAction = NULL;
>+    PNET_BUFFER_LIST newNbl = NULL;
>+
>+    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;
>+    }
>+
>+    deferredAction = OvsAddDeferredActions(nbl, key, hash, NULL);
>+    if (deferredAction) {
>+        deferredAction->key.recircId = NlAttrGetU32(actions);
>+    } else {
>+        if (newNbl) {
>+            OvsCompleteNBL(switchContext, newNbl, TRUE);
>+        }
>+    }
>+
>+    return STATUS_SUCCESS;
>+}
> 
> /*
>  * 
>--------------------------------------------------------------------------
>- * OvsActionsExecute --
>+ * 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
>@@ -1399,16 +1450,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;
>@@ -1513,6 +1564,30 @@ 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-set recirculation failed";
>+                goto dropit;
>+            }
>+
>+            if (NlAttrIsLast(a, rem)) {
>+                goto exit;
>+            }
>+            break;
>+        }
>+
>         case OVS_ACTION_ATTR_USERSPACE:
>         {
>             PNL_ATTR userdataAttr;
>@@ -1599,5 +1674,92 @@ 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;
>+    OvsForwardingContext ovsFwdCtx;
>+    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);
>+
>+    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..01ad8d2
>--- /dev/null
>+++ b/datapath-windows/ovsext/Actions.h
>@@ -0,0 +1,54 @@
>+/*
>+ * Copyright (c) 2015 Cloudbase Solutions Srl
>+ *
>+ * Licensed under the Apache License, Version 2.0 (the "License");
>+ * you may not use this file except in compliance with the License.
>+ * You may obtain a copy of the License at:
>+ *
>+ *     
>https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_license
>s_LICENSE-2D2.0&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=D
>cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=Zs90ntv9lKYhlT7rupjF5zlQhJthj
>BirTyHJcaPmaVM&s=OFsPb6sq-Dp3dCViFalg7pJ9JWEbn4jeZyy4bPtVHF0&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/DpInternal.h
>b/datapath-windows/ovsext/DpInternal.h
>index 466a33a..b7e011f 100644
>--- a/datapath-windows/ovsext/DpInternal.h
>+++ b/datapath-windows/ovsext/DpInternal.h
>@@ -158,6 +158,7 @@ typedef __declspec(align(8)) struct OvsFlowKey {
>         Ipv6Key ipv6Key;         /* size 48 */
>         Icmp6Key icmp6Key;       /* size 72 */
>     };
>+    UINT32 recircId;
> } OvsFlowKey;
> 
> #define OVS_WIN_TUNNEL_KEY_SIZE (sizeof (OvsIPv4TunnelKey))
>diff --git a/datapath-windows/ovsext/Flow.c
>b/datapath-windows/ovsext/Flow.c
>index 31ddc66..099f1c9 100644
>--- a/datapath-windows/ovsext/Flow.c
>+++ b/datapath-windows/ovsext/Flow.c
>@@ -818,6 +818,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);
>@@ -1308,6 +1314,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]);
> 
>@@ -1993,6 +2003,45 @@ 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)
>+{
>+    if (!hash || !(*hash)) {
>+        return OvsLookupFlow(datapath, key, hash, FALSE);
>+    }
>+
>+    /*
>+     * Pre and post recirulation flows usually have the same hash
>+     * value. To avoid hash collisions, rehash the 'hash' with
>+     * 'recircId'.
>+     */
>+    if (key->recircId) {
>+        UINT16 offset = key->l2.offset;
>+        UINT16 size = key->l2.keyLen;
>+        UINT8 *start;
>+
>+        start = (UINT8 *)key + offset;
>+        *hash = OvsJhashBytes(start, size, key->recircId);
>+    }
>+
>+    return OvsLookupFlow(datapath, key, hash, TRUE);
>+}
>+
> 
> /*
>  * 
>--------------------------------------------------------------------------
>--
>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 d270737..5cdd0c3 100644
>--- a/datapath-windows/ovsext/Netlink/Netlink.h
>+++ b/datapath-windows/ovsext/Netlink/Netlink.h
>@@ -172,6 +172,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..44e2dda 100644
>--- a/datapath-windows/ovsext/PacketIO.c
>+++ b/datapath-windows/ovsext/PacketIO.c
>@@ -28,6 +28,7 @@
> #include "Flow.h"
> #include "Event.h"
> #include "User.h"
>+#include "Actions.h"
> 
> /* Due to an imported header file */
> #pragma warning( disable:4505 )
>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..a594806
>--- /dev/null
>+++ b/datapath-windows/ovsext/Recirc.c
>@@ -0,0 +1,140 @@
>+#include "Recirc.h"
>+#include "Flow.h"
>+#include "Jhash.h"
>+
>+static OVS_DEFERRED_ACTION_QUEUE ovsDeferredActionsQueue = { 0 };
>+
>+/*
>+ * 
>--------------------------------------------------------------------------
>+ * 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)
>+{
>+    if (OvsDeferredActionsQueueIsEmpty(queue))
>+              return NULL;
>+
>+    return &queue->queue[queue->tail++];
>+}
>+
>+/*
>+ * 
>--------------------------------------------------------------------------
>+ * OvsDeferredActionsQueuePush --
>+ *     The function pushes the current element in the deferred actions
>queue.
>+ * 
>--------------------------------------------------------------------------
>+ */
>+static
>+POVS_DEFERRED_ACTION
>+OvsDeferredActionsQueuePush(POVS_DEFERRED_ACTION_QUEUE queue)
>+{
>+    if (queue->head >= DEFERRED_ACTION_QUEUE_SIZE - 1)
>+              return NULL;
>+
>+    return &queue->queue[queue->head++];
>+}
>+
>+/*
>+ * 
>--------------------------------------------------------------------------
>+ * OvsAddDeferredActions --
>+ *     The function 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)
>+{
>+    POVS_DEFERRED_ACTION deferredAction = NULL;
>+
>+    deferredAction =
>OvsDeferredActionsQueuePush(&ovsDeferredActionsQueue);
>+    if (deferredAction) {
>+        deferredAction->packet = packet;
>+        deferredAction->actions = actions;
>+        deferredAction->key = *key;
>+        deferredAction->hash = hash ? *hash : 0;
>+    }
>+
>+    return deferredAction;
>+}
>+
>+/*
>+ * 
>--------------------------------------------------------------------------
>+ * OvsProcessDeferredActions --
>+ *     The function processes all deferred actions contained in the
>queue.
>+ * 
>--------------------------------------------------------------------------
>+ */
>+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;
>+
>+    if (OvsDeferredActionsQueueIsEmpty(queue))
>+        return STATUS_SUCCESS;
>+
>+    /* Process all deferred actions. */
>+    do {
>+        POVS_DEFERRED_ACTION deferredAction =
>+            OvsDeferredActionsQueuePop(queue);
>+        const PNL_ATTR actions = deferredAction->actions;
>+
>+        if (actions) {
>+            status = OvsDoExecuteActions(switchContext,
>+                                         completionList,
>+                                         deferredAction->packet,
>+                                         portNo,
>+                                         sendFlags,
>+                                         &deferredAction->key,
>+                                         &deferredAction->hash,
>+                                         layers, actions,
>+                                         NlAttrLen(actions));
>+        } else {
>+            status = OvsDoRecircFlowLookupOutput(switchContext,
>+                                                 completionList,
>+                                                 deferredAction->packet,
>+                                                 &deferredAction->key,
>+                                                 &deferredAction->hash);
>+        }
>+    } while (!OvsDeferredActionsQueueIsEmpty(queue));
>+
>+    /* Reset the queue for the next packet. */
>+    OvsDeferredActionsQueueInit(queue);
>+
>+    return status;
>+}
>diff --git a/datapath-windows/ovsext/Recirc.h
>b/datapath-windows/ovsext/Recirc.h
>new file mode 100644
>index 0000000..3a378d5
>--- /dev/null
>+++ b/datapath-windows/ovsext/Recirc.h
>@@ -0,0 +1,106 @@
>+/*
>+ * Copyright (c) 2015 Cloudbase Solutions Srl
>+ *
>+ * Licensed under the Apache License, Version 2.0 (the "License");
>+ * you may not use this file except in compliance with the License.
>+ * You may obtain a copy of the License at:
>+ *
>+ *     
>https://urldefense.proofpoint.com/v2/url?u=http-3A__www.apache.org_license
>s_LICENSE-2D2.0&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=D
>cruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=Zs90ntv9lKYhlT7rupjF5zlQhJthj
>BirTyHJcaPmaVM&s=OFsPb6sq-Dp3dCViFalg7pJ9JWEbn4jeZyy4bPtVHF0&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
>+
>+/*
>+ * Recirculation
>+ * =============
>+ *
>+ * Recirculation is the technique to allow a frame to re-enter the
>datapath
>+ * packet processing path to achieve more flexible packet processing,
>such as
>+ * modifying header fields after MPLS POP action and selecting a slave
>port for
>+ * bond ports.
>+ *
>+ * Data path and user space interface
>+ * -----------------------------------
>+ *
>+ * Recirculation uses two uint32_t fields, recirc_id and dp_hash, and a
>RECIRC
>+ * action.  recirc_id is used to select the next packet processing steps
>among
>+ * multiple instances of recirculation.  When a packet initially enters
>the
>+ * datapath it is assigned with recirc_id 0, which indicates no
>recirculation.
>+ * Recirc_ids are managed by the user space, opaque to the datapath.
>+ *
>+ * On the other hand, dp_hash can only be computed by the datapath,
>opaque to
>+ * the user space, as the datapath is free to choose the hashing
>algorithm
>+ * without informing user space about it.  The dp_hash value should be
>+ * wildcarded for newly received packets.  HASH action specifies whether
>the
>+ * hash is computed, and if computed, how many fields are to be included
>in the
>+ * hash computation.  The computed hash value is stored into the dp_hash
>field
>+ * prior to recirculation.
>+ *
>+ * The RECIRC action sets the recirc_id field and then reprocesses the
>packet
>+ * as if it was received again on the same input port.  RECIRC action
>works
>+ * like a function call; actions listed after the RECIRC action will be
>+ * executed after recirculation.  RECIRC action can be nested, but
>datapath
>+ * implementation limits the number of nested recirculations to prevent
>+ * unreasonable nesting depth or infinite loop.
>+ *
>+ * User space recirculation context
>+ * ---------------------------------
>+ *
>+ * Recirculation is usually hidden from the OpenFlow controllers.  Action
>+ * translation code deduces when recirculation is necessary and issues a
>+ * datapath recirculation action.  All OpenFlow actions to be performed
>after
>+ * recirculation are derived from the OpenFlow pipeline and are stored
>with the
>+ * recirculation ID.  When the OpenFlow tables are changed in a way
>affecting
>+ * the recirculation flows, new recirculation ID with new metadata and
>actions
>+ * is allocated and the old one is timed out.
>+ *
>+ * Recirculation ID pool
>+ * ----------------------
>+ *
>+ * Recirculation ID needs to be unique for all datapaths.  Recirculation
>ID
>+ * pool keeps track of recirculation ids and stores OpenFlow pipeline
>+ * translation context so that flow processing may continue after
>+ * recirculation.
>+ *
>+ * A Recirculation ID can be any uint32_t value, except for that the
>value 0 is
>+ * reserved for 'no recirculation' case.
>+ */
>+
>+typedef struct _OVS_DEFERRED_ACTION {
>+    PNET_BUFFER_LIST    packet;
>+    PNL_ATTR            actions;
>+    OvsFlowKey          key;
>+    UINT64              hash;
>+} OVS_DEFERRED_ACTION, *POVS_DEFERRED_ACTION;
>+
>+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;
>+
>+NTSTATUS
>+OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
>+                          OvsCompletionList *completionList,
>+                          UINT32 portNo,
>+                          ULONG sendFlags,
>+                          OVS_PACKET_HDR_INFO *layers);
>+
>+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..88a7929 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;
> 
>diff --git a/datapath-windows/ovsext/User.c
>b/datapath-windows/ovsext/User.c
>index 42af7f3..3f4e307 100644
>--- a/datapath-windows/ovsext/User.c
>+++ b/datapath-windows/ovsext/User.c
>@@ -33,6 +33,7 @@
> #include "Flow.h"
> #include "TunnelIntf.h"
> #include "Jhash.h"
>+#include "Actions.h"
> 
> #ifdef OVS_DBG_MOD
> #undef OVS_DBG_MOD
>diff --git a/datapath-windows/ovsext/ovsext.vcxproj 
>b/datapath-windows/ovsext/ovsext.vcxproj
>index 616f688..6987035 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="Checksum.h" />
>@@ -91,6 +92,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" />
>@@ -186,6 +188,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.0.msysgit.0
>_______________________________________________
>dev mailing list
>dev@openvswitch.org
>https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailma
>n_listinfo_dev&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=Dc
>ruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=Zs90ntv9lKYhlT7rupjF5zlQhJthjB
>irTyHJcaPmaVM&s=sJRx8MU4p5gl0J2boMWHh8rvmXINtnnkbUJY8DhFizU&e= 

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to