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 <svintu...@cloudbasesolutions.com> Reported-by: Sorin Vinturis <svintu...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev