[ovs-dev] [PATCH v3] datapath-windows Event read handler

Eitan Eliahu eliahue at vmware.com
Fri Sep 26 12:03:33 UTC 2014


The Read event handler is executed when user mode issues a socket receive on
an MC socket associated with the event queue. A new IOCTL READ command is
used to differentiate between transaction based and packet miss sockets.
An entry for the handler will be added once the Vport family implementation
checked in.
User mode code for setting the socket type will follow

Signed-off-by: Eitan Eliahu <eliahue at vmware.com>
---
 build-aux/extract-odp-netlink-windows-dp-h   |   4 +
 datapath-windows/include/OvsDpInterfaceExt.h |  10 +-
 datapath-windows/ovsext/Datapath.c           | 150 ++++++++++++++++++++++++++-
 datapath-windows/ovsext/Event.c              |  42 ++++++++
 datapath-windows/ovsext/Event.h              |   2 +
 5 files changed, 205 insertions(+), 3 deletions(-)

diff --git a/build-aux/extract-odp-netlink-windows-dp-h b/build-aux/extract-odp-netlink-windows-dp-h
index 70514cb..82d95f1 100755
--- a/build-aux/extract-odp-netlink-windows-dp-h
+++ b/build-aux/extract-odp-netlink-windows-dp-h
@@ -23,3 +23,7 @@ s,#include <linux/if_ether\.h>,\n#ifndef ETH_ADDR_LEN \
 
 # Use OVS's own ETH_ADDR_LEN instead of Linux-specific ETH_ALEN.
 s/ETH_ALEN/ETH_ADDR_LEN/
+
+s/OVS_VPORT_CMD_GET,/OVS_VPORT_CMD_GET,\
+	OVS_VPORT_CMD_NOTIFY,/
+
diff --git a/datapath-windows/include/OvsDpInterfaceExt.h b/datapath-windows/include/OvsDpInterfaceExt.h
index 64fd20e..be1e49f 100644
--- a/datapath-windows/include/OvsDpInterfaceExt.h
+++ b/datapath-windows/include/OvsDpInterfaceExt.h
@@ -34,11 +34,17 @@
 #define OVS_IOCTL_READ \
     CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x0, METHOD_OUT_DIRECT,\
               FILE_READ_ACCESS)
+#define OVS_IOCTL_READ_PACKET \
+    CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x1, METHOD_OUT_DIRECT, \
+              FILE_READ_ACCESS)
+#define OVS_IOCTL_READ_EVENT \
+    CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x2, METHOD_OUT_DIRECT, \
+              FILE_READ_ACCESS)
 #define OVS_IOCTL_WRITE \
-    CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x1, METHOD_IN_DIRECT,\
+    CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x3, METHOD_IN_DIRECT,\
               FILE_READ_ACCESS)
 #define OVS_IOCTL_TRANSACT \
-    CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x2, METHOD_OUT_DIRECT,\
+    CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x4, METHOD_OUT_DIRECT,\
               FILE_WRITE_ACCESS)
 
 /*
diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c
index 0dfdd57..3102e66 100644
--- a/datapath-windows/ovsext/Datapath.c
+++ b/datapath-windows/ovsext/Datapath.c
@@ -99,7 +99,8 @@ static NetlinkCmdHandler OvsGetPidCmdHandler,
                          OvsGetDpCmdHandler,
                          OvsPendEventCmdHandler,
                          OvsSubscribeEventCmdHandler,
-                         OvsSetDpCmdHandler;
+                         OvsSetDpCmdHandler,
+                         OvsReadEventCmdHandler;
 
 static NTSTATUS HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
                                        UINT32 *replyLen);
@@ -620,6 +621,29 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
         devOp = OVS_TRANSACTION_DEV_OP;
         break;
 
+    case OVS_IOCTL_READ_EVENT:
+        /* This IOCTL is used to read events */
+        if (outputBufferLen != 0) {
+            status = MapIrpOutputBuffer(irp, outputBufferLen,
+                                        sizeof *ovsMsg, &outputBuffer);
+            if (status != STATUS_SUCCESS) {
+                goto done;
+            }
+            ASSERT(outputBuffer);
+        } else {
+            status = STATUS_NDIS_INVALID_LENGTH;
+            goto done;
+        }
+        inputBuffer = NULL;
+        inputBufferLen = 0;
+
+        ovsMsg = &ovsMsgReadOp;
+        ovsMsg->nlMsg.nlmsgType = OVS_WIN_NL_VPORT_FAMILY_ID;
+        /* An "artificial" command so we can use NL family function table*/
+        ovsMsg->genlMsg.cmd = OVS_VPORT_CMD_NOTIFY;
+        devOp = OVS_READ_DEV_OP;
+        break;
+
     case OVS_IOCTL_READ:
         /* Output buffer is mandatory. */
         if (outputBufferLen != 0) {
@@ -924,6 +948,7 @@ OvsPendEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     return status;
 }
 
+
 /*
  * --------------------------------------------------------------------------
  *  Handler for the subscription for the event queue
@@ -1214,4 +1239,127 @@ MapIrpOutputBuffer(PIRP irp,
     return STATUS_SUCCESS;
 }
 
+/*
+ * --------------------------------------------------------------------------
+ * Utility function to fill up information about the state of a port in a reply
+ * to* userspace.
+ * Assumes that 'gOvsCtrlLock' lock is acquired.
+ * --------------------------------------------------------------------------
+ */
+static NTSTATUS
+OvsPortFillInfo(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+                POVS_EVENT_ENTRY eventEntry,
+                PNL_BUFFER nlBuf)
+{
+    NTSTATUS status;
+    BOOLEAN rc;
+    OVS_MESSAGE msgOutTmp;
+    PNL_MSG_HDR nlMsg;
+    POVS_VPORT_ENTRY vport;
+
+    ASSERT(NlBufAt(nlBuf, 0, 0) != 0 && nlBuf->bufRemLen >= sizeof msgOutTmp);
+
+    msgOutTmp.nlMsg.nlmsgType = OVS_WIN_NL_VPORT_FAMILY_ID;
+    msgOutTmp.nlMsg.nlmsgFlags = 0;  /* XXX: ? */
+    msgOutTmp.nlMsg.nlmsgSeq = 0; /* driver intiated messages should have */
+    msgOutTmp.nlMsg.nlmsgPid = usrParamsCtx->ovsInstance->pid;
+
+    msgOutTmp.genlMsg.version = nlVportFamilyOps.version;
+    msgOutTmp.genlMsg.reserved = 0;
+
+    /* we don't have netdev yet, treat link up/down a adding/removing a port*/
+    if (eventEntry->status & (OVS_EVENT_LINK_UP | OVS_EVENT_CONNECT)) {
+        msgOutTmp.genlMsg.cmd = OVS_VPORT_CMD_NEW;
+    } else if (eventEntry->status &
+             (OVS_EVENT_LINK_DOWN | OVS_EVENT_DISCONNECT)) {
+        msgOutTmp.genlMsg.cmd = OVS_VPORT_CMD_DEL;
+    } else {
+        ASSERT(FALSE);
+        return STATUS_UNSUCCESSFUL;
+    }
+    msgOutTmp.ovsHdr.dp_ifindex = gOvsSwitchContext->dpNo;
+
+    rc = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
+    if (!rc) {
+        status = STATUS_INVALID_BUFFER_SIZE;
+        goto cleanup;
+    }
+
+    vport = OvsFindVportByPortNo(gOvsSwitchContext, eventEntry->portNo);
+    if (!vport) {
+        status = STATUS_DEVICE_DOES_NOT_EXIST;
+        goto cleanup;
+    }
+
+    rc = NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_PORT_NO, eventEntry->portNo) ||
+         NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_TYPE, vport->ovsType) ||
+         NlMsgPutTailString(nlBuf, OVS_VPORT_ATTR_NAME, vport->ovsName);
+    if (!rc) {
+        status = STATUS_INVALID_BUFFER_SIZE;
+        goto cleanup;
+    }
+
+    /* XXXX Should we add the port stats attributes?*/
+    nlMsg = (PNL_MSG_HDR)NlBufAt(nlBuf, 0, 0);
+    nlMsg->nlmsgLen = NlBufSize(nlBuf);
+    status = STATUS_SUCCESS;
+
+cleanup:
+    return status;
+}
+
+
+/*
+ * --------------------------------------------------------------------------
+ * Handler for reading events from the driver event queue. This handler is
+ * executed when user modes issues a socket receive on a socket assocaited
+ * with the MC group for events.
+ * XXX user mode should read multiple events in one system call
+ * --------------------------------------------------------------------------
+ */
+static NTSTATUS
+OvsReadEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+                       UINT32 *replyLen)
+{
+#ifdef DBG
+    POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
+    POVS_OPEN_INSTANCE instance =
+        (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
+#endif
+    NL_BUFFER nlBuf;
+    NTSTATUS status;
+    OVS_EVENT_ENTRY eventEntry;
+
+    ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
+
+    /* Should never read events with a dump socket */
+    ASSERT(instance->dumpState.ovsMsg == NULL);
+
+    /* Must have an event queue */
+    ASSERT(instance->eventQueue != NULL);
+
+    /* Output buffer has been validated while validating read dev op. */
+    ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
+
+    NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
+
+    OvsAcquireCtrlLock();
+    if (!gOvsSwitchContext) {
+        status = STATUS_SUCCESS;
+        goto cleanup;
+    }
+
+    /* remove an event entry from the event queue */
+    status = OvsRemoveEventEntry(usrParamsCtx->ovsInstance, &eventEntry);
+    if (status != STATUS_SUCCESS) {
+        goto cleanup;
+    }
+
+    status = OvsPortFillInfo(usrParamsCtx, &eventEntry, &nlBuf);
+
+cleanup:
+    OvsReleaseCtrlLock();
+    *replyLen = NlBufSize(&nlBuf);;
+    return status;
+}
 #endif /* OVS_USE_NL_INTERFACE */
diff --git a/datapath-windows/ovsext/Event.c b/datapath-windows/ovsext/Event.c
index fec3485..467771d 100644
--- a/datapath-windows/ovsext/Event.c
+++ b/datapath-windows/ovsext/Event.c
@@ -292,6 +292,7 @@ done_event_subscribe:
     return status;
 }
 
+#if defined OVS_USE_NL_INTERFACE && OVS_USE_NL_INTERFACE == 0
 /*
  * --------------------------------------------------------------------------
  * Poll event queued in the event queue. always synchronous.
@@ -376,6 +377,7 @@ event_poll_done:
     OVS_LOG_TRACE("Exit: numEventPolled: %d", numEntry);
     return STATUS_SUCCESS;
 }
+#endif /* OVS_USE_NL_INTERFACE */
 
 
 /*
@@ -494,3 +496,43 @@ OvsWaitEventIoctl(PIRP irp,
     OVS_LOG_TRACE("Exit: return status: %#x", status);
     return status;
 }
+
+/*
+ *--------------------------------------------------------------------------
+ * Poll event queued in the event queue.always synchronous.
+ *
+ * Results:
+ *     STATUS_SUCCESS event was dequeued
+ *     STATUS_UNSUCCESSFUL the queue is empty.
+ * --------------------------------------------------------------------------
+ */
+NTSTATUS
+OvsRemoveEventEntry(POVS_OPEN_INSTANCE instance,
+                    POVS_EVENT_ENTRY entry)
+{
+    NTSTATUS status = STATUS_UNSUCCESSFUL;
+    POVS_EVENT_QUEUE queue;
+    POVS_EVENT_QUEUE_ELEM elem;
+
+    OvsAcquireEventQueueLock();
+
+    queue = (POVS_EVENT_QUEUE)instance->eventQueue;
+
+    if (queue == NULL) {
+        ASSERT(queue);
+        goto remove_event_done;
+    }
+
+    if (queue->numElems) {
+        elem = (POVS_EVENT_QUEUE_ELEM)RemoveHeadList(&queue->elemList);
+        entry->portNo = elem->portNo;
+        entry->status = elem->status;
+        OvsFreeMemory(elem);
+        queue->numElems--;
+        status = STATUS_SUCCESS;
+    }
+
+remove_event_done:
+    OvsReleaseEventQueueLock();
+    return status;
+}
diff --git a/datapath-windows/ovsext/Event.h b/datapath-windows/ovsext/Event.h
index f4801b9..a43a0bb 100644
--- a/datapath-windows/ovsext/Event.h
+++ b/datapath-windows/ovsext/Event.h
@@ -47,4 +47,6 @@ NTSTATUS OvsPollEventIoctl(PFILE_OBJECT fileObject, PVOID inputBuffer,
                            UINT32 outputLength, UINT32 *replyLen);
 NTSTATUS OvsWaitEventIoctl(PIRP irp, PFILE_OBJECT fileObject,
                            PVOID inputBuffer, UINT32 inputLength);
+NTSTATUS OvsRemoveEventEntry(PVOID instance, POVS_EVENT_ENTRY entry);
+
 #endif /* __EVENT_H_ */
-- 
1.9.4.msysgit.0




More information about the dev mailing list