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