datapath-windows: Avoid unnecessary vport array search
[cascardo/ovs.git] / datapath-windows / ovsext / PacketIO.c
index 7eb6ed8..cfbae34 100644 (file)
@@ -44,6 +44,10 @@ extern NDIS_STRING ovsExtFriendlyNameUC;
 static VOID OvsFinalizeCompletionList(OvsCompletionList *completionList);
 static VOID OvsCompleteNBLIngress(POVS_SWITCH_CONTEXT switchContext,
                     PNET_BUFFER_LIST netBufferLists, ULONG sendCompleteFlags);
+static NTSTATUS OvsCreateNewNBLsFromMultipleNBs(
+                    POVS_SWITCH_CONTEXT switchContext,
+                    PNET_BUFFER_LIST *curNbl,
+                    PNET_BUFFER_LIST *nextNbl);
 
 __inline VOID
 OvsInitCompletionList(OvsCompletionList *completionList,
@@ -176,6 +180,29 @@ OvsStartNBLIngressError(POVS_SWITCH_CONTEXT switchContext,
                                     sendCompleteFlags);
 }
 
+static VOID
+OvsAppendNativeForwardedPacket(POVS_SWITCH_CONTEXT switchContext,
+                               PNET_BUFFER_LIST curNbl,
+                               PNET_BUFFER_LIST *nativeNbls,
+                               ULONG flags,
+                               BOOLEAN isRecv)
+{
+    POVS_BUFFER_CONTEXT ctx = { 0 };
+    NDIS_STRING filterReason;
+
+    *nativeNbls = curNbl;
+    nativeNbls = &(curNbl->Next);
+
+    ctx = OvsInitExternalNBLContext(switchContext, curNbl, isRecv);
+    if (ctx == NULL) {
+        RtlInitUnicodeString(&filterReason,
+                             L"Cannot allocate native NBL context.");
+
+        OvsStartNBLIngressError(switchContext, curNbl, flags, &filterReason,
+                                NDIS_STATUS_RESOURCES);
+    }
+}
+
 static VOID
 OvsStartNBLIngress(POVS_SWITCH_CONTEXT switchContext,
                    PNET_BUFFER_LIST netBufferLists,
@@ -193,6 +220,10 @@ OvsStartNBLIngress(POVS_SWITCH_CONTEXT switchContext,
     LIST_ENTRY missedPackets;
     UINT32 num = 0;
     OvsCompletionList completionList;
+#if (NDIS_SUPPORT_NDIS640)
+    PNET_BUFFER_LIST nativeForwardedNbls = NULL;
+    PNET_BUFFER_LIST *nextNativeForwardedNbl = &nativeForwardedNbls;
+#endif
 
     dispatch = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags)?
                                             NDIS_RWL_AT_DISPATCH_LEVEL : 0;
@@ -210,22 +241,59 @@ OvsStartNBLIngress(POVS_SWITCH_CONTEXT switchContext,
         OvsFlowKey key;
         UINT64 hash;
         PNET_BUFFER curNb;
+        POVS_BUFFER_CONTEXT ctx;
 
         nextNbl = curNbl->Next;
         curNbl->Next = NULL;
 
+        fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl);
+        sourcePort = fwdDetail->SourcePortId;
+        sourceIndex = (NDIS_SWITCH_NIC_INDEX)fwdDetail->SourceNicIndex;
+
+#if (NDIS_SUPPORT_NDIS640)
+        if (fwdDetail->NativeForwardingRequired) {
+            /* Add current NBL to those that require native forwarding. */
+            OvsAppendNativeForwardedPacket(
+                switchContext,
+                curNbl,
+                nextNativeForwardedNbl,
+                sendCompleteFlags,
+                sourcePort == switchContext->virtualExternalPortId);
+            continue;
+        }
+#endif /* NDIS_SUPPORT_NDIS640 */
+
+        ctx = OvsInitExternalNBLContext(switchContext, curNbl,
+                  sourcePort == switchContext->virtualExternalPortId);
+        if (ctx == NULL) {
+            RtlInitUnicodeString(&filterReason,
+                L"Cannot allocate external NBL context.");
+
+            OvsStartNBLIngressError(switchContext, curNbl,
+                                    sendCompleteFlags, &filterReason,
+                                    NDIS_STATUS_RESOURCES);
+            continue;
+        }
+
         /* Ethernet Header is a guaranteed safe access. */
         curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
         if (curNb->Next != NULL) {
-            /* XXX: This case is not handled yet. */
-            ASSERT(FALSE);
-        } else {
-            POVS_BUFFER_CONTEXT ctx;
-            OvsFlow *flow;
+            /* Create a NET_BUFFER_LIST for each NET_BUFFER. */
+            status = OvsCreateNewNBLsFromMultipleNBs(switchContext,
+                                                     &curNbl,
+                                                     &nextNbl);
+            if (!NT_SUCCESS(status)) {
+                RtlInitUnicodeString(&filterReason,
+                                     L"Cannot allocate NBLs with single NB.");
 
-            fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl);
-            sourcePort = fwdDetail->SourcePortId;
-            sourceIndex = (NDIS_SWITCH_NIC_INDEX)fwdDetail->SourceNicIndex;
+                OvsStartNBLIngressError(switchContext, curNbl,
+                                        sendCompleteFlags, &filterReason,
+                                        NDIS_STATUS_RESOURCES);
+                continue;
+            }
+        }
+        {
+            OvsFlow *flow;
 
             /* Take the DispatchLock so none of the VPORTs disconnect while
              * we are setting destination ports.
@@ -235,19 +303,6 @@ OvsStartNBLIngress(POVS_SWITCH_CONTEXT switchContext,
             NdisAcquireRWLockRead(switchContext->dispatchLock, &lockState,
                                   dispatch);
 
-            ctx = OvsInitExternalNBLContext(switchContext, curNbl,
-                                  sourcePort == switchContext->externalPortId);
-            if (ctx == NULL) {
-                RtlInitUnicodeString(&filterReason,
-                                     L"Cannot allocate external NBL context.");
-
-                OvsStartNBLIngressError(switchContext, curNbl,
-                                        sendCompleteFlags, &filterReason,
-                                        NDIS_STATUS_RESOURCES);
-                NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
-                continue;
-            }
-
             vport = OvsFindVportByPortIdAndNicIndex(switchContext, sourcePort,
                                                     sourceIndex);
             if (vport == NULL || vport->ovsState != OVS_STATE_CONNECTED) {
@@ -278,8 +333,8 @@ OvsStartNBLIngress(POVS_SWITCH_CONTEXT switchContext,
                  * Otherwise, it adds it to the completionList. No need to
                  * check the return value. */
                 OvsActionsExecute(switchContext, &completionList, curNbl,
-                                portNo, SendFlags, &key, &hash, &layers,
-                                flow->actions, flow->actionsLen);
+                                  portNo, SendFlags, &key, &hash, &layers,
+                                  flow->actions, flow->actionsLen);
                 OvsReleaseDatapath(datapath, &dpLockState);
                 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
                 continue;
@@ -288,12 +343,9 @@ OvsStartNBLIngress(POVS_SWITCH_CONTEXT switchContext,
 
                 datapath->misses++;
                 status = OvsCreateAndAddPackets(NULL, 0, OVS_PACKET_CMD_MISS,
-                                                portNo,
-                                                &key, curNbl,
-                                                sourcePort ==
-                                                switchContext->externalPortId,
-                                                &layers, switchContext,
-                                                &missedPackets, &num);
+                             vport, &key, curNbl,
+                             sourcePort == switchContext->virtualExternalPortId,
+                             &layers, switchContext, &missedPackets, &num);
                 if (status == NDIS_STATUS_SUCCESS) {
                     /* Complete the packet since it was copied to user
                      * buffer. */
@@ -313,6 +365,14 @@ dropit:
         }
     }
 
+#if (NDIS_SUPPORT_NDIS640)
+    if (nativeForwardedNbls) {
+        /* This is NVGRE encapsulated traffic and is forwarded to NDIS
+         * in order to be handled by the HNV module. */
+        OvsSendNBLIngress(switchContext, nativeForwardedNbls, SendFlags);
+    }
+#endif /* NDIS_SUPPORT_NDIS640 */
+
     /* Queue the missed packets. */
     OvsQueuePackets(&missedPackets, num);
     OvsFinalizeCompletionList(&completionList);
@@ -435,3 +495,43 @@ OvsExtCancelSendNBL(NDIS_HANDLE filterModuleContext,
     /* All send requests get completed synchronously, so there is no need to
      * implement this callback. */
 }
+
+static NTSTATUS
+OvsCreateNewNBLsFromMultipleNBs(POVS_SWITCH_CONTEXT switchContext,
+                                PNET_BUFFER_LIST *curNbl,
+                                PNET_BUFFER_LIST *nextNbl)
+{
+    NTSTATUS status = STATUS_SUCCESS;
+    PNET_BUFFER_LIST newNbls = NULL;
+    PNET_BUFFER_LIST lastNbl = NULL;
+    PNET_BUFFER_LIST nbl = NULL;
+    BOOLEAN error = TRUE;
+
+    do {
+        /* Create new NBLs from curNbl with multiple net buffers. */
+        newNbls = OvsPartialCopyToMultipleNBLs(switchContext,
+                                               *curNbl, 0, 0, TRUE);
+        if (NULL == newNbls) {
+            OVS_LOG_ERROR("Failed to allocate NBLs with single NB.");
+            status = NDIS_STATUS_RESOURCES;
+            break;
+        }
+
+        nbl = newNbls;
+        while (nbl) {
+            lastNbl = nbl;
+            nbl = NET_BUFFER_LIST_NEXT_NBL(nbl);
+        }
+        lastNbl->Next = *nextNbl;
+        *nextNbl = newNbls->Next;
+
+        OvsCompleteNBL(switchContext, *curNbl, TRUE);
+
+        *curNbl = newNbls;
+        (*curNbl)->Next = NULL;
+
+        error = FALSE;
+    } while (error);
+
+    return status;
+}