#include "precomp.h"
-#include "Datapath.h"
#include "Switch.h"
#include "Vport.h"
#include "Event.h"
#include "User.h"
+#include "Datapath.h"
#include "PacketIO.h"
#include "Checksum.h"
#include "NetProto.h"
#include "Flow.h"
#include "TunnelIntf.h"
+#include "Jhash.h"
#ifdef OVS_DBG_MOD
#undef OVS_DBG_MOD
#define OVS_DBG_MOD OVS_DBG_USER
#include "Debug.h"
-OVS_USER_PACKET_QUEUE ovsPacketQueues[OVS_MAX_NUM_PACKET_QUEUES];
-
POVS_PACKET_QUEUE_ELEM OvsGetNextPacket(POVS_OPEN_INSTANCE instance);
extern PNDIS_SPIN_LOCK gOvsCtrlLock;
extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
OvsPacketExecute *execute);
extern NL_POLICY nlFlowKeyPolicy[];
-NTSTATUS
-OvsUserInit()
+static __inline VOID
+OvsAcquirePidHashLock()
{
- UINT32 i;
- POVS_USER_PACKET_QUEUE queue;
- for (i = 0; i < OVS_MAX_NUM_PACKET_QUEUES; i++) {
- queue = &ovsPacketQueues[i];
- RtlZeroMemory(queue, sizeof (*queue));
- InitializeListHead(&queue->packetList);
- NdisAllocateSpinLock(&queue->queueLock);
- }
- return STATUS_SUCCESS;
+ NdisAcquireSpinLock(&(gOvsSwitchContext->pidHashLock));
}
-VOID
-OvsUserCleanup()
+static __inline VOID
+OvsReleasePidHashLock()
{
- UINT32 i;
- POVS_USER_PACKET_QUEUE queue;
- for (i = 0; i < OVS_MAX_NUM_PACKET_QUEUES; i++) {
- queue = &ovsPacketQueues[i];
- ASSERT(IsListEmpty(&queue->packetList));
- ASSERT(queue->instance == NULL);
- ASSERT(queue->pendingIrp == NULL);
- NdisFreeSpinLock(&queue->queueLock);
- }
+ NdisReleaseSpinLock(&(gOvsSwitchContext->pidHashLock));
}
+
static VOID
OvsPurgePacketQueue(POVS_USER_PACKET_QUEUE queue,
POVS_OPEN_INSTANCE instance)
LIST_FORALL_SAFE(&tmp, link, next) {
RemoveEntryList(link);
elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
}
}
-
VOID
OvsCleanupPacketQueue(POVS_OPEN_INSTANCE instance)
{
LIST_ENTRY tmp;
PIRP irp = NULL;
+ ASSERT(instance);
InitializeListHead(&tmp);
queue = (POVS_USER_PACKET_QUEUE)instance->packetQueue;
if (queue) {
PDRIVER_CANCEL cancelRoutine;
NdisAcquireSpinLock(&queue->queueLock);
+ ASSERT(queue->instance == instance);
+ /* XXX Should not happen */
if (queue->instance != instance) {
NdisReleaseSpinLock(&queue->queueLock);
+ NdisFreeSpinLock(&queue->queueLock);
return;
}
queue->numPackets = 0;
}
queue->instance = NULL;
- queue->queueId = OVS_MAX_NUM_PACKET_QUEUES;
instance->packetQueue = NULL;
irp = queue->pendingIrp;
queue->pendingIrp = NULL;
}
}
NdisReleaseSpinLock(&queue->queueLock);
+ NdisFreeSpinLock(&queue->queueLock);
}
LIST_FORALL_SAFE(&tmp, link, next) {
RemoveEntryList(link);
elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
}
if (irp) {
OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
}
+ if (queue) {
+ OvsFreeMemoryWithTag(queue, OVS_USER_POOL_TAG);
+ }
+
+ /* Verify if gOvsSwitchContext exists. */
+ if (gOvsSwitchContext) {
+ /* Remove the instance from pidHashArray */
+ OvsAcquirePidHashLock();
+ OvsDelPidInstance(gOvsSwitchContext, instance->pid);
+ OvsReleasePidHashLock();
+ }
}
NTSTATUS
-OvsSubscribeDpIoctl(PFILE_OBJECT fileObject,
- PVOID inputBuffer,
- UINT32 inputLength)
+OvsSubscribeDpIoctl(PVOID instanceP,
+ UINT32 pid,
+ UINT8 join)
{
- POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
- UINT32 queueId;
POVS_USER_PACKET_QUEUE queue;
- if (inputLength < sizeof (UINT32)) {
- return STATUS_INVALID_PARAMETER;
- }
- queueId = *(UINT32 *)inputBuffer;
- if (instance->packetQueue && queueId >= OVS_MAX_NUM_PACKET_QUEUES) {
- /*
- * unsubscribe
- */
+ POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)instanceP;
+
+ if (instance->packetQueue && !join) {
+ /* unsubscribe */
OvsCleanupPacketQueue(instance);
- } else if (instance->packetQueue == NULL &&
- queueId < OVS_MAX_NUM_PACKET_QUEUES) {
- queue = &ovsPacketQueues[queueId];
- NdisAcquireSpinLock(&queue->queueLock);
- if (ovsPacketQueues[queueId].instance) {
- if (ovsPacketQueues[queueId].instance != instance) {
- NdisReleaseSpinLock(&queue->queueLock);
- return STATUS_INSUFFICIENT_RESOURCES;
- } else {
- NdisReleaseSpinLock(&queue->queueLock);
- return STATUS_SUCCESS;
- }
+ } else if (instance->packetQueue == NULL && join) {
+ queue = (POVS_USER_PACKET_QUEUE) OvsAllocateMemoryWithTag(
+ sizeof *queue, OVS_USER_POOL_TAG);
+ if (queue == NULL) {
+ return STATUS_NO_MEMORY;
}
- queue->queueId = queueId;
+ InitializeListHead(&(instance->pidLink));
+ instance->packetQueue = queue;
+ RtlZeroMemory(queue, sizeof (*queue));
+ NdisAllocateSpinLock(&queue->queueLock);
+ NdisAcquireSpinLock(&queue->queueLock);
+ InitializeListHead(&queue->packetList);
+ queue->pid = pid;
queue->instance = instance;
instance->packetQueue = queue;
- ASSERT(IsListEmpty(&queue->packetList));
NdisReleaseSpinLock(&queue->queueLock);
+
+ OvsAcquirePidHashLock();
+ /* Insert the instance to pidHashArray */
+ OvsAddPidInstance(gOvsSwitchContext, pid, instance);
+ OvsReleasePidHashLock();
+
} else {
+ /* user mode should call only once for subscribe */
return STATUS_INVALID_PARAMETER;
}
+
return STATUS_SUCCESS;
}
if ((elem->hdrInfo.tcpCsumNeeded || elem->hdrInfo.udpCsumNeeded) &&
len == elem->packet.totalLen) {
UINT16 sum, *ptr;
- UINT16 size = (UINT16)(elem->packet.userDataLen +
- elem->hdrInfo.l4Offset +
- (UINT16)sizeof (OVS_PACKET_INFO));
- RtlCopyMemory(outputBuffer, &elem->packet, size);
- ASSERT(len - size >= elem->hdrInfo.l4PayLoad);
+ UINT16 size = (UINT16)(elem->packet.payload - elem->packet.data +
+ elem->hdrInfo.l4Offset);
+ RtlCopyMemory(outputBuffer, &elem->packet.data, size);
+ ASSERT(len - size >= elem->hdrInfo.l4PayLoad);
sum = CopyAndCalculateChecksum((UINT8 *)outputBuffer + size,
- (UINT8 *)&elem->packet + size,
+ (UINT8 *)&elem->packet.data + size,
elem->hdrInfo.l4PayLoad, 0);
ptr =(UINT16 *)((UINT8 *)outputBuffer + size +
(elem->hdrInfo.tcpCsumNeeded ?
*ptr = sum;
ovsUserStats.l4Csum++;
} else {
- RtlCopyMemory(outputBuffer, &elem->packet, len);
+ RtlCopyMemory(outputBuffer, &elem->packet.data, len);
}
*replyLen = len;
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
}
return STATUS_SUCCESS;
}
status = OvsExecuteDpIoctl(&execute);
+ /* Default reply that we want to send */
if (status == STATUS_SUCCESS) {
+ BOOLEAN ok;
+
NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
usrParamsCtx->outputLength);
/* Prepare nl Msg headers */
- status = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0,
+ ok = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0,
nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid,
genlMsgHdr->cmd, OVS_PACKET_VERSION,
ovsHdr->dp_ifindex);
- if (status == STATUS_SUCCESS) {
+ if (ok) {
*replyLen = msgOut->nlMsg.nlmsgLen;
+ } else {
+ status = STATUS_INVALID_BUFFER_SIZE;
+ }
+ } else {
+ /* Map NTSTATUS to NL_ERROR */
+ nlError = NlMapStatusToNlErr(status);
+
+ /* As of now there are no transactional errors in the implementation.
+ * Once we have them then we need to map status to correct
+ * nlError value, so that below mentioned code gets hit. */
+ if ((nlError != NL_ERROR_SUCCESS) &&
+ (usrParamsCtx->outputBuffer)) {
+
+ POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
+ usrParamsCtx->outputBuffer;
+ NlBuildErrorMsg(msgIn, msgError, nlError);
+ *replyLen = msgError->nlMsg.nlmsgLen;
+ status = STATUS_SUCCESS;
+ goto done;
}
- }
-
- /* As of now there are no transactional errors in the implementation.
- * Once we have them then we need to map status to correct
- * nlError value, so that below mentioned code gets hit. */
- if ((nlError != NL_ERROR_SUCCESS) &&
- (usrParamsCtx->outputBuffer)) {
-
- POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
- usrParamsCtx->outputBuffer;
- BuildErrorMsg(msgIn, msgError, nlError);
- *replyLen = msgError->nlMsg.nlmsgLen;
- status = STATUS_SUCCESS;
- goto done;
}
done:
OVS_PACKET_HDR_INFO layers;
POVS_VPORT_ENTRY vport;
- NdisAcquireSpinLock(gOvsCtrlLock);
- if (gOvsSwitchContext == NULL) {
- status = STATUS_INVALID_PARAMETER;
- goto unlock;
- }
-
if (execute->packetLen == 0) {
status = STATUS_INVALID_PARAMETER;
- goto unlock;
+ goto exit;
}
actions = execute->actions;
execute->packetLen);
if (pNbl == NULL) {
status = STATUS_NO_MEMORY;
- goto unlock;
+ goto exit;
}
fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pNbl);
// XXX: Figure out if any of the other members of fwdDetail need to be set.
ndisStatus = OvsExtractFlow(pNbl, fwdDetail->SourcePortId, &key, &layers,
- NULL);
+ NULL);
if (ndisStatus == NDIS_STATUS_SUCCESS) {
- ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
- NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
- NDIS_RWL_AT_DISPATCH_LEVEL);
+ NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
ndisStatus = OvsActionsExecute(gOvsSwitchContext, NULL, pNbl,
vport ? vport->portNo :
OVS_DEFAULT_PORT_NO,
NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
}
if (ndisStatus != NDIS_STATUS_SUCCESS) {
- status = STATUS_UNSUCCESSFUL;
+ if (ndisStatus == NDIS_STATUS_NOT_SUPPORTED) {
+ status = STATUS_NOT_SUPPORTED;
+ } else {
+ status = STATUS_UNSUCCESSFUL;
+ }
}
if (pNbl) {
OvsCompleteNBL(gOvsSwitchContext, pNbl, TRUE);
}
-unlock:
- NdisReleaseSpinLock(gOvsCtrlLock);
+exit:
return status;
}
return CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
}
-
+/*
+ * ---------------------------------------------------------------------------
+ * Given a pid, returns the corresponding USER_PACKET_QUEUE.
+ * ---------------------------------------------------------------------------
+ */
POVS_USER_PACKET_QUEUE
-OvsGetQueue(UINT32 queueId)
+OvsGetQueue(UINT32 pid)
{
- POVS_USER_PACKET_QUEUE queue;
- if (queueId >= OVS_MAX_NUM_PACKET_QUEUES) {
- return NULL;
+ POVS_OPEN_INSTANCE instance;
+ POVS_USER_PACKET_QUEUE ret = NULL;
+
+ instance = OvsGetPidInstance(gOvsSwitchContext, pid);
+
+ if (instance) {
+ ret = instance->packetQueue;
}
- queue = &ovsPacketQueues[queueId];
- return queue->instance != NULL ? queue : NULL;
+
+ return ret;
}
+/*
+ * ---------------------------------------------------------------------------
+ * Given a pid, returns the corresponding instance.
+ * pidHashLock must be acquired before calling this API.
+ * ---------------------------------------------------------------------------
+ */
+POVS_OPEN_INSTANCE
+OvsGetPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid)
+{
+ POVS_OPEN_INSTANCE instance;
+ PLIST_ENTRY head, link;
+ UINT32 hash = OvsJhashBytes((const VOID *)&pid, sizeof(pid),
+ OVS_HASH_BASIS);
+ head = &(switchContext->pidHashArray[hash & OVS_PID_MASK]);
+ LIST_FORALL(head, link) {
+ instance = CONTAINING_RECORD(link, OVS_OPEN_INSTANCE, pidLink);
+ if (instance->pid == pid) {
+ return instance;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Given a pid and an instance. This API adds instance to pidHashArray.
+ * pidHashLock must be acquired before calling this API.
+ * ---------------------------------------------------------------------------
+ */
VOID
-OvsQueuePackets(UINT32 queueId,
- PLIST_ENTRY packetList,
+OvsAddPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid,
+ POVS_OPEN_INSTANCE instance)
+{
+ PLIST_ENTRY head;
+ UINT32 hash = OvsJhashBytes((const VOID *)&pid, sizeof(pid),
+ OVS_HASH_BASIS);
+ head = &(switchContext->pidHashArray[hash & OVS_PID_MASK]);
+ InsertHeadList(head, &(instance->pidLink));
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Given a pid and an instance. This API removes instance from pidHashArray.
+ * pidHashLock must be acquired before calling this API.
+ * ---------------------------------------------------------------------------
+ */
+VOID
+OvsDelPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid)
+{
+ POVS_OPEN_INSTANCE instance = OvsGetPidInstance(switchContext, pid);
+
+ if (instance) {
+ RemoveEntryList(&(instance->pidLink));
+ }
+}
+
+VOID
+OvsQueuePackets(PLIST_ENTRY packetList,
UINT32 numElems)
{
- POVS_USER_PACKET_QUEUE queue = OvsGetQueue(queueId);
+ POVS_USER_PACKET_QUEUE upcallQueue = NULL;
POVS_PACKET_QUEUE_ELEM elem;
PIRP irp = NULL;
PLIST_ENTRY link;
UINT32 num = 0;
+ LIST_ENTRY dropPackets;
- OVS_LOG_LOUD("Enter: queueId %u, numELems: %u",
- queueId, numElems);
- if (queue == NULL) {
- goto cleanup;
- }
+ OVS_LOG_LOUD("Enter: numELems: %u", numElems);
- NdisAcquireSpinLock(&queue->queueLock);
- if (queue->instance == NULL) {
- NdisReleaseSpinLock(&queue->queueLock);
- goto cleanup;
- } else {
- OvsAppendList(&queue->packetList, packetList);
- queue->numPackets += numElems;
- }
- if (queue->pendingIrp) {
- PDRIVER_CANCEL cancelRoutine;
- irp = queue->pendingIrp;
- queue->pendingIrp = NULL;
- cancelRoutine = IoSetCancelRoutine(irp, NULL);
- if (cancelRoutine == NULL) {
- irp = NULL;
- }
- }
- NdisReleaseSpinLock(&queue->queueLock);
- if (irp) {
- OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
- }
+ InitializeListHead(&dropPackets);
-cleanup:
while (!IsListEmpty(packetList)) {
link = RemoveHeadList(packetList);
elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
- OvsFreeMemory(elem);
+
+ ASSERT(elem);
+
+ OvsAcquirePidHashLock();
+
+ upcallQueue = OvsGetQueue(elem->upcallPid);
+ if (!upcallQueue) {
+ /* No upcall queue found, drop this packet. */
+ InsertTailList(&dropPackets, &elem->link);
+ } else {
+ NdisAcquireSpinLock(&upcallQueue->queueLock);
+
+ if (upcallQueue->instance == NULL) {
+ InsertTailList(&dropPackets, &elem->link);
+ } else {
+ InsertTailList(&upcallQueue->packetList, &elem->link);
+ upcallQueue->numPackets++;
+ if (upcallQueue->pendingIrp) {
+ PDRIVER_CANCEL cancelRoutine;
+ irp = upcallQueue->pendingIrp;
+ upcallQueue->pendingIrp = NULL;
+ cancelRoutine = IoSetCancelRoutine(irp, NULL);
+ if (cancelRoutine == NULL) {
+ irp = NULL;
+ }
+ }
+ }
+
+ if (irp) {
+ OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
+ }
+
+ NdisReleaseSpinLock(&upcallQueue->queueLock);
+ }
+
+ OvsReleasePidHashLock();
+ }
+
+ while (!IsListEmpty(&dropPackets)) {
+ link = RemoveHeadList(&dropPackets);
+ elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
+ OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
num++;
}
+
OVS_LOG_LOUD("Exit: drop %u packets", num);
}
-
/*
*----------------------------------------------------------------------------
* OvsCreateAndAddPackets --
{
UNREFERENCED_PARAMETER(nb);
+ ASSERT(vport);
+
/* XXX select a pid from an array of pids using a flow based hash */
*pid = vport->upcallPid;
return STATUS_SUCCESS;
UINT32 pid;
UINT32 nlMsgSize;
NL_BUFFER nlBuf;
+ PNL_MSG_HDR nlMsg;
/* XXX pass vport in the stack rather than portNo */
POVS_VPORT_ENTRY vport =
OvsFindVportByPortNo(gOvsSwitchContext, inPort);
if (vport == NULL){
- /* Should never happen as dispatch lock is held */
- ASSERT(vport);
+ /* No vport is not fatal. */
return NULL;
}
- if (!OvsGetPid(vport, nb, &pid)) {
+ OvsGetPid(vport, nb, &pid);
+
+ if (!pid) {
/*
* There is no userspace queue created yet, so there is no point for
* creating a new packet to be queued.
dataLen + extraLen);
allocLen = sizeof (OVS_PACKET_QUEUE_ELEM) + nlMsgSize;
- elem = (POVS_PACKET_QUEUE_ELEM)OvsAllocateMemory(allocLen);
+ elem = (POVS_PACKET_QUEUE_ELEM)OvsAllocateMemoryWithTag(allocLen,
+ OVS_USER_POOL_TAG);
if (elem == NULL) {
ovsUserStats.dropDuetoResource++;
return NULL;
}
elem->hdrInfo.value = hdrInfo->value;
+ elem->upcallPid = pid;
elem->packet.totalLen = nlMsgSize;
/* XXX remove queueid */
elem->packet.queue = 0;
* Since we are pre allocating memory for the NL buffer
* the attribute settings should not fail
*/
- if (NlFillOvsMsg(&nlBuf, OVS_WIN_NL_PACKET_FAMILY_ID, 0,
+ if (!NlFillOvsMsg(&nlBuf, OVS_WIN_NL_PACKET_FAMILY_ID, 0,
0, pid, (UINT8)cmd, OVS_PACKET_VERSION,
- gOvsSwitchContext->dpNo) != STATUS_SUCCESS) {
+ gOvsSwitchContext->dpNo)) {
goto fail;
}
elem->hdrInfo.l4Offset += VLAN_TAG_SIZE;
ovsUserStats.vlanInsert++;
}
+
+ nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuf, 0, 0);
+ nlMsg->nlmsgLen = NlBufSize(&nlBuf);
+ /* 'totalLen' should be size of valid data. */
+ elem->packet.totalLen = nlMsg->nlmsgLen;
+
return elem;
fail:
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
return NULL;
}