diff options
Diffstat (limited to 'datapath-windows')
-rw-r--r-- | datapath-windows/include/OvsDpInterfaceExt.h | 13 | ||||
-rw-r--r-- | datapath-windows/ovsext/Datapath.c | 158 | ||||
-rw-r--r-- | datapath-windows/ovsext/Event.c | 42 | ||||
-rw-r--r-- | datapath-windows/ovsext/Event.h | 2 |
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_ */ |