2 * Copyright (c) 2014 VMware, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * XXX: OVS_USE_NL_INTERFACE is being used to keep the legacy DPIF interface
19 * alive while we transition over to the netlink based interface.
20 * OVS_USE_NL_INTERFACE = 0 => legacy inteface to use with dpif-windows.c
21 * OVS_USE_NL_INTERFACE = 1 => netlink inteface to use with ported dpif-linux.c
42 #define OVS_DBG_MOD OVS_DBG_DATAPATH
45 #define NETLINK_FAMILY_NAME_LEN 48
49 * Netlink messages are grouped by family (aka type), and each family supports
50 * a set of commands, and can be passed both from kernel -> userspace or
51 * vice-versa. To call into the kernel, userspace uses a device operation which
52 * is outside of a netlink message.
54 * Each command results in the invocation of a handler function to implement the
55 * request functionality.
57 * Expectedly, only certain combinations of (device operation, netlink family,
60 * Here, we implement the basic infrastructure to perform validation on the
61 * incoming message, version checking, and also to invoke the corresponding
62 * handler to do the heavy-lifting.
66 * Handler for a given netlink command. Not all the parameters are used by all
69 typedef NTSTATUS(NetlinkCmdHandler)(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
72 typedef struct _NETLINK_CMD {
74 NetlinkCmdHandler *handler;
75 UINT32 supportedDevOp; /* Supported device operations. */
76 BOOLEAN validateDpIndex; /* Does command require a valid DP argument. */
77 } NETLINK_CMD, *PNETLINK_CMD;
79 /* A netlink family is a group of commands. */
80 typedef struct _NETLINK_FAMILY {
86 NETLINK_CMD *cmds; /* Array of netlink commands and handlers. */
88 } NETLINK_FAMILY, *PNETLINK_FAMILY;
90 /* Handlers for the various netlink commands. */
91 static NetlinkCmdHandler OvsGetPidCmdHandler,
92 OvsPendEventCmdHandler,
93 OvsPendPacketCmdHandler,
94 OvsSubscribeEventCmdHandler,
95 OvsSubscribePacketCmdHandler,
96 OvsReadEventCmdHandler,
97 OvsReadPacketCmdHandler,
102 NetlinkCmdHandler OvsGetNetdevCmdHandler,
103 OvsGetVportCmdHandler,
104 OvsSetVportCmdHandler,
105 OvsNewVportCmdHandler,
106 OvsDeleteVportCmdHandler;
108 static NTSTATUS HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
110 static NTSTATUS HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
112 static NTSTATUS HandleDpTransactionCommon(
113 POVS_USER_PARAMS_CONTEXT usrParamsCtx, UINT32 *replyLen);
116 * The various netlink families, along with the supported commands. Most of
117 * these families and commands are part of the openvswitch specification for a
118 * netlink datapath. In addition, each platform can implement a few families
119 * and commands as extensions.
122 /* Netlink control family: this is a Windows specific family. */
123 NETLINK_CMD nlControlFamilyCmdOps[] = {
124 { .cmd = OVS_CTRL_CMD_WIN_GET_PID,
125 .handler = OvsGetPidCmdHandler,
126 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
127 .validateDpIndex = FALSE,
129 { .cmd = OVS_CTRL_CMD_WIN_PEND_REQ,
130 .handler = OvsPendEventCmdHandler,
131 .supportedDevOp = OVS_WRITE_DEV_OP,
132 .validateDpIndex = TRUE,
134 { .cmd = OVS_CTRL_CMD_WIN_PEND_PACKET_REQ,
135 .handler = OvsPendPacketCmdHandler,
136 .supportedDevOp = OVS_WRITE_DEV_OP,
137 .validateDpIndex = TRUE,
139 { .cmd = OVS_CTRL_CMD_MC_SUBSCRIBE_REQ,
140 .handler = OvsSubscribeEventCmdHandler,
141 .supportedDevOp = OVS_WRITE_DEV_OP,
142 .validateDpIndex = TRUE,
144 { .cmd = OVS_CTRL_CMD_PACKET_SUBSCRIBE_REQ,
145 .handler = OvsSubscribePacketCmdHandler,
146 .supportedDevOp = OVS_WRITE_DEV_OP,
147 .validateDpIndex = TRUE,
149 { .cmd = OVS_CTRL_CMD_EVENT_NOTIFY,
150 .handler = OvsReadEventCmdHandler,
151 .supportedDevOp = OVS_READ_EVENT_DEV_OP,
152 .validateDpIndex = FALSE,
154 { .cmd = OVS_CTRL_CMD_READ_NOTIFY,
155 .handler = OvsReadPacketCmdHandler,
156 .supportedDevOp = OVS_READ_PACKET_DEV_OP,
157 .validateDpIndex = FALSE,
161 NETLINK_FAMILY nlControlFamilyOps = {
162 .name = OVS_WIN_CONTROL_FAMILY,
163 .id = OVS_WIN_NL_CTRL_FAMILY_ID,
164 .version = OVS_WIN_CONTROL_VERSION,
165 .maxAttr = OVS_WIN_CONTROL_ATTR_MAX,
166 .cmds = nlControlFamilyCmdOps,
167 .opsCount = ARRAY_SIZE(nlControlFamilyCmdOps)
170 /* Netlink datapath family. */
171 NETLINK_CMD nlDatapathFamilyCmdOps[] = {
172 { .cmd = OVS_DP_CMD_NEW,
173 .handler = OvsNewDpCmdHandler,
174 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
175 .validateDpIndex = FALSE
177 { .cmd = OVS_DP_CMD_GET,
178 .handler = OvsGetDpCmdHandler,
179 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
180 OVS_TRANSACTION_DEV_OP,
181 .validateDpIndex = FALSE
183 { .cmd = OVS_DP_CMD_SET,
184 .handler = OvsSetDpCmdHandler,
185 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
186 OVS_TRANSACTION_DEV_OP,
187 .validateDpIndex = TRUE
191 NETLINK_FAMILY nlDatapathFamilyOps = {
192 .name = OVS_DATAPATH_FAMILY,
193 .id = OVS_WIN_NL_DATAPATH_FAMILY_ID,
194 .version = OVS_DATAPATH_VERSION,
195 .maxAttr = OVS_DP_ATTR_MAX,
196 .cmds = nlDatapathFamilyCmdOps,
197 .opsCount = ARRAY_SIZE(nlDatapathFamilyCmdOps)
200 /* Netlink packet family. */
202 NETLINK_CMD nlPacketFamilyCmdOps[] = {
203 { .cmd = OVS_PACKET_CMD_EXECUTE,
204 .handler = OvsNlExecuteCmdHandler,
205 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
206 .validateDpIndex = TRUE
210 NETLINK_FAMILY nlPacketFamilyOps = {
211 .name = OVS_PACKET_FAMILY,
212 .id = OVS_WIN_NL_PACKET_FAMILY_ID,
213 .version = OVS_PACKET_VERSION,
214 .maxAttr = OVS_PACKET_ATTR_MAX,
215 .cmds = nlPacketFamilyCmdOps,
216 .opsCount = ARRAY_SIZE(nlPacketFamilyCmdOps)
219 /* Netlink vport family. */
220 NETLINK_CMD nlVportFamilyCmdOps[] = {
221 { .cmd = OVS_VPORT_CMD_GET,
222 .handler = OvsGetVportCmdHandler,
223 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
224 OVS_TRANSACTION_DEV_OP,
225 .validateDpIndex = TRUE
227 { .cmd = OVS_VPORT_CMD_NEW,
228 .handler = OvsNewVportCmdHandler,
229 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
230 .validateDpIndex = TRUE
232 { .cmd = OVS_VPORT_CMD_SET,
233 .handler = OvsSetVportCmdHandler,
234 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
235 .validateDpIndex = TRUE
237 { .cmd = OVS_VPORT_CMD_DEL,
238 .handler = OvsDeleteVportCmdHandler,
239 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
240 .validateDpIndex = TRUE
244 NETLINK_FAMILY nlVportFamilyOps = {
245 .name = OVS_VPORT_FAMILY,
246 .id = OVS_WIN_NL_VPORT_FAMILY_ID,
247 .version = OVS_VPORT_VERSION,
248 .maxAttr = OVS_VPORT_ATTR_MAX,
249 .cmds = nlVportFamilyCmdOps,
250 .opsCount = ARRAY_SIZE(nlVportFamilyCmdOps)
253 /* Netlink flow family. */
255 NETLINK_CMD nlFlowFamilyCmdOps[] = {
256 { .cmd = OVS_FLOW_CMD_NEW,
257 .handler = OvsFlowNlCmdHandler,
258 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
259 .validateDpIndex = TRUE
261 { .cmd = OVS_FLOW_CMD_SET,
262 .handler = OvsFlowNlCmdHandler,
263 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
264 .validateDpIndex = TRUE
266 { .cmd = OVS_FLOW_CMD_DEL,
267 .handler = OvsFlowNlCmdHandler,
268 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
269 .validateDpIndex = TRUE
271 { .cmd = OVS_FLOW_CMD_GET,
272 .handler = OvsFlowNlGetCmdHandler,
273 .supportedDevOp = OVS_TRANSACTION_DEV_OP |
274 OVS_WRITE_DEV_OP | OVS_READ_DEV_OP,
275 .validateDpIndex = TRUE
279 NETLINK_FAMILY nlFLowFamilyOps = {
280 .name = OVS_FLOW_FAMILY,
281 .id = OVS_WIN_NL_FLOW_FAMILY_ID,
282 .version = OVS_FLOW_VERSION,
283 .maxAttr = OVS_FLOW_ATTR_MAX,
284 .cmds = nlFlowFamilyCmdOps,
285 .opsCount = ARRAY_SIZE(nlFlowFamilyCmdOps)
288 /* Netlink netdev family. */
289 NETLINK_CMD nlNetdevFamilyCmdOps[] = {
290 { .cmd = OVS_WIN_NETDEV_CMD_GET,
291 .handler = OvsGetNetdevCmdHandler,
292 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
293 .validateDpIndex = FALSE
297 NETLINK_FAMILY nlNetdevFamilyOps = {
298 .name = OVS_WIN_NETDEV_FAMILY,
299 .id = OVS_WIN_NL_NETDEV_FAMILY_ID,
300 .version = OVS_WIN_NETDEV_VERSION,
301 .maxAttr = OVS_WIN_NETDEV_ATTR_MAX,
302 .cmds = nlNetdevFamilyCmdOps,
303 .opsCount = ARRAY_SIZE(nlNetdevFamilyCmdOps)
306 static NTSTATUS MapIrpOutputBuffer(PIRP irp,
308 UINT32 requiredLength,
310 static NTSTATUS ValidateNetlinkCmd(UINT32 devOp,
311 POVS_OPEN_INSTANCE instance,
313 NETLINK_FAMILY *nlFamilyOps);
314 static NTSTATUS InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
315 NETLINK_FAMILY *nlFamilyOps,
318 /* Handles to the device object for communication with userspace. */
319 NDIS_HANDLE gOvsDeviceHandle;
320 PDEVICE_OBJECT gOvsDeviceObject;
322 _Dispatch_type_(IRP_MJ_CREATE)
323 _Dispatch_type_(IRP_MJ_CLOSE)
324 DRIVER_DISPATCH OvsOpenCloseDevice;
326 _Dispatch_type_(IRP_MJ_CLEANUP)
327 DRIVER_DISPATCH OvsCleanupDevice;
329 _Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
330 DRIVER_DISPATCH OvsDeviceControl;
333 #pragma alloc_text(INIT, OvsCreateDeviceObject)
334 #pragma alloc_text(PAGE, OvsOpenCloseDevice)
335 #pragma alloc_text(PAGE, OvsCleanupDevice)
336 #pragma alloc_text(PAGE, OvsDeviceControl)
337 #endif // ALLOC_PRAGMA
340 * We might hit this limit easily since userspace opens a netlink descriptor for
341 * each thread, and at least one descriptor per vport. Revisit this later.
343 #define OVS_MAX_OPEN_INSTANCES 512
344 #define OVS_SYSTEM_DP_NAME "ovs-system"
346 POVS_OPEN_INSTANCE ovsOpenInstanceArray[OVS_MAX_OPEN_INSTANCES];
347 UINT32 ovsNumberOfOpenInstances;
348 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
350 NDIS_SPIN_LOCK ovsCtrlLockObj;
351 PNDIS_SPIN_LOCK gOvsCtrlLock;
357 gOvsCtrlLock = &ovsCtrlLockObj;
358 NdisAllocateSpinLock(gOvsCtrlLock);
365 OvsCleanupEventQueue();
367 NdisFreeSpinLock(gOvsCtrlLock);
375 NdisAcquireSpinLock(gOvsCtrlLock);
381 NdisReleaseSpinLock(gOvsCtrlLock);
386 * --------------------------------------------------------------------------
387 * Creates the communication device between user and kernel, and also
388 * initializes the data associated data structures.
389 * --------------------------------------------------------------------------
392 OvsCreateDeviceObject(NDIS_HANDLE ovsExtDriverHandle)
394 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
395 UNICODE_STRING deviceName;
396 UNICODE_STRING symbolicDeviceName;
397 PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
398 NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttributes;
399 OVS_LOG_TRACE("ovsExtDriverHandle: %p", ovsExtDriverHandle);
401 RtlZeroMemory(dispatchTable,
402 (IRP_MJ_MAXIMUM_FUNCTION + 1) * sizeof (PDRIVER_DISPATCH));
403 dispatchTable[IRP_MJ_CREATE] = OvsOpenCloseDevice;
404 dispatchTable[IRP_MJ_CLOSE] = OvsOpenCloseDevice;
405 dispatchTable[IRP_MJ_CLEANUP] = OvsCleanupDevice;
406 dispatchTable[IRP_MJ_DEVICE_CONTROL] = OvsDeviceControl;
408 NdisInitUnicodeString(&deviceName, OVS_DEVICE_NAME_NT);
409 NdisInitUnicodeString(&symbolicDeviceName, OVS_DEVICE_NAME_DOS);
411 RtlZeroMemory(&deviceAttributes, sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
413 OVS_INIT_OBJECT_HEADER(&deviceAttributes.Header,
414 NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES,
415 NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1,
416 sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
418 deviceAttributes.DeviceName = &deviceName;
419 deviceAttributes.SymbolicName = &symbolicDeviceName;
420 deviceAttributes.MajorFunctions = dispatchTable;
421 deviceAttributes.ExtensionSize = sizeof (OVS_DEVICE_EXTENSION);
423 status = NdisRegisterDeviceEx(ovsExtDriverHandle,
427 if (status != NDIS_STATUS_SUCCESS) {
428 POVS_DEVICE_EXTENSION ovsExt =
429 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(gOvsDeviceObject);
430 ASSERT(gOvsDeviceObject != NULL);
431 ASSERT(gOvsDeviceHandle != NULL);
434 ovsExt->numberOpenInstance = 0;
437 /* Initialize the associated data structures. */
440 OVS_LOG_TRACE("DeviceObject: %p", gOvsDeviceObject);
446 OvsDeleteDeviceObject()
448 if (gOvsDeviceHandle) {
450 POVS_DEVICE_EXTENSION ovsExt = (POVS_DEVICE_EXTENSION)
451 NdisGetDeviceReservedExtension(gOvsDeviceObject);
453 ASSERT(ovsExt->numberOpenInstance == 0);
457 ASSERT(gOvsDeviceObject);
458 NdisDeregisterDeviceEx(gOvsDeviceHandle);
459 gOvsDeviceHandle = NULL;
460 gOvsDeviceObject = NULL;
466 OvsGetOpenInstance(PFILE_OBJECT fileObject,
469 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
471 ASSERT(instance->fileObject == fileObject);
472 if (gOvsSwitchContext->dpNo != dpNo) {
480 OvsFindOpenInstance(PFILE_OBJECT fileObject)
483 for (i = 0, j = 0; i < OVS_MAX_OPEN_INSTANCES &&
484 j < ovsNumberOfOpenInstances; i++) {
485 if (ovsOpenInstanceArray[i]) {
486 if (ovsOpenInstanceArray[i]->fileObject == fileObject) {
487 return ovsOpenInstanceArray[i];
496 OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt,
497 PFILE_OBJECT fileObject)
499 POVS_OPEN_INSTANCE instance =
500 (POVS_OPEN_INSTANCE) OvsAllocateMemory(sizeof (OVS_OPEN_INSTANCE));
503 if (instance == NULL) {
504 return STATUS_NO_MEMORY;
506 OvsAcquireCtrlLock();
507 ASSERT(OvsFindOpenInstance(fileObject) == NULL);
509 if (ovsNumberOfOpenInstances >= OVS_MAX_OPEN_INSTANCES) {
510 OvsReleaseCtrlLock();
511 OvsFreeMemory(instance);
512 return STATUS_INSUFFICIENT_RESOURCES;
514 RtlZeroMemory(instance, sizeof (OVS_OPEN_INSTANCE));
516 for (i = 0; i < OVS_MAX_OPEN_INSTANCES; i++) {
517 if (ovsOpenInstanceArray[i] == NULL) {
518 ovsOpenInstanceArray[i] = instance;
519 ovsNumberOfOpenInstances++;
520 instance->cookie = i;
524 ASSERT(i < OVS_MAX_OPEN_INSTANCES);
525 instance->fileObject = fileObject;
526 ASSERT(fileObject->FsContext == NULL);
527 instance->pid = (UINT32)InterlockedIncrement((LONG volatile *)&ovsExt->pidCount);
528 if (instance->pid == 0) {
529 /* XXX: check for rollover. */
531 fileObject->FsContext = instance;
532 OvsReleaseCtrlLock();
533 return STATUS_SUCCESS;
537 OvsCleanupOpenInstance(PFILE_OBJECT fileObject)
539 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
541 ASSERT(fileObject == instance->fileObject);
542 OvsCleanupEvent(instance);
543 OvsCleanupPacketQueue(instance);
547 OvsRemoveOpenInstance(PFILE_OBJECT fileObject)
549 POVS_OPEN_INSTANCE instance;
550 ASSERT(fileObject->FsContext);
551 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
552 ASSERT(instance->cookie < OVS_MAX_OPEN_INSTANCES);
554 OvsAcquireCtrlLock();
555 fileObject->FsContext = NULL;
556 ASSERT(ovsOpenInstanceArray[instance->cookie] == instance);
557 ovsOpenInstanceArray[instance->cookie] = NULL;
558 ovsNumberOfOpenInstances--;
559 OvsReleaseCtrlLock();
560 ASSERT(instance->eventQueue == NULL);
561 ASSERT (instance->packetQueue == NULL);
562 OvsFreeMemory(instance);
566 OvsCompleteIrpRequest(PIRP irp,
570 irp->IoStatus.Information = infoPtr;
571 irp->IoStatus.Status = status;
572 IoCompleteRequest(irp, IO_NO_INCREMENT);
578 OvsOpenCloseDevice(PDEVICE_OBJECT deviceObject,
581 PIO_STACK_LOCATION irpSp;
582 NTSTATUS status = STATUS_SUCCESS;
583 PFILE_OBJECT fileObject;
584 POVS_DEVICE_EXTENSION ovsExt =
585 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
587 ASSERT(deviceObject == gOvsDeviceObject);
588 ASSERT(ovsExt != NULL);
590 irpSp = IoGetCurrentIrpStackLocation(irp);
591 fileObject = irpSp->FileObject;
592 OVS_LOG_TRACE("DeviceObject: %p, fileObject:%p, instance: %u",
593 deviceObject, fileObject,
594 ovsExt->numberOpenInstance);
596 switch (irpSp->MajorFunction) {
598 status = OvsAddOpenInstance(ovsExt, fileObject);
599 if (STATUS_SUCCESS == status) {
600 InterlockedIncrement((LONG volatile *)&ovsExt->numberOpenInstance);
604 ASSERT(ovsExt->numberOpenInstance > 0);
605 OvsRemoveOpenInstance(fileObject);
606 InterlockedDecrement((LONG volatile *)&ovsExt->numberOpenInstance);
611 return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
614 _Use_decl_annotations_
616 OvsCleanupDevice(PDEVICE_OBJECT deviceObject,
620 PIO_STACK_LOCATION irpSp;
621 PFILE_OBJECT fileObject;
623 NTSTATUS status = STATUS_SUCCESS;
625 POVS_DEVICE_EXTENSION ovsExt =
626 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
628 ASSERT(ovsExt->numberOpenInstance > 0);
631 UNREFERENCED_PARAMETER(deviceObject);
633 ASSERT(deviceObject == gOvsDeviceObject);
634 irpSp = IoGetCurrentIrpStackLocation(irp);
635 fileObject = irpSp->FileObject;
637 ASSERT(irpSp->MajorFunction == IRP_MJ_CLEANUP);
639 OvsCleanupOpenInstance(fileObject);
641 return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
646 * --------------------------------------------------------------------------
647 * IOCTL function handler for the device.
648 * --------------------------------------------------------------------------
651 OvsDeviceControl(PDEVICE_OBJECT deviceObject,
654 PIO_STACK_LOCATION irpSp;
655 NTSTATUS status = STATUS_SUCCESS;
656 PFILE_OBJECT fileObject;
657 PVOID inputBuffer = NULL;
658 PVOID outputBuffer = NULL;
659 UINT32 inputBufferLen, outputBufferLen;
660 UINT32 code, replyLen = 0;
661 POVS_OPEN_INSTANCE instance;
663 OVS_MESSAGE ovsMsgReadOp;
665 NETLINK_FAMILY *nlFamilyOps;
666 OVS_USER_PARAMS_CONTEXT usrParamsCtx;
669 POVS_DEVICE_EXTENSION ovsExt =
670 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
671 ASSERT(deviceObject == gOvsDeviceObject);
673 ASSERT(ovsExt->numberOpenInstance > 0);
675 UNREFERENCED_PARAMETER(deviceObject);
678 irpSp = IoGetCurrentIrpStackLocation(irp);
680 ASSERT(irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
681 ASSERT(irpSp->FileObject != NULL);
683 fileObject = irpSp->FileObject;
684 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
685 code = irpSp->Parameters.DeviceIoControl.IoControlCode;
686 inputBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
687 outputBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
688 inputBuffer = irp->AssociatedIrp.SystemBuffer;
690 /* Check if the extension is enabled. */
691 if (NULL == gOvsSwitchContext) {
692 status = STATUS_DEVICE_NOT_READY;
696 /* Concurrent netlink operations are not supported. */
697 if (InterlockedCompareExchange((LONG volatile *)&instance->inUse, 1, 0)) {
698 status = STATUS_RESOURCE_IN_USE;
703 * Validate the input/output buffer arguments depending on the type of the
707 case OVS_IOCTL_TRANSACT:
708 /* Both input buffer and output buffer are mandatory. */
709 if (outputBufferLen != 0) {
710 status = MapIrpOutputBuffer(irp, outputBufferLen,
711 sizeof *ovsMsg, &outputBuffer);
712 if (status != STATUS_SUCCESS) {
715 ASSERT(outputBuffer);
717 status = STATUS_NDIS_INVALID_LENGTH;
721 if (inputBufferLen < sizeof (*ovsMsg)) {
722 status = STATUS_NDIS_INVALID_LENGTH;
726 ovsMsg = inputBuffer;
727 devOp = OVS_TRANSACTION_DEV_OP;
730 case OVS_IOCTL_READ_EVENT:
731 case OVS_IOCTL_READ_PACKET:
733 * Output buffer is mandatory. These IOCTLs are used to read events and
734 * packets respectively. It is convenient to have separate ioctls.
736 if (outputBufferLen != 0) {
737 status = MapIrpOutputBuffer(irp, outputBufferLen,
738 sizeof *ovsMsg, &outputBuffer);
739 if (status != STATUS_SUCCESS) {
742 ASSERT(outputBuffer);
744 status = STATUS_NDIS_INVALID_LENGTH;
750 ovsMsg = &ovsMsgReadOp;
751 ovsMsg->nlMsg.nlmsgType = OVS_WIN_NL_CTRL_FAMILY_ID;
752 ovsMsg->nlMsg.nlmsgPid = instance->pid;
753 /* An "artificial" command so we can use NL family function table*/
754 ovsMsg->genlMsg.cmd = (code == OVS_IOCTL_READ_EVENT) ?
755 OVS_CTRL_CMD_EVENT_NOTIFY :
756 OVS_CTRL_CMD_READ_NOTIFY;
757 devOp = OVS_READ_DEV_OP;
761 /* Output buffer is mandatory. */
762 if (outputBufferLen != 0) {
763 status = MapIrpOutputBuffer(irp, outputBufferLen,
764 sizeof *ovsMsg, &outputBuffer);
765 if (status != STATUS_SUCCESS) {
768 ASSERT(outputBuffer);
770 status = STATUS_NDIS_INVALID_LENGTH;
775 * Operate in the mode that read ioctl is similar to ReadFile(). This
776 * might change as the userspace code gets implemented.
782 * For implementing read (ioctl or otherwise), we need to store some
783 * state in the instance to indicate the command that started the dump
784 * operation. The state can setup 'ovsMsgReadOp' appropriately. Note
785 * that 'ovsMsgReadOp' is needed only in this function to call into the
786 * appropriate handler. The handler itself can access the state in the
789 * In the absence of a dump start, return 0 bytes.
791 if (instance->dumpState.ovsMsg == NULL) {
793 status = STATUS_SUCCESS;
796 RtlCopyMemory(&ovsMsgReadOp, instance->dumpState.ovsMsg,
797 sizeof (ovsMsgReadOp));
799 /* Create an NL message for consumption. */
800 ovsMsg = &ovsMsgReadOp;
801 devOp = OVS_READ_DEV_OP;
805 case OVS_IOCTL_WRITE:
806 /* Input buffer is mandatory. */
807 if (inputBufferLen < sizeof (*ovsMsg)) {
808 status = STATUS_NDIS_INVALID_LENGTH;
812 ovsMsg = inputBuffer;
813 devOp = OVS_WRITE_DEV_OP;
817 status = STATUS_INVALID_DEVICE_REQUEST;
822 switch (ovsMsg->nlMsg.nlmsgType) {
823 case OVS_WIN_NL_CTRL_FAMILY_ID:
824 nlFamilyOps = &nlControlFamilyOps;
826 case OVS_WIN_NL_DATAPATH_FAMILY_ID:
827 nlFamilyOps = &nlDatapathFamilyOps;
829 case OVS_WIN_NL_FLOW_FAMILY_ID:
830 nlFamilyOps = &nlFLowFamilyOps;
832 case OVS_WIN_NL_PACKET_FAMILY_ID:
833 nlFamilyOps = &nlPacketFamilyOps;
835 case OVS_WIN_NL_VPORT_FAMILY_ID:
836 nlFamilyOps = &nlVportFamilyOps;
838 case OVS_WIN_NL_NETDEV_FAMILY_ID:
839 nlFamilyOps = &nlNetdevFamilyOps;
842 status = STATUS_INVALID_PARAMETER;
847 * For read operation, the netlink command has already been validated
850 if (devOp != OVS_READ_DEV_OP) {
851 status = ValidateNetlinkCmd(devOp, instance, ovsMsg, nlFamilyOps);
852 if (status != STATUS_SUCCESS) {
857 InitUserParamsCtx(irp, instance, devOp, ovsMsg,
858 inputBuffer, inputBufferLen,
859 outputBuffer, outputBufferLen,
862 status = InvokeNetlinkCmdHandler(&usrParamsCtx, nlFamilyOps, &replyLen);
868 /* Should not complete a pending IRP unless proceesing is completed */
869 if (status == STATUS_PENDING) {
872 return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status);
877 * --------------------------------------------------------------------------
878 * Function to validate a netlink command. Only certain combinations of
879 * (device operation, netlink family, command) are valid.
880 * --------------------------------------------------------------------------
883 ValidateNetlinkCmd(UINT32 devOp,
884 POVS_OPEN_INSTANCE instance,
886 NETLINK_FAMILY *nlFamilyOps)
888 NTSTATUS status = STATUS_INVALID_PARAMETER;
891 for (i = 0; i < nlFamilyOps->opsCount; i++) {
892 if (nlFamilyOps->cmds[i].cmd == ovsMsg->genlMsg.cmd) {
893 /* Validate if the command is valid for the device operation. */
894 if ((devOp & nlFamilyOps->cmds[i].supportedDevOp) == 0) {
895 status = STATUS_INVALID_PARAMETER;
899 /* Validate the version. */
900 if (nlFamilyOps->version > ovsMsg->genlMsg.version) {
901 status = STATUS_INVALID_PARAMETER;
905 /* Validate the DP for commands that require a DP. */
906 if (nlFamilyOps->cmds[i].validateDpIndex == TRUE) {
907 OvsAcquireCtrlLock();
908 if (ovsMsg->ovsHdr.dp_ifindex !=
909 (INT)gOvsSwitchContext->dpNo) {
910 status = STATUS_INVALID_PARAMETER;
911 OvsReleaseCtrlLock();
914 OvsReleaseCtrlLock();
917 /* Validate the PID. */
918 if (ovsMsg->genlMsg.cmd != OVS_CTRL_CMD_WIN_GET_PID) {
919 if (ovsMsg->nlMsg.nlmsgPid != instance->pid) {
920 status = STATUS_INVALID_PARAMETER;
925 status = STATUS_SUCCESS;
935 * --------------------------------------------------------------------------
936 * Function to invoke the netlink command handler.
937 * --------------------------------------------------------------------------
940 InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
941 NETLINK_FAMILY *nlFamilyOps,
944 NTSTATUS status = STATUS_INVALID_PARAMETER;
947 for (i = 0; i < nlFamilyOps->opsCount; i++) {
948 if (nlFamilyOps->cmds[i].cmd == usrParamsCtx->ovsMsg->genlMsg.cmd) {
949 NetlinkCmdHandler *handler = nlFamilyOps->cmds[i].handler;
952 status = handler(usrParamsCtx, replyLen);
962 * --------------------------------------------------------------------------
963 * Command Handler for 'OVS_CTRL_CMD_WIN_GET_PID'.
965 * Each handle on the device is assigned a unique PID when the handle is
966 * created. On platforms that support netlink natively, the PID is available
967 * to userspace when the netlink socket is created. However, without native
968 * netlink support on Windows, OVS datapath generates the PID and lets the
969 * userspace query it.
971 * This function implements the query.
972 * --------------------------------------------------------------------------
975 OvsGetPidCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
978 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
979 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
981 if (usrParamsCtx->outputLength >= sizeof *msgOut) {
982 POVS_OPEN_INSTANCE instance =
983 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
985 RtlZeroMemory(msgOut, sizeof *msgOut);
986 msgOut->nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
987 msgOut->nlMsg.nlmsgPid = instance->pid;
988 *replyLen = sizeof *msgOut;
989 /* XXX: We might need to return the DP index as well. */
991 return STATUS_NDIS_INVALID_LENGTH;
994 return STATUS_SUCCESS;
998 * --------------------------------------------------------------------------
999 * Utility function to fill up information about the datapath in a reply to
1001 * Assumes that 'gOvsCtrlLock' lock is acquired.
1002 * --------------------------------------------------------------------------
1005 OvsDpFillInfo(POVS_SWITCH_CONTEXT ovsSwitchContext,
1010 OVS_MESSAGE msgOutTmp;
1011 OVS_DATAPATH *datapath = &ovsSwitchContext->datapath;
1014 ASSERT(NlBufAt(nlBuf, 0, 0) != 0 && NlBufRemLen(nlBuf) >= sizeof *msgIn);
1016 msgOutTmp.nlMsg.nlmsgType = OVS_WIN_NL_DATAPATH_FAMILY_ID;
1017 msgOutTmp.nlMsg.nlmsgFlags = 0; /* XXX: ? */
1018 msgOutTmp.nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
1019 msgOutTmp.nlMsg.nlmsgPid = msgIn->nlMsg.nlmsgPid;
1021 msgOutTmp.genlMsg.cmd = OVS_DP_CMD_GET;
1022 msgOutTmp.genlMsg.version = nlDatapathFamilyOps.version;
1023 msgOutTmp.genlMsg.reserved = 0;
1025 msgOutTmp.ovsHdr.dp_ifindex = ovsSwitchContext->dpNo;
1027 writeOk = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
1029 writeOk = NlMsgPutTailString(nlBuf, OVS_DP_ATTR_NAME,
1030 OVS_SYSTEM_DP_NAME);
1033 OVS_DP_STATS dpStats;
1035 dpStats.n_hit = datapath->hits;
1036 dpStats.n_missed = datapath->misses;
1037 dpStats.n_lost = datapath->lost;
1038 dpStats.n_flows = datapath->nFlows;
1039 writeOk = NlMsgPutTailUnspec(nlBuf, OVS_DP_ATTR_STATS,
1040 (PCHAR)&dpStats, sizeof dpStats);
1042 nlMsg = (PNL_MSG_HDR)NlBufAt(nlBuf, 0, 0);
1043 nlMsg->nlmsgLen = NlBufSize(nlBuf);
1045 return writeOk ? STATUS_SUCCESS : STATUS_INVALID_BUFFER_SIZE;
1049 * --------------------------------------------------------------------------
1050 * Handler for queueing an IRP used for event notification. The IRP is
1051 * completed when a port state changes. STATUS_PENDING is returned on
1052 * success. User mode keep a pending IRP at all times.
1053 * --------------------------------------------------------------------------
1056 OvsPendEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1061 UNREFERENCED_PARAMETER(replyLen);
1063 POVS_OPEN_INSTANCE instance =
1064 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1065 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1066 OVS_EVENT_POLL poll;
1068 poll.dpNo = msgIn->ovsHdr.dp_ifindex;
1069 status = OvsWaitEventIoctl(usrParamsCtx->irp, instance->fileObject,
1070 &poll, sizeof poll);
1075 * --------------------------------------------------------------------------
1076 * Handler for the subscription for the event queue
1077 * --------------------------------------------------------------------------
1080 OvsSubscribeEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1084 OVS_EVENT_SUBSCRIBE request;
1088 const NL_POLICY policy[] = {
1089 [OVS_NL_ATTR_MCAST_GRP] = {.type = NL_A_U32 },
1090 [OVS_NL_ATTR_MCAST_JOIN] = {.type = NL_A_U8 },
1093 UNREFERENCED_PARAMETER(replyLen);
1095 POVS_OPEN_INSTANCE instance =
1096 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1097 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1099 rc = NlAttrParse(&msgIn->nlMsg, sizeof (*msgIn),
1100 NlMsgAttrsLen((PNL_MSG_HDR)msgIn), policy, attrs, ARRAY_SIZE(attrs));
1102 status = STATUS_INVALID_PARAMETER;
1106 /* XXX Ignore the MC group for now */
1107 join = NlAttrGetU8(attrs[OVS_NL_ATTR_MCAST_JOIN]);
1108 request.dpNo = msgIn->ovsHdr.dp_ifindex;
1109 request.subscribe = join;
1110 request.mask = OVS_EVENT_MASK_ALL;
1112 status = OvsSubscribeEventIoctl(instance->fileObject, &request,
1119 * --------------------------------------------------------------------------
1120 * Command Handler for 'OVS_DP_CMD_NEW'.
1121 * --------------------------------------------------------------------------
1124 OvsNewDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1127 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1131 * --------------------------------------------------------------------------
1132 * Command Handler for 'OVS_DP_CMD_GET'.
1134 * The function handles both the dump based as well as the transaction based
1135 * 'OVS_DP_CMD_GET' command. In the dump command, it handles the initial
1136 * call to setup dump state, as well as subsequent calls to continue dumping
1138 * --------------------------------------------------------------------------
1141 OvsGetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1144 if (usrParamsCtx->devOp == OVS_TRANSACTION_DEV_OP) {
1145 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1147 return HandleGetDpDump(usrParamsCtx, replyLen);
1152 * --------------------------------------------------------------------------
1153 * Function for handling the transaction based 'OVS_DP_CMD_GET' command.
1154 * --------------------------------------------------------------------------
1157 HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1160 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1165 * --------------------------------------------------------------------------
1166 * Function for handling the dump-based 'OVS_DP_CMD_GET' command.
1167 * --------------------------------------------------------------------------
1170 HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1173 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1174 POVS_OPEN_INSTANCE instance =
1175 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1177 if (usrParamsCtx->devOp == OVS_WRITE_DEV_OP) {
1179 OvsSetupDumpStart(usrParamsCtx);
1183 POVS_MESSAGE msgIn = instance->dumpState.ovsMsg;
1185 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1187 if (instance->dumpState.ovsMsg == NULL) {
1189 return STATUS_INVALID_DEVICE_STATE;
1192 /* Dump state must have been deleted after previous dump operation. */
1193 ASSERT(instance->dumpState.index[0] == 0);
1195 /* Output buffer has been validated while validating read dev op. */
1196 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1198 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
1199 usrParamsCtx->outputLength);
1201 OvsAcquireCtrlLock();
1202 status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
1203 OvsReleaseCtrlLock();
1205 if (status != STATUS_SUCCESS) {
1207 FreeUserDumpState(instance);
1211 /* Increment the dump index. */
1212 instance->dumpState.index[0] = 1;
1213 *replyLen = msgOut->nlMsg.nlmsgLen;
1215 /* Free up the dump state, since there's no more data to continue. */
1216 FreeUserDumpState(instance);
1219 return STATUS_SUCCESS;
1224 * --------------------------------------------------------------------------
1225 * Command Handler for 'OVS_DP_CMD_SET'.
1226 * --------------------------------------------------------------------------
1229 OvsSetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1232 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1236 * --------------------------------------------------------------------------
1237 * Function for handling transaction based 'OVS_DP_CMD_NEW', 'OVS_DP_CMD_GET'
1238 * and 'OVS_DP_CMD_SET' commands.
1240 * 'OVS_DP_CMD_NEW' is implemented to keep userspace code happy. Creation of a
1241 * new datapath is not supported currently.
1242 * --------------------------------------------------------------------------
1245 HandleDpTransactionCommon(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1248 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1249 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1250 NTSTATUS status = STATUS_SUCCESS;
1252 NL_ERROR nlError = NL_ERROR_SUCCESS;
1253 static const NL_POLICY ovsDatapathSetPolicy[] = {
1254 [OVS_DP_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ },
1255 [OVS_DP_ATTR_UPCALL_PID] = { .type = NL_A_U32, .optional = TRUE },
1256 [OVS_DP_ATTR_USER_FEATURES] = { .type = NL_A_U32, .optional = TRUE },
1258 PNL_ATTR dpAttrs[ARRAY_SIZE(ovsDatapathSetPolicy)];
1260 /* input buffer has been validated while validating write dev op. */
1261 ASSERT(msgIn != NULL && usrParamsCtx->inputLength >= sizeof *msgIn);
1263 /* Parse any attributes in the request. */
1264 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_SET ||
1265 usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_NEW) {
1266 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1267 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1268 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1269 ovsDatapathSetPolicy, dpAttrs, ARRAY_SIZE(dpAttrs))) {
1270 return STATUS_INVALID_PARAMETER;
1274 * XXX: Not clear at this stage if there's any role for the
1275 * OVS_DP_ATTR_UPCALL_PID and OVS_DP_ATTR_USER_FEATURES attributes passed
1280 RtlZeroMemory(dpAttrs, sizeof dpAttrs);
1283 /* Output buffer has been validated while validating transact dev op. */
1284 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1286 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
1288 OvsAcquireCtrlLock();
1289 if (dpAttrs[OVS_DP_ATTR_NAME] != NULL) {
1290 if (!OvsCompareString(NlAttrGet(dpAttrs[OVS_DP_ATTR_NAME]),
1291 OVS_SYSTEM_DP_NAME)) {
1292 OvsReleaseCtrlLock();
1294 /* Creation of new datapaths is not supported. */
1295 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_SET) {
1296 nlError = NL_ERROR_NOTSUPP;
1300 nlError = NL_ERROR_NODEV;
1303 } else if ((UINT32)msgIn->ovsHdr.dp_ifindex != gOvsSwitchContext->dpNo) {
1304 OvsReleaseCtrlLock();
1305 nlError = NL_ERROR_NODEV;
1309 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_NEW) {
1310 OvsReleaseCtrlLock();
1311 nlError = NL_ERROR_EXIST;
1315 status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
1316 OvsReleaseCtrlLock();
1318 *replyLen = NlBufSize(&nlBuf);
1321 if (nlError != NL_ERROR_SUCCESS) {
1322 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1323 usrParamsCtx->outputBuffer;
1325 BuildErrorMsg(msgIn, msgError, nlError);
1326 *replyLen = msgError->nlMsg.nlmsgLen;
1329 return STATUS_SUCCESS;
1334 OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx)
1336 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1337 POVS_OPEN_INSTANCE instance =
1338 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1340 /* input buffer has been validated while validating write dev op. */
1341 ASSERT(msgIn != NULL && usrParamsCtx->inputLength >= sizeof *msgIn);
1343 /* A write operation that does not indicate dump start is invalid. */
1344 if ((msgIn->nlMsg.nlmsgFlags & NLM_F_DUMP) != NLM_F_DUMP) {
1345 return STATUS_INVALID_PARAMETER;
1347 /* XXX: Handle other NLM_F_* flags in the future. */
1350 * This operation should be setting up the dump state. If there's any
1351 * previous state, clear it up so as to set it up afresh.
1353 FreeUserDumpState(instance);
1355 return InitUserDumpState(instance, msgIn);
1360 * --------------------------------------------------------------------------
1361 * Utility function to map the output buffer in an IRP. The buffer is assumed
1362 * to have been passed down using METHOD_OUT_DIRECT (Direct I/O).
1363 * --------------------------------------------------------------------------
1366 MapIrpOutputBuffer(PIRP irp,
1367 UINT32 bufferLength,
1368 UINT32 requiredLength,
1373 ASSERT(bufferLength);
1374 ASSERT(requiredLength);
1375 if (!buffer || !irp || bufferLength == 0 || requiredLength == 0) {
1376 return STATUS_INVALID_PARAMETER;
1379 if (bufferLength < requiredLength) {
1380 return STATUS_NDIS_INVALID_LENGTH;
1382 if (irp->MdlAddress == NULL) {
1383 return STATUS_INVALID_PARAMETER;
1385 *buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress,
1386 NormalPagePriority);
1387 if (*buffer == NULL) {
1388 return STATUS_INSUFFICIENT_RESOURCES;
1391 return STATUS_SUCCESS;
1395 * --------------------------------------------------------------------------
1396 * Utility function to fill up information about the state of a port in a reply
1398 * Assumes that 'gOvsCtrlLock' lock is acquired.
1399 * --------------------------------------------------------------------------
1402 OvsPortFillInfo(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1403 POVS_EVENT_ENTRY eventEntry,
1408 OVS_MESSAGE msgOutTmp;
1410 POVS_VPORT_ENTRY vport;
1412 ASSERT(NlBufAt(nlBuf, 0, 0) != 0 && nlBuf->bufRemLen >= sizeof msgOutTmp);
1414 msgOutTmp.nlMsg.nlmsgType = OVS_WIN_NL_VPORT_FAMILY_ID;
1415 msgOutTmp.nlMsg.nlmsgFlags = 0; /* XXX: ? */
1417 /* driver intiated messages should have zerp seq number*/
1418 msgOutTmp.nlMsg.nlmsgSeq = 0;
1419 msgOutTmp.nlMsg.nlmsgPid = usrParamsCtx->ovsInstance->pid;
1421 msgOutTmp.genlMsg.version = nlVportFamilyOps.version;
1422 msgOutTmp.genlMsg.reserved = 0;
1424 /* we don't have netdev yet, treat link up/down a adding/removing a port*/
1425 if (eventEntry->status & (OVS_EVENT_LINK_UP | OVS_EVENT_CONNECT)) {
1426 msgOutTmp.genlMsg.cmd = OVS_VPORT_CMD_NEW;
1427 } else if (eventEntry->status &
1428 (OVS_EVENT_LINK_DOWN | OVS_EVENT_DISCONNECT)) {
1429 msgOutTmp.genlMsg.cmd = OVS_VPORT_CMD_DEL;
1432 return STATUS_UNSUCCESSFUL;
1434 msgOutTmp.ovsHdr.dp_ifindex = gOvsSwitchContext->dpNo;
1436 rc = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
1438 status = STATUS_INVALID_BUFFER_SIZE;
1442 vport = OvsFindVportByPortNo(gOvsSwitchContext, eventEntry->portNo);
1444 status = STATUS_DEVICE_DOES_NOT_EXIST;
1448 rc = NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_PORT_NO, eventEntry->portNo) ||
1449 NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_TYPE, vport->ovsType) ||
1450 NlMsgPutTailString(nlBuf, OVS_VPORT_ATTR_NAME, vport->ovsName);
1452 status = STATUS_INVALID_BUFFER_SIZE;
1456 /* XXXX Should we add the port stats attributes?*/
1457 nlMsg = (PNL_MSG_HDR)NlBufAt(nlBuf, 0, 0);
1458 nlMsg->nlmsgLen = NlBufSize(nlBuf);
1459 status = STATUS_SUCCESS;
1467 * --------------------------------------------------------------------------
1468 * Handler for reading events from the driver event queue. This handler is
1469 * executed when user modes issues a socket receive on a socket assocaited
1470 * with the MC group for events.
1471 * XXX user mode should read multiple events in one system call
1472 * --------------------------------------------------------------------------
1475 OvsReadEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1479 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1480 POVS_OPEN_INSTANCE instance =
1481 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1485 OVS_EVENT_ENTRY eventEntry;
1487 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1489 /* Should never read events with a dump socket */
1490 ASSERT(instance->dumpState.ovsMsg == NULL);
1492 /* Must have an event queue */
1493 ASSERT(instance->eventQueue != NULL);
1495 /* Output buffer has been validated while validating read dev op. */
1496 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1498 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
1500 OvsAcquireCtrlLock();
1502 /* remove an event entry from the event queue */
1503 status = OvsRemoveEventEntry(usrParamsCtx->ovsInstance, &eventEntry);
1504 if (status != STATUS_SUCCESS) {
1505 /* If there were not elements, read should return no data. */
1506 status = STATUS_SUCCESS;
1511 status = OvsPortFillInfo(usrParamsCtx, &eventEntry, &nlBuf);
1512 if (status == NDIS_STATUS_SUCCESS) {
1513 *replyLen = NlBufSize(&nlBuf);
1517 OvsReleaseCtrlLock();
1522 * --------------------------------------------------------------------------
1523 * Handler for reading missed pacckets from the driver event queue. This
1524 * handler is executed when user modes issues a socket receive on a socket
1525 * --------------------------------------------------------------------------
1528 OvsReadPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1532 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1534 POVS_OPEN_INSTANCE instance =
1535 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1538 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1540 /* Should never read events with a dump socket */
1541 ASSERT(instance->dumpState.ovsMsg == NULL);
1543 /* Must have an packet queue */
1544 ASSERT(instance->packetQueue != NULL);
1546 /* Output buffer has been validated while validating read dev op. */
1547 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1549 /* Read a packet from the instance queue */
1550 status = OvsReadDpIoctl(instance->fileObject, usrParamsCtx->outputBuffer,
1551 usrParamsCtx->outputLength, replyLen);
1556 * --------------------------------------------------------------------------
1557 * Handler for the subscription for a packet queue
1558 * --------------------------------------------------------------------------
1561 OvsSubscribePacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1568 const NL_POLICY policy[] = {
1569 [OVS_NL_ATTR_PACKET_PID] = {.type = NL_A_U32 },
1570 [OVS_NL_ATTR_PACKET_SUBSCRIBE] = {.type = NL_A_U8 }
1572 PNL_ATTR attrs[ARRAY_SIZE(policy)];
1574 UNREFERENCED_PARAMETER(replyLen);
1576 POVS_OPEN_INSTANCE instance =
1577 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1578 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1580 rc = NlAttrParse(&msgIn->nlMsg, sizeof (*msgIn),
1581 NlMsgAttrsLen((PNL_MSG_HDR)msgIn), policy, attrs, ARRAY_SIZE(attrs));
1583 status = STATUS_INVALID_PARAMETER;
1587 join = NlAttrGetU8(attrs[OVS_NL_ATTR_PACKET_PID]);
1588 pid = NlAttrGetU32(attrs[OVS_NL_ATTR_PACKET_PID]);
1590 /* The socket subscribed with must be the same socket we perform receive*/
1591 ASSERT(pid == instance->pid);
1593 status = OvsSubscribeDpIoctl(instance, pid, join);
1596 * XXX Need to add this instance to a global data structure
1597 * which hold all packet based instances. The data structure (hash)
1598 * should be searched through the pid field of the instance for
1599 * placing the missed packet into the correct queue
1606 * --------------------------------------------------------------------------
1607 * Handler for queueing an IRP used for missed packet notification. The IRP is
1608 * completed when a packet received and mismatched. STATUS_PENDING is returned
1609 * on success. User mode keep a pending IRP at all times.
1610 * --------------------------------------------------------------------------
1613 OvsPendPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1616 UNREFERENCED_PARAMETER(replyLen);
1618 POVS_OPEN_INSTANCE instance =
1619 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1622 * XXX access to packet queue must be through acquiring a lock as user mode
1623 * could unsubscribe and the instnace will be freed.
1625 return OvsWaitDpIoctl(usrParamsCtx->irp, instance->fileObject);