summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--datapath-windows/include/OvsDpInterfaceExt.h13
-rw-r--r--datapath-windows/ovsext/Datapath.c158
-rw-r--r--datapath-windows/ovsext/Event.c42
-rw-r--r--datapath-windows/ovsext/Event.h2
4 files changed, 213 insertions, 2 deletions
diff --git a/datapath-windows/include/OvsDpInterfaceExt.h b/datapath-windows/include/OvsDpInterfaceExt.h
index 72b2e8e83..e1c186ffc 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_EVENT \
+ CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x1, METHOD_OUT_DIRECT, \
+ FILE_READ_ACCESS)
+#define OVS_IOCTL_READ_PACKET \
+ 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)
/*
@@ -72,6 +78,9 @@ enum ovs_win_control_cmd {
OVS_CTRL_CMD_WIN_GET_PID,
OVS_CTRL_CMD_WIN_PEND_REQ,
OVS_CTRL_CMD_MC_SUBSCRIBE_REQ,
+
+ /* This command is logically belong to the Vport family */
+ OVS_CTRL_CMD_EVENT_NOTIFY
};
/* NL Attributes for joining/unjoining an MC group */
diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c
index b6dc55e8b..3be383564 100644
--- a/datapath-windows/ovsext/Datapath.c
+++ b/datapath-windows/ovsext/Datapath.c
@@ -93,6 +93,7 @@ typedef struct _NETLINK_FAMILY {
#define OVS_READ_DEV_OP (1 << 0)
#define OVS_WRITE_DEV_OP (1 << 1)
#define OVS_TRANSACTION_DEV_OP (1 << 2)
+#define OVS_READ_EVENT_DEV_OP (1 << 3)
/* Handlers for the various netlink commands. */
static NetlinkCmdHandler OvsGetPidCmdHandler,
@@ -100,6 +101,7 @@ static NetlinkCmdHandler OvsGetPidCmdHandler,
OvsPendEventCmdHandler,
OvsSubscribeEventCmdHandler,
OvsSetDpCmdHandler,
+ OvsReadEventCmdHandler,
OvsGetVportCmdHandler;
static NTSTATUS HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
@@ -132,6 +134,11 @@ NETLINK_CMD nlControlFamilyCmdOps[] = {
.handler = OvsSubscribeEventCmdHandler,
.supportedDevOp = OVS_WRITE_DEV_OP,
.validateDpIndex = TRUE,
+ },
+ { .cmd = OVS_CTRL_CMD_EVENT_NOTIFY,
+ .handler = OvsReadEventCmdHandler,
+ .supportedDevOp = OVS_READ_EVENT_DEV_OP,
+ .validateDpIndex = FALSE,
}
};
@@ -629,6 +636,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_CTRL_FAMILY_ID;
+ /* An "artificial" command so we can use NL family function table*/
+ ovsMsg->genlMsg.cmd = OVS_CTRL_CMD_EVENT_NOTIFY;
+ devOp = OVS_READ_DEV_OP;
+ break;
+
case OVS_IOCTL_READ:
/* Output buffer is mandatory. */
if (outputBufferLen != 0) {
@@ -934,6 +964,7 @@ OvsPendEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
return status;
}
+
/*
* --------------------------------------------------------------------------
* Handler for the subscription for the event queue
@@ -1567,4 +1598,131 @@ 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: ? */
+
+ /* driver intiated messages should have zerp seq number*/
+ msgOutTmp.nlMsg.nlmsgSeq = 0;
+ 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);
+ if (status == NDIS_STATUS_SUCCESS) {
+ *replyLen = NlBufSize(&nlBuf);
+ }
+
+cleanup:
+ OvsReleaseCtrlLock();
+ return status;
+}
#endif /* OVS_USE_NL_INTERFACE */
diff --git a/datapath-windows/ovsext/Event.c b/datapath-windows/ovsext/Event.c
index fec3485f8..467771de3 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 f4801b981..a43a0bbd0 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_ */