[ovs-dev] [PATCH v2] datapath-windows: Hot add CPU support.
Sorin Vinturis
svinturis at cloudbasesolutions.com
Mon Apr 4 10:03:50 UTC 2016
Hot add CPU is the ability to dynamically add CPUs to a running
system. Adding CPUs can occur physically by adding new hardware,
logically by online hardware partitioning, or virtually through
a virtualization layer.
This patch add support to reallocate any per-cpu resources, in
case a new processor is added.
Signed-off-by: Sorin Vinturis <svinturis at cloudbasesolutions.com>
Reported-by: Sorin Vinturis <svinturis at cloudbasesolutions.com>
Reported-at: https://github.com/openvswitch/ovs-issues/issues/112
---
v2: Correctly reallocate per-cpu data structures when a new processor
is about to be added to the system.
---
datapath-windows/ovsext/Actions.c | 11 +-
datapath-windows/ovsext/Datapath.c | 4 -
datapath-windows/ovsext/Driver.c | 9 ++
datapath-windows/ovsext/Recirc.c | 249 +++++++++++++++++++++++++++++++------
datapath-windows/ovsext/Recirc.h | 87 ++++++-------
datapath-windows/ovsext/Util.c | 142 ++++++++++++++++++++-
datapath-windows/ovsext/Util.h | 35 +++++-
7 files changed, 442 insertions(+), 95 deletions(-)
diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c
index 3e5dac9..5c39951 100644
--- a/datapath-windows/ovsext/Actions.c
+++ b/datapath-windows/ovsext/Actions.c
@@ -40,6 +40,8 @@
#define OVS_DEST_PORTS_ARRAY_MIN_SIZE 2
+extern PNDIS_RW_LOCK_EX ovsDeferredActionLevelLock;
+
typedef struct _OVS_ACTION_STATS {
UINT64 rxGre;
UINT64 txGre;
@@ -1973,14 +1975,19 @@ OvsDoRecirc(POVS_SWITCH_CONTEXT switchContext,
flow = OvsLookupFlow(&ovsFwdCtx.switchContext->datapath, key, &hash, FALSE);
if (flow) {
- UINT32 level = OvsDeferredActionsLevelGet();
+ UINT32 level = 0;
+ LOCK_STATE_EX lockState;
+
+ NdisAcquireRWLockRead(ovsDeferredActionLevelLock, &lockState, 0);
+ level = OvsDeferredActionsLevelGet();
if (level > DEFERRED_ACTION_EXEC_LEVEL) {
OvsCompleteNBLForwardingCtx(&ovsFwdCtx,
L"OVS-Dropped due to deferred actions execution level limit \
reached");
ovsActionStats.deferredActionsExecLimit++;
ovsFwdCtx.curNbl = NULL;
+ NdisReleaseRWLock(ovsDeferredActionLevelLock, &lockState);
return NDIS_STATUS_FAILURE;
}
@@ -1999,6 +2006,8 @@ OvsDoRecirc(POVS_SWITCH_CONTEXT switchContext,
ovsFwdCtx.curNbl = NULL;
OvsDeferredActionsLevelDec();
+
+ NdisReleaseRWLock(ovsDeferredActionLevelLock, &lockState);
} else {
POVS_VPORT_ENTRY vport = NULL;
LIST_ENTRY missedPackets;
diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c
index 464fa97..5725114 100644
--- a/datapath-windows/ovsext/Datapath.c
+++ b/datapath-windows/ovsext/Datapath.c
@@ -385,8 +385,6 @@ OvsInit()
gOvsCtrlLock = &ovsCtrlLockObj;
NdisAllocateSpinLock(gOvsCtrlLock);
OvsInitEventQueue();
- OvsDeferredActionsQueueAlloc();
- OvsDeferredActionsLevelAlloc();
}
VOID
@@ -397,8 +395,6 @@ OvsCleanup()
NdisFreeSpinLock(gOvsCtrlLock);
gOvsCtrlLock = NULL;
}
- OvsDeferredActionsQueueFree();
- OvsDeferredActionsLevelFree();
}
VOID
diff --git a/datapath-windows/ovsext/Driver.c b/datapath-windows/ovsext/Driver.c
index 853886e..f5d3f9c 100644
--- a/datapath-windows/ovsext/Driver.c
+++ b/datapath-windows/ovsext/Driver.c
@@ -152,6 +152,12 @@ DriverEntry(PDRIVER_OBJECT driverObject,
goto cleanup;
}
+ /* Allocate per-cpu structures and register processor change callback. */
+ status = OvsPerCpuDataInit(gOvsExtDriverHandle);
+ if (!NT_SUCCESS(status)) {
+ goto cleanup;
+ }
+
cleanup:
if (status != NDIS_STATUS_SUCCESS){
OvsCleanup();
@@ -180,6 +186,9 @@ OvsExtUnload(struct _DRIVER_OBJECT *driverObject)
OvsDeleteDeviceObject();
+ /* Release per-cpu structures and deregister processor change callback. */
+ OvsPerCpuDataCleanup();
+
NdisFDeregisterFilterDriver(gOvsExtDriverHandle);
}
diff --git a/datapath-windows/ovsext/Recirc.c b/datapath-windows/ovsext/Recirc.c
index 86e6f51..5ef1992 100644
--- a/datapath-windows/ovsext/Recirc.c
+++ b/datapath-windows/ovsext/Recirc.c
@@ -18,71 +18,218 @@
#include "Flow.h"
#include "Jhash.h"
-static POVS_DEFERRED_ACTION_QUEUE ovsDeferredActionQueue = NULL;
-static UINT32* ovsDeferredActionLevel = NULL;
+/*
+ * --------------------------------------------------------------------------
+ * '_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;
+
+static POVS_DEFERRED_ACTION_QUEUE ovsDeferredActionQueue = NULL;
+static UINT32* ovsDeferredActionLevel = NULL;
+static PNDIS_RW_LOCK_EX ovsDeferredActionQueueLock = NULL;
+PNDIS_RW_LOCK_EX ovsDeferredActionLevelLock = NULL;
+static ULONG ovsActiveProcessorCount = 0;
/*
* --------------------------------------------------------------------------
- * OvsDeferredActionsQueueAlloc --
- * The function allocates per-cpu deferred actions queue.
+ * OvsDeferredActionsLevelRealloc --
+ * The function allocates per-processor deferred actions level.
* --------------------------------------------------------------------------
*/
-BOOLEAN
-OvsDeferredActionsQueueAlloc()
+NTSTATUS
+OvsDeferredActionsLevelRealloc(BOOLEAN addCpu, PULONG count)
{
- ovsDeferredActionQueue =
- OvsAllocateMemoryPerCpu(sizeof(*ovsDeferredActionQueue),
- OVS_RECIRC_POOL_TAG);
- if (!ovsDeferredActionQueue) {
- return FALSE;
+ NTSTATUS status = STATUS_SUCCESS;
+ PUINT32 level = NULL;
+ LOCK_STATE_EX lockState;
+
+ NdisAcquireRWLockWrite(ovsDeferredActionLevelLock, &lockState, 0);
+
+ level = OvsReallocateMemoryPerCpu(ovsDeferredActionLevel,
+ sizeof(*ovsDeferredActionLevel),
+ OVS_RECIRC_POOL_TAG,
+ addCpu,
+ ovsActiveProcessorCount,
+ count);
+ if (!level) {
+ NdisReleaseRWLock(ovsDeferredActionLevelLock, &lockState);
+ status = NDIS_STATUS_RESOURCES;
+ goto exit;
}
- return TRUE;
+
+ ovsDeferredActionLevel = level;
+
+ NdisReleaseRWLock(ovsDeferredActionLevelLock, &lockState);
+
+exit:
+ return status;
}
/*
* --------------------------------------------------------------------------
- * OvsDeferredActionsQueueFree --
- * The function frees per-cpu deferred actions queue.
+ * OvsDeferredActionsQueueRealloc --
+ * The function allocates per-processor deferred actions queue.
* --------------------------------------------------------------------------
*/
-VOID
-OvsDeferredActionsQueueFree()
+NTSTATUS
+OvsDeferredActionsQueueRealloc(BOOLEAN addCpu, PULONG count)
{
- OvsFreeMemoryWithTag(ovsDeferredActionQueue,
- OVS_RECIRC_POOL_TAG);
- ovsDeferredActionQueue = NULL;
+ NTSTATUS status = STATUS_SUCCESS;
+ POVS_DEFERRED_ACTION_QUEUE queue = NULL;
+ LOCK_STATE_EX lockState;
+
+ NdisAcquireRWLockWrite(ovsDeferredActionQueueLock, &lockState, 0);
+
+ queue = OvsReallocateMemoryPerCpu(ovsDeferredActionQueue,
+ sizeof(*ovsDeferredActionQueue),
+ OVS_RECIRC_POOL_TAG,
+ addCpu,
+ ovsActiveProcessorCount,
+ count);
+ if (!queue) {
+ NdisReleaseRWLock(ovsDeferredActionQueueLock, &lockState);
+ status = NDIS_STATUS_RESOURCES;
+ goto exit;
+ }
+
+ ovsDeferredActionQueue = queue;
+
+ NdisReleaseRWLock(ovsDeferredActionQueueLock, &lockState);
+
+exit:
+ return status;
}
/*
* --------------------------------------------------------------------------
- * OvsDeferredActionsLevelAlloc --
- * The function allocates per-cpu deferred actions execution level.
+ * OvsDeferredActionsRealloc --
+ * The function reallocates per-cpu necessary resources and is triggered
+ * by the 'OvsCpuChange' callback.
+ *
+ * If the function was triggered by a 'KeProcessorAddStartNotify'
+ * notification, it means that the operating system is about to add a
+ * new processor and the function reallocates new space to accomodate
+ * new per-processor data requirements.
+ *
+ * If the function was triggered by a 'KeProcessorAddFailureNotify'
+ * notification, it means that the operating system failed to add the
+ * new processor and the function frees all per-processor resources
+ * that were allocated for the new processor.
* --------------------------------------------------------------------------
*/
-BOOLEAN
-OvsDeferredActionsLevelAlloc()
+NTSTATUS
+OvsDeferredActionsRealloc(BOOLEAN addCpu)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG count = 0;
+
+ status = OvsDeferredActionsQueueRealloc(addCpu, &count);
+ if (!NT_SUCCESS(status)) {
+ goto exit;
+ }
+
+ status = OvsDeferredActionsLevelRealloc(addCpu, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto exit;
+ }
+
+ ovsActiveProcessorCount = count;
+
+exit:
+ return status;
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsDeferredActionsInit --
+ * The function allocates all necessary per-processor deferred actions
+ * resources.
+ * --------------------------------------------------------------------------
+ */
+NTSTATUS
+OvsDeferredActionsInit(NDIS_HANDLE NdisFilterHandle)
{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ ovsDeferredActionQueueLock = NdisAllocateRWLock(NdisFilterHandle);
+ if (!ovsDeferredActionQueueLock) {
+ status = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ ovsDeferredActionLevelLock = NdisAllocateRWLock(NdisFilterHandle);
+ if (!ovsDeferredActionLevelLock) {
+ status = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ ovsDeferredActionQueue =
+ OvsAllocateMemoryPerCpu(sizeof(*ovsDeferredActionQueue),
+ OVS_RECIRC_POOL_TAG,
+ FALSE,
+ &ovsActiveProcessorCount);
+ if (!ovsDeferredActionQueue) {
+ status = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
ovsDeferredActionLevel =
OvsAllocateMemoryPerCpu(sizeof(*ovsDeferredActionLevel),
- OVS_RECIRC_POOL_TAG);
+ OVS_RECIRC_POOL_TAG,
+ FALSE,
+ NULL);
if (!ovsDeferredActionLevel) {
- return FALSE;
+ status = NDIS_STATUS_RESOURCES;
+ goto cleanup;
}
- return TRUE;
+
+cleanup:
+ if (!NT_SUCCESS(status)) {
+ OvsDeferredActionsCleanup();
+ }
+
+ return status;
}
/*
* --------------------------------------------------------------------------
- * OvsDeferredActionsLevelFree --
- * The function frees per-cpu deferred actions execution level.
+ * OvsDeferredActionsCleanup --
+ * The function frees all per-processor deferred actions resources.
* --------------------------------------------------------------------------
*/
VOID
-OvsDeferredActionsLevelFree()
+OvsDeferredActionsCleanup()
{
- OvsFreeMemoryWithTag(ovsDeferredActionLevel,
- OVS_RECIRC_POOL_TAG);
- ovsDeferredActionLevel = NULL;
+ if (ovsDeferredActionLevel) {
+ OvsFreeMemoryWithTag(ovsDeferredActionLevel,
+ OVS_RECIRC_POOL_TAG);
+ ovsDeferredActionLevel = NULL;
+ }
+
+ if (ovsDeferredActionQueue) {
+ OvsFreeMemoryWithTag(ovsDeferredActionQueue,
+ OVS_RECIRC_POOL_TAG);
+ ovsDeferredActionQueue = NULL;
+ }
+
+ if (ovsDeferredActionLevelLock) {
+ NdisFreeRWLock(ovsDeferredActionLevelLock);
+ ovsDeferredActionLevelLock = NULL;
+ }
+
+ if (ovsDeferredActionQueueLock) {
+ NdisFreeRWLock(ovsDeferredActionQueueLock);
+ ovsDeferredActionQueueLock = NULL;
+ }
+
+ ovsActiveProcessorCount = 0;
}
/*
@@ -104,7 +251,9 @@ OvsDeferredActionsQueueGet()
}
index = KeGetCurrentProcessorNumberEx(NULL);
- queue = &ovsDeferredActionQueue[index];
+ if (index < ovsActiveProcessorCount) {
+ queue = &ovsDeferredActionQueue[index];
+ }
if (oldIrql < DISPATCH_LEVEL) {
KeLowerIrql(oldIrql);
@@ -132,7 +281,9 @@ OvsDeferredActionsLevelGet()
}
index = KeGetCurrentProcessorNumberEx(NULL);
- level = &ovsDeferredActionLevel[index];
+ if (index < ovsActiveProcessorCount) {
+ level = &ovsDeferredActionLevel[index];
+ }
if (oldIrql < DISPATCH_LEVEL) {
KeLowerIrql(oldIrql);
@@ -160,8 +311,10 @@ OvsDeferredActionsLevelInc()
}
index = KeGetCurrentProcessorNumberEx(NULL);
- level = &ovsDeferredActionLevel[index];
- (*level)++;
+ if (index < ovsActiveProcessorCount) {
+ level = &ovsDeferredActionLevel[index];
+ (*level)++;
+ }
if (oldIrql < DISPATCH_LEVEL) {
KeLowerIrql(oldIrql);
@@ -187,8 +340,10 @@ OvsDeferredActionsLevelDec()
}
index = KeGetCurrentProcessorNumberEx(NULL);
- level = &ovsDeferredActionLevel[index];
- (*level)--;
+ if (index < ovsActiveProcessorCount) {
+ level = &ovsDeferredActionLevel[index];
+ (*level)--;
+ }
if (oldIrql < DISPATCH_LEVEL) {
KeLowerIrql(oldIrql);
@@ -293,8 +448,13 @@ OvsAddDeferredActions(PNET_BUFFER_LIST nbl,
OvsFlowKey *key,
const PNL_ATTR actions)
{
- POVS_DEFERRED_ACTION_QUEUE queue = OvsDeferredActionsQueueGet();
+ POVS_DEFERRED_ACTION_QUEUE queue = NULL;
POVS_DEFERRED_ACTION deferredAction = NULL;
+ LOCK_STATE_EX lockState;
+
+ NdisAcquireRWLockRead(ovsDeferredActionQueueLock, &lockState, 0);
+
+ queue = OvsDeferredActionsQueueGet();
deferredAction = OvsDeferredActionsQueuePush(queue);
if (deferredAction) {
@@ -303,6 +463,8 @@ OvsAddDeferredActions(PNET_BUFFER_LIST nbl,
deferredAction->key = *key;
}
+ NdisReleaseRWLock(ovsDeferredActionQueueLock, &lockState);
+
return deferredAction;
}
@@ -321,8 +483,13 @@ OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
OVS_PACKET_HDR_INFO *layers)
{
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
- POVS_DEFERRED_ACTION_QUEUE queue = OvsDeferredActionsQueueGet();
+ POVS_DEFERRED_ACTION_QUEUE queue = NULL;
POVS_DEFERRED_ACTION deferredAction = NULL;
+ LOCK_STATE_EX lockState;
+
+ NdisAcquireRWLockRead(ovsDeferredActionQueueLock, &lockState, 0);
+
+ queue = OvsDeferredActionsQueueGet();
/* Process all deferred actions. */
while ((deferredAction = OvsDeferredActionsQueuePop(queue)) != NULL) {
@@ -345,5 +512,7 @@ OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
}
}
+ NdisReleaseRWLock(ovsDeferredActionQueueLock, &lockState);
+
return status;
}
diff --git a/datapath-windows/ovsext/Recirc.h b/datapath-windows/ovsext/Recirc.h
index ee05763..240b492 100644
--- a/datapath-windows/ovsext/Recirc.h
+++ b/datapath-windows/ovsext/Recirc.h
@@ -30,19 +30,6 @@ typedef struct _OVS_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.
@@ -69,68 +56,72 @@ OvsAddDeferredActions(PNET_BUFFER_LIST packet,
/*
* --------------------------------------------------------------------------
- * OvsDeferredActionsQueueAlloc --
- * The function allocates per-cpu deferred actions queue.
+ * OvsDeferredActionsLevelGet --
+ * The function returns the deferred action execution level corresponding
+ * to the current processor.
* --------------------------------------------------------------------------
*/
-BOOLEAN
-OvsDeferredActionsQueueAlloc();
+UINT32
+OvsDeferredActionsLevelGet();
/*
* --------------------------------------------------------------------------
- * OvsDeferredActionsQueueFree --
- * The function frees per-cpu deferred actions queue.
+ * OvsDeferredActionsLevelInc --
+ * The function increments the deferred action execution level
+ * corresponding to the current processor.
* --------------------------------------------------------------------------
*/
VOID
-OvsDeferredActionsQueueFree();
-
-/*
- * --------------------------------------------------------------------------
- * OvsDeferredActionsLevelAlloc --
- * The function allocates per-cpu deferred actions execution level.
- * --------------------------------------------------------------------------
- */
-BOOLEAN
-OvsDeferredActionsLevelAlloc();
+OvsDeferredActionsLevelInc();
/*
* --------------------------------------------------------------------------
- * OvsDeferredActionsLevelFree --
- * The function frees per-cpu deferred actions execution level.
+ * OvsDeferredActionsLevelDec --
+ * The function decrements the deferred action execution level
+ * corresponding to the current processor.
* --------------------------------------------------------------------------
- */
+*/
VOID
-OvsDeferredActionsLevelFree();
+OvsDeferredActionsLevelDec();
/*
* --------------------------------------------------------------------------
- * OvsDeferredActionsLevelGet --
- * The function returns the deferred action execution level corresponding
- * to the current processor.
+ * OvsDeferredActionsRealloc --
+ * The function reallocates per-cpu necessary resources and is triggered
+ * by the 'OvsCpuChange' callback.
+ *
+ * If the function was triggered due to a 'KeProcessorAddStartNotify'
+ * notification, it means that the operating system is about to add a
+ * new processor and the function reallocates new space to accomodate
+ * new per-processor data requirements.
+ *
+ * If the function was triggered due to a 'KeProcessorAddFailureNotify'
+ * notification, it means that the operating system failed to add the
+ * new processor and the function frees all per-processor resources
+ * that were allocated for the new processor.
* --------------------------------------------------------------------------
*/
-UINT32
-OvsDeferredActionsLevelGet();
+NTSTATUS
+OvsDeferredActionsRealloc(BOOLEAN addCpu);
/*
* --------------------------------------------------------------------------
- * OvsDeferredActionsLevelInc --
- * The function increments the deferred action execution level
- * corresponding to the current processor.
+ * OvsDeferredActionsInit --
+ * The function allocates necessary per-processor resources and registers
+ * processor change callback.
* --------------------------------------------------------------------------
*/
-VOID
-OvsDeferredActionsLevelInc();
+NTSTATUS
+OvsDeferredActionsInit(NDIS_HANDLE NdisFilterHandle);
/*
* --------------------------------------------------------------------------
- * OvsDeferredActionsLevelDec --
- * The function decrements the deferred action execution level
- * corresponding to the current processor.
+ * OvsDeferredActionsCleanup --
+ * The function frees all per-processor resources and deregisters
+ * processor change callback.
* --------------------------------------------------------------------------
-*/
+ */
VOID
-OvsDeferredActionsLevelDec();
+OvsDeferredActionsCleanup();
#endif /* __RECIRC_H_ */
diff --git a/datapath-windows/ovsext/Util.c b/datapath-windows/ovsext/Util.c
index 14c4493..12f6eac 100644
--- a/datapath-windows/ovsext/Util.c
+++ b/datapath-windows/ovsext/Util.c
@@ -15,6 +15,7 @@
*/
#include "precomp.h"
+#include "Recirc.h"
#ifdef OVS_DBG_MOD
#undef OVS_DBG_MOD
#endif
@@ -23,6 +24,7 @@
#include "Debug.h"
extern NDIS_HANDLE gOvsExtDriverHandle;
+static VOID* ovsRegistrationHandle = NULL;
VOID*
OvsAllocateMemoryWithTag(size_t size, ULONG tag)
@@ -118,17 +120,155 @@ OvsCompareString(PVOID string1, PVOID string2)
}
VOID *
-OvsAllocateMemoryPerCpu(size_t size, ULONG tag)
+OvsAllocateMemoryPerCpu(size_t size,
+ ULONG tag,
+ BOOLEAN addCpu,
+ PULONG cpuCount)
{
VOID *ptr = NULL;
ULONG count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
ASSERT(KeQueryActiveGroupCount() == 1);
+ if (addCpu) {
+ /*
+ * The incrementation of 'count' is required in case the OS is about to
+ * add a new processor to the system, i.e. 'KeProcessorAddStartNotify'
+ * notification is received, and the processor is not active yet.
+ * In this situation the new processor won't be counted by the
+ * 'KeQueryActiveProcessorCountEx' function. So we increment the
+ * 'count' here in order to allocate the memory for the new processor
+ * also.
+ */
+ count++;
+ }
+
ptr = OvsAllocateMemoryWithTag(count * size, tag);
if (ptr) {
RtlZeroMemory(ptr, count * size);
+ if (cpuCount) {
+ *cpuCount = count;
+ }
}
return ptr;
}
+
+VOID *
+OvsReallocateMemoryPerCpu(VOID *buffer,
+ size_t bufferSize,
+ ULONG tag,
+ BOOLEAN addCpu,
+ ULONG oldCpuCount,
+ ULONG *newCpuCount)
+{
+ VOID *ptr = NULL;
+ ULONG cpuCount = 0;
+
+ ptr = OvsAllocateMemoryPerCpu(bufferSize, tag, addCpu, &cpuCount);
+ if (ptr) {
+ ULONG count = 0;
+ count = (cpuCount > oldCpuCount) ? oldCpuCount : cpuCount;
+ RtlCopyMemory(ptr, buffer, count * bufferSize);
+ if (newCpuCount) {
+ *newCpuCount = cpuCount;
+ }
+
+ if (buffer) {
+ OvsFreeMemoryWithTag(buffer, tag);
+ }
+ }
+
+ return ptr;
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsCpuChange --
+ * This is the processor change callback function that is to be called by
+ * the operating system whenever a new processor is added to the hardware
+ * partition.
+ *
+ * 'KeProcessorAddStartNotify' notification is received when the OS is
+ * about to add the processor; at this state, any per-processor data
+ * structures must be allocated for the new processor to prepare the
+ * driver for execution on the new processor.
+ *
+ * 'KeProcessorAddFailureNotify' notification is received when the OS
+ * failed to add the processor and any per-processor data structures that
+ * were allocated for the new processor should be freed.
+ * --------------------------------------------------------------------------
+ */
+VOID
+OvsCpuChange(__in PVOID CallbackContext,
+ __in PKE_PROCESSOR_CHANGE_NOTIFY_CONTEXT ChangeContext,
+ __inout PNTSTATUS OperationStatus)
+{
+ UNREFERENCED_PARAMETER(CallbackContext);
+
+ switch (ChangeContext->State) {
+ case KeProcessorAddFailureNotify:
+ {
+ OvsDeferredActionsRealloc(FALSE);
+ break;
+ }
+ case KeProcessorAddStartNotify:
+ {
+ NTSTATUS status = STATUS_SUCCESS;
+
+ status = OvsDeferredActionsRealloc(TRUE);
+ if (!NT_SUCCESS(status)) {
+ *OperationStatus = status;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsPerCpuDataInit --
+ * The function allocates necessary per-processor resources and registers
+ * processor change callback.
+ * --------------------------------------------------------------------------
+ */
+NTSTATUS
+OvsPerCpuDataInit(NDIS_HANDLE ndisFilterHandle)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ status = OvsDeferredActionsInit(ndisFilterHandle);
+ if (!NT_SUCCESS(status)) {
+ goto exit;
+ }
+
+ ovsRegistrationHandle =
+ KeRegisterProcessorChangeCallback(OvsCpuChange, NULL, 0);
+ if (!ovsRegistrationHandle) {
+ status = NDIS_STATUS_FAILURE;
+ goto exit;
+ }
+
+exit:
+ return status;
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsPerCpuDataCleanup --
+ * The function frees all per-processor resources and deregisters
+ * processor change callback.
+ * --------------------------------------------------------------------------
+ */
+VOID
+OvsPerCpuDataCleanup()
+{
+ if (ovsRegistrationHandle) {
+ KeDeregisterProcessorChangeCallback(ovsRegistrationHandle);
+ ovsRegistrationHandle = NULL;
+ }
+
+ OvsDeferredActionsCleanup();
+}
diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h
index 038754d..09a60d1 100644
--- a/datapath-windows/ovsext/Util.h
+++ b/datapath-windows/ovsext/Util.h
@@ -41,7 +41,16 @@
VOID *OvsAllocateMemory(size_t size);
VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag);
VOID *OvsAllocateAlignedMemory(size_t size, UINT16 align);
-VOID *OvsAllocateMemoryPerCpu(size_t size, ULONG tag);
+VOID *OvsAllocateMemoryPerCpu(size_t size,
+ ULONG tag,
+ BOOLEAN addCpu,
+ PULONG cpuCount);
+VOID *OvsReallocateMemoryPerCpu(VOID *ptr,
+ size_t size,
+ ULONG tag,
+ BOOLEAN addCpu,
+ ULONG oldCpuCount,
+ ULONG *newCpuCount);
VOID OvsFreeMemory(VOID *ptr);
VOID OvsFreeMemoryWithTag(VOID *ptr, ULONG tag);
VOID OvsFreeAlignedMemory(VOID *ptr);
@@ -94,4 +103,28 @@ VOID OvsAppendList(PLIST_ENTRY dst, PLIST_ENTRY src);
BOOLEAN OvsCompareString(PVOID string1, PVOID string2);
+/*
+ * --------------------------------------------------------------------------
+ * OvsPerCpuDataInit --
+ * The function allocates necessary per-processor resources and registers
+ * processor change callback.
+ * --------------------------------------------------------------------------
+ */
+NTSTATUS
+OvsPerCpuDataInit(NDIS_HANDLE NdisFilterHandle);
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsPerCpuDataCleanup --
+ * The function frees all per-processor resources and deregisters
+ * processor change callback.
+ * --------------------------------------------------------------------------
+ */
+VOID
+OvsPerCpuDataCleanup();
+VOID
+OvsCpuChange(__in PVOID CallbackContext,
+__in PKE_PROCESSOR_CHANGE_NOTIFY_CONTEXT ChangeContext,
+__inout PNTSTATUS OperationStatus);
+
#endif /* __UTIL_H_ */
--
1.9.0.msysgit.0
More information about the dev
mailing list