@@ -46,6 +46,7 @@ EXTRA_DIST += \
datapath-windows/ovsext/PacketIO.h \
datapath-windows/ovsext/PacketParser.c \
datapath-windows/ovsext/PacketParser.h \
+ datapath-windows/ovsext/Random.h \
datapath-windows/ovsext/Recirc.c \
datapath-windows/ovsext/Recirc.h \
datapath-windows/ovsext/Stt.c \
@@ -24,6 +24,7 @@
#include "NetProto.h"
#include "Offload.h"
#include "PacketIO.h"
+#include "Random.h"
#include "Recirc.h"
#include "Stt.h"
#include "Switch.h"
@@ -1585,6 +1586,132 @@ OvsActionExecuteHash(OvsFlowKey *key,
hash = 1;
key->dpHash = hash;
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsOutputUserspaceAction --
+ * Executes a sample action.
+ * --------------------------------------------------------------------------
+ */
+static __inline NDIS_STATUS
+OvsOutputUserspaceAction(OvsForwardingContext *ovsFwdCtx,
+ OvsFlowKey *key,
+ const PNL_ATTR attr)
+{
+ NTSTATUS status = NDIS_STATUS_SUCCESS;
+ PNL_ATTR userdataAttr;
+ PNL_ATTR queueAttr;
+ POVS_PACKET_QUEUE_ELEM elem;
+ POVS_PACKET_HDR_INFO layers = &ovsFwdCtx->layers;
+ BOOLEAN isRecv = FALSE;
+
+ POVS_VPORT_ENTRY vport = OvsFindVportByPortNo(ovsFwdCtx->switchContext,
+ ovsFwdCtx->srcVportNo);
+
+ if (vport) {
+ if (vport->isExternal ||
+ OvsIsTunnelVportType(vport->ovsType)) {
+ isRecv = TRUE;
+ }
+ }
+
+ queueAttr = NlAttrFindNested(attr, OVS_USERSPACE_ATTR_PID);
+ userdataAttr = NlAttrFindNested(attr, OVS_USERSPACE_ATTR_USERDATA);
+
+ elem = OvsCreateQueueNlPacket(NlAttrData(userdataAttr),
+ NlAttrGetSize(userdataAttr),
+ OVS_PACKET_CMD_ACTION,
+ vport, key, ovsFwdCtx->curNbl,
+ NET_BUFFER_LIST_FIRST_NB(ovsFwdCtx->curNbl),
+ isRecv,
+ layers);
+ if (elem) {
+ LIST_ENTRY missedPackets;
+ InitializeListHead(&missedPackets);
+ InsertTailList(&missedPackets, &elem->link);
+ OvsQueuePackets(&missedPackets, 1);
+ } else {
+ status = NDIS_STATUS_FAILURE;
+ }
+
+ return status;
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsExecuteSampleAction --
+ * Executes a sample action.
+ * --------------------------------------------------------------------------
+ */
+static __inline NDIS_STATUS
+OvsExecuteSampleAction(OvsForwardingContext *ovsFwdCtx,
+ OvsFlowKey *key,
+ UINT64 *hashAction,
+ const PNL_ATTR attr)
+{
+ PNET_BUFFER_LIST newNbl = NULL;
+ PNL_ATTR actionsList = NULL;
+ PNL_ATTR a = NULL;
+ INT rem = 0;
+ UINT64 hash = 0;
+
+ SRand();
+ NL_ATTR_FOR_EACH_UNSAFE(a, rem, NlAttrData(attr), NlAttrGetSize(attr)) {
+ switch (NlAttrType(a)) {
+ case OVS_SAMPLE_ATTR_PROBABILITY:
+ {
+ UINT32 probability = NlAttrGetU32(a);
+
+ if (!probability || Rand() > probability) {
+ return 0;
+ }
+ break;
+ }
+ case OVS_SAMPLE_ATTR_ACTIONS:
+ actionsList = a;
+ break;
+ }
+ }
+
+ if (actionsList) {
+ rem = NlAttrGetSize(actionsList);
+ a = (PNL_ATTR)NlAttrData(actionsList);
+ }
+
+ if (!rem) {
+ /* Actions list is empty, do nothing */
+ return STATUS_SUCCESS;
+ }
+
+ /*
+ * The only known usage of sample action is having a single user-space
+ * action. Treat this usage as a special case.
+ */
+ if (NlAttrType(a) == OVS_ACTION_ATTR_USERSPACE &&
+ NlAttrIsLast(a, rem)) {
+ return OvsOutputUserspaceAction(ovsFwdCtx, key, a);
+ }
+
+ newNbl = OvsPartialCopyNBL(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
+ 0, 0, TRUE /*copy NBL info*/);
+ if (newNbl == NULL) {
+ /*
+ * Skip the sample action when out of memory, but continue on with the
+ * rest of the action list.
+ */
+ ovsActionStats.noCopiedNbl++;
+ return STATUS_SUCCESS;
+ }
+
+ hash = hashAction ? *hashAction : OvsHashFlow(key);
+ if (!OvsAddDeferredActions(newNbl, key, hash, a)) {
+ OVS_LOG_INFO(
+ "Deferred actions limit reached, dropping sample action.");
+ OvsCompleteNBL(ovsFwdCtx->switchContext, newNbl, TRUE);
+ }
+
+ return STATUS_SUCCESS;
}
/*
@@ -1807,43 +1934,15 @@ OvsDoExecuteActions(POVS_SWITCH_CONTEXT switchContext,
case OVS_ACTION_ATTR_USERSPACE:
{
- PNL_ATTR userdataAttr;
- PNL_ATTR queueAttr;
- POVS_PACKET_QUEUE_ELEM elem;
- BOOLEAN isRecv = FALSE;
-
- POVS_VPORT_ENTRY vport = OvsFindVportByPortNo(switchContext,
- portNo);
-
- if (vport) {
- if (vport->isExternal ||
- OvsIsTunnelVportType(vport->ovsType)) {
- isRecv = TRUE;
- }
- }
-
- queueAttr = NlAttrFindNested(a, OVS_USERSPACE_ATTR_PID);
- userdataAttr = NlAttrFindNested(a, OVS_USERSPACE_ATTR_USERDATA);
-
- elem = OvsCreateQueueNlPacket((PVOID)userdataAttr,
- userdataAttr->nlaLen,
- OVS_PACKET_CMD_ACTION,
- vport, key, ovsFwdCtx.curNbl,
- NET_BUFFER_LIST_FIRST_NB(ovsFwdCtx.curNbl),
- isRecv,
- layers);
- if (elem) {
- LIST_ENTRY missedPackets;
- InitializeListHead(&missedPackets);
- InsertTailList(&missedPackets, &elem->link);
- OvsQueuePackets(&missedPackets, 1);
- dropReason = L"OVS-Completed since packet was copied to "
- L"userspace";
- } else {
+ status = OvsOutputUserspaceAction(&ovsFwdCtx, key,
+ (const PNL_ATTR)a);
+ if (status != NDIS_STATUS_SUCCESS) {
dropReason = L"OVS-Dropped due to failure to queue to "
L"userspace";
goto dropit;
}
+ dropReason = L"OVS-Completed since packet was copied to "
+ L"userspace";
break;
}
case OVS_ACTION_ATTR_SET:
@@ -1867,6 +1966,24 @@ OvsDoExecuteActions(POVS_SWITCH_CONTEXT switchContext,
break;
}
case OVS_ACTION_ATTR_SAMPLE:
+ {
+ 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 = OvsExecuteSampleAction(&ovsFwdCtx, key, hash,
+ (const PNL_ATTR)a);
+ if (status != NDIS_STATUS_SUCCESS) {
+ dropReason = L"OVS-sample action failed";
+ goto dropit;
+ }
+ break;
+ }
default:
status = NDIS_STATUS_NOT_SUPPORTED;
break;
new file mode 100644
@@ -0,0 +1,49 @@
+/*
+ * 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:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 __RANDOM_H_
+#define __RANDOM_H_ 1
+
+#include "precomp.h"
+
+static LARGE_INTEGER seed;
+
+/*
+ *----------------------------------------------------------------------------
+ * SRand --
+ * This function sets the starting seed value for the pseudorandom number
+ * generator.
+ *----------------------------------------------------------------------------
+ */
+static __inline
+VOID SRand()
+{
+ KeQuerySystemTime(&seed);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Rand --
+ * This function generates a pseudorandom number between 0 to UINT_MAX.
+ *----------------------------------------------------------------------------
+ */
+static __inline
+UINT32 Rand()
+{
+ return seed.LowPart *= 0x8088405 + 1;
+}
+
+#endif /* __RANDOM_H_ */
@@ -94,6 +94,7 @@
<ClInclude Include="PacketIO.h" />
<ClInclude Include="PacketParser.h" />
<ClInclude Include="precomp.h" />
+ <ClInclude Include="Random.h" />
<ClInclude Include="Recirc.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="Stt.h" />
This patch adds support for sampling to the OVS extension. Signed-off-by: Sorin Vinturis <svinturis@cloudbasesolutions.com> --- v3: No previous version. --- datapath-windows/automake.mk | 1 + datapath-windows/ovsext/Actions.c | 183 +++++++++++++++++++++++++++------ datapath-windows/ovsext/Random.h | 49 +++++++++ datapath-windows/ovsext/ovsext.vcxproj | 1 + 4 files changed, 201 insertions(+), 33 deletions(-) create mode 100644 datapath-windows/ovsext/Random.h