datapath-windows: update extension information
[cascardo/ovs.git] / datapath-windows / ovsext / User.c
index 8400b83..9f462cf 100644 (file)
 
 #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
@@ -39,8 +40,6 @@
 #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;
@@ -50,34 +49,19 @@ static VOID _MapNlAttrToOvsPktExec(PNL_ATTR *nlAttrs, PNL_ATTR *keyAttrs,
                                    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)
@@ -101,11 +85,10 @@ OvsPurgePacketQueue(POVS_USER_PACKET_QUEUE queue,
     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)
 {
@@ -115,13 +98,17 @@ 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;
         }
 
@@ -130,7 +117,6 @@ OvsCleanupPacketQueue(POVS_OPEN_INSTANCE instance)
             queue->numPackets = 0;
         }
         queue->instance = NULL;
-        queue->queueId = OVS_MAX_NUM_PACKET_QUEUES;
         instance->packetQueue = NULL;
         irp = queue->pendingIrp;
         queue->pendingIrp = NULL;
@@ -141,55 +127,67 @@ OvsCleanupPacketQueue(POVS_OPEN_INSTANCE instance)
             }
         }
         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;
 }
 
@@ -226,13 +224,12 @@ OvsReadDpIoctl(PFILE_OBJECT fileObject,
         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 ?
@@ -240,11 +237,11 @@ OvsReadDpIoctl(PFILE_OBJECT fileObject,
             *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;
 }
@@ -369,33 +366,41 @@ OvsNlExecuteCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
     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:
@@ -434,15 +439,9 @@ OvsExecuteDpIoctl(OvsPacketExecute *execute)
     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;
@@ -457,7 +456,7 @@ OvsExecuteDpIoctl(OvsPacketExecute *execute)
                                        execute->packetLen);
     if (pNbl == NULL) {
         status = STATUS_NO_MEMORY;
-        goto unlock;
+        goto exit;
     }
 
     fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pNbl);
@@ -472,11 +471,9 @@ OvsExecuteDpIoctl(OvsPacketExecute *execute)
     // 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,
@@ -487,14 +484,17 @@ OvsExecuteDpIoctl(OvsPacketExecute *execute)
         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;
 }
 
@@ -614,68 +614,148 @@ OvsGetNextPacket(POVS_OPEN_INSTANCE instance)
     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 --
@@ -872,6 +952,8 @@ OvsGetPid(POVS_VPORT_ENTRY vport, PNET_BUFFER nb, UINT32 *pid)
 {
     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;
@@ -921,18 +1003,20 @@ OvsCreateQueueNlPacket(PVOID userData,
     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.
@@ -963,12 +1047,14 @@ OvsCreateQueueNlPacket(PVOID userData,
                                     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;
@@ -994,9 +1080,9 @@ OvsCreateQueueNlPacket(PVOID userData,
      * 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;
     }
 
@@ -1057,8 +1143,14 @@ OvsCreateQueueNlPacket(PVOID userData,
         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;
 }