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 {
87 NETLINK_CMD *cmds; /* Array of netlink commands and handlers. */
89 } NETLINK_FAMILY, *PNETLINK_FAMILY;
91 /* Handlers for the various netlink commands. */
92 static NetlinkCmdHandler OvsPendEventCmdHandler,
93 OvsSubscribeEventCmdHandler,
94 OvsReadEventCmdHandler,
99 NetlinkCmdHandler OvsGetNetdevCmdHandler,
100 OvsGetVportCmdHandler,
101 OvsSetVportCmdHandler,
102 OvsNewVportCmdHandler,
103 OvsDeleteVportCmdHandler,
104 OvsPendPacketCmdHandler,
105 OvsSubscribePacketCmdHandler,
106 OvsReadPacketCmdHandler;
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);
114 static NTSTATUS OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
118 * The various netlink families, along with the supported commands. Most of
119 * these families and commands are part of the openvswitch specification for a
120 * netlink datapath. In addition, each platform can implement a few families
121 * and commands as extensions.
124 /* Netlink control family: this is a Windows specific family. */
125 NETLINK_CMD nlControlFamilyCmdOps[] = {
126 { .cmd = OVS_CTRL_CMD_WIN_PEND_REQ,
127 .handler = OvsPendEventCmdHandler,
128 .supportedDevOp = OVS_WRITE_DEV_OP,
129 .validateDpIndex = TRUE,
131 { .cmd = OVS_CTRL_CMD_WIN_PEND_PACKET_REQ,
132 .handler = OvsPendPacketCmdHandler,
133 .supportedDevOp = OVS_WRITE_DEV_OP,
134 .validateDpIndex = TRUE,
136 { .cmd = OVS_CTRL_CMD_MC_SUBSCRIBE_REQ,
137 .handler = OvsSubscribeEventCmdHandler,
138 .supportedDevOp = OVS_WRITE_DEV_OP,
139 .validateDpIndex = TRUE,
141 { .cmd = OVS_CTRL_CMD_PACKET_SUBSCRIBE_REQ,
142 .handler = OvsSubscribePacketCmdHandler,
143 .supportedDevOp = OVS_WRITE_DEV_OP,
144 .validateDpIndex = TRUE,
146 { .cmd = OVS_CTRL_CMD_EVENT_NOTIFY,
147 .handler = OvsReadEventCmdHandler,
148 .supportedDevOp = OVS_READ_DEV_OP,
149 .validateDpIndex = FALSE,
151 { .cmd = OVS_CTRL_CMD_READ_NOTIFY,
152 .handler = OvsReadPacketCmdHandler,
153 .supportedDevOp = OVS_READ_DEV_OP,
154 .validateDpIndex = FALSE,
158 NETLINK_FAMILY nlControlFamilyOps = {
159 .name = OVS_WIN_CONTROL_FAMILY,
160 .id = OVS_WIN_NL_CTRL_FAMILY_ID,
161 .version = OVS_WIN_CONTROL_VERSION,
162 .maxAttr = OVS_WIN_CONTROL_ATTR_MAX,
163 .cmds = nlControlFamilyCmdOps,
164 .opsCount = ARRAY_SIZE(nlControlFamilyCmdOps)
167 /* Netlink datapath family. */
168 NETLINK_CMD nlDatapathFamilyCmdOps[] = {
169 { .cmd = OVS_DP_CMD_NEW,
170 .handler = OvsNewDpCmdHandler,
171 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
172 .validateDpIndex = FALSE
174 { .cmd = OVS_DP_CMD_GET,
175 .handler = OvsGetDpCmdHandler,
176 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
177 OVS_TRANSACTION_DEV_OP,
178 .validateDpIndex = FALSE
180 { .cmd = OVS_DP_CMD_SET,
181 .handler = OvsSetDpCmdHandler,
182 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
183 OVS_TRANSACTION_DEV_OP,
184 .validateDpIndex = TRUE
188 NETLINK_FAMILY nlDatapathFamilyOps = {
189 .name = OVS_DATAPATH_FAMILY,
190 .id = OVS_WIN_NL_DATAPATH_FAMILY_ID,
191 .version = OVS_DATAPATH_VERSION,
192 .maxAttr = OVS_DP_ATTR_MAX,
193 .cmds = nlDatapathFamilyCmdOps,
194 .opsCount = ARRAY_SIZE(nlDatapathFamilyCmdOps)
197 /* Netlink packet family. */
199 NETLINK_CMD nlPacketFamilyCmdOps[] = {
200 { .cmd = OVS_PACKET_CMD_EXECUTE,
201 .handler = OvsNlExecuteCmdHandler,
202 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
203 .validateDpIndex = TRUE
207 NETLINK_FAMILY nlPacketFamilyOps = {
208 .name = OVS_PACKET_FAMILY,
209 .id = OVS_WIN_NL_PACKET_FAMILY_ID,
210 .version = OVS_PACKET_VERSION,
211 .maxAttr = OVS_PACKET_ATTR_MAX,
212 .cmds = nlPacketFamilyCmdOps,
213 .opsCount = ARRAY_SIZE(nlPacketFamilyCmdOps)
216 /* Netlink vport family. */
217 NETLINK_CMD nlVportFamilyCmdOps[] = {
218 { .cmd = OVS_VPORT_CMD_GET,
219 .handler = OvsGetVportCmdHandler,
220 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP |
221 OVS_TRANSACTION_DEV_OP,
222 .validateDpIndex = TRUE
224 { .cmd = OVS_VPORT_CMD_NEW,
225 .handler = OvsNewVportCmdHandler,
226 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
227 .validateDpIndex = TRUE
229 { .cmd = OVS_VPORT_CMD_SET,
230 .handler = OvsSetVportCmdHandler,
231 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
232 .validateDpIndex = TRUE
234 { .cmd = OVS_VPORT_CMD_DEL,
235 .handler = OvsDeleteVportCmdHandler,
236 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
237 .validateDpIndex = TRUE
241 NETLINK_FAMILY nlVportFamilyOps = {
242 .name = OVS_VPORT_FAMILY,
243 .id = OVS_WIN_NL_VPORT_FAMILY_ID,
244 .version = OVS_VPORT_VERSION,
245 .maxAttr = OVS_VPORT_ATTR_MAX,
246 .cmds = nlVportFamilyCmdOps,
247 .opsCount = ARRAY_SIZE(nlVportFamilyCmdOps)
250 /* Netlink flow family. */
252 NETLINK_CMD nlFlowFamilyCmdOps[] = {
253 { .cmd = OVS_FLOW_CMD_NEW,
254 .handler = OvsFlowNlCmdHandler,
255 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
256 .validateDpIndex = TRUE
258 { .cmd = OVS_FLOW_CMD_SET,
259 .handler = OvsFlowNlCmdHandler,
260 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
261 .validateDpIndex = TRUE
263 { .cmd = OVS_FLOW_CMD_DEL,
264 .handler = OvsFlowNlCmdHandler,
265 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
266 .validateDpIndex = TRUE
268 { .cmd = OVS_FLOW_CMD_GET,
269 .handler = OvsFlowNlGetCmdHandler,
270 .supportedDevOp = OVS_TRANSACTION_DEV_OP |
271 OVS_WRITE_DEV_OP | OVS_READ_DEV_OP,
272 .validateDpIndex = TRUE
276 NETLINK_FAMILY nlFLowFamilyOps = {
277 .name = OVS_FLOW_FAMILY,
278 .id = OVS_WIN_NL_FLOW_FAMILY_ID,
279 .version = OVS_FLOW_VERSION,
280 .maxAttr = OVS_FLOW_ATTR_MAX,
281 .cmds = nlFlowFamilyCmdOps,
282 .opsCount = ARRAY_SIZE(nlFlowFamilyCmdOps)
285 /* Netlink netdev family. */
286 NETLINK_CMD nlNetdevFamilyCmdOps[] = {
287 { .cmd = OVS_WIN_NETDEV_CMD_GET,
288 .handler = OvsGetNetdevCmdHandler,
289 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
290 .validateDpIndex = FALSE
294 NETLINK_FAMILY nlNetdevFamilyOps = {
295 .name = OVS_WIN_NETDEV_FAMILY,
296 .id = OVS_WIN_NL_NETDEV_FAMILY_ID,
297 .version = OVS_WIN_NETDEV_VERSION,
298 .maxAttr = OVS_WIN_NETDEV_ATTR_MAX,
299 .cmds = nlNetdevFamilyCmdOps,
300 .opsCount = ARRAY_SIZE(nlNetdevFamilyCmdOps)
303 static NTSTATUS MapIrpOutputBuffer(PIRP irp,
305 UINT32 requiredLength,
307 static NTSTATUS ValidateNetlinkCmd(UINT32 devOp,
308 POVS_OPEN_INSTANCE instance,
311 NETLINK_FAMILY *nlFamilyOps);
312 static NTSTATUS InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
313 NETLINK_FAMILY *nlFamilyOps,
316 /* Handles to the device object for communication with userspace. */
317 NDIS_HANDLE gOvsDeviceHandle;
318 PDEVICE_OBJECT gOvsDeviceObject;
320 _Dispatch_type_(IRP_MJ_CREATE)
321 _Dispatch_type_(IRP_MJ_CLOSE)
322 DRIVER_DISPATCH OvsOpenCloseDevice;
324 _Dispatch_type_(IRP_MJ_CLEANUP)
325 DRIVER_DISPATCH OvsCleanupDevice;
327 _Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
328 DRIVER_DISPATCH OvsDeviceControl;
331 #pragma alloc_text(INIT, OvsCreateDeviceObject)
332 #pragma alloc_text(PAGE, OvsOpenCloseDevice)
333 #pragma alloc_text(PAGE, OvsCleanupDevice)
334 #pragma alloc_text(PAGE, OvsDeviceControl)
335 #endif // ALLOC_PRAGMA
338 * We might hit this limit easily since userspace opens a netlink descriptor for
339 * each thread, and at least one descriptor per vport. Revisit this later.
341 #define OVS_MAX_OPEN_INSTANCES 512
342 #define OVS_SYSTEM_DP_NAME "ovs-system"
344 POVS_OPEN_INSTANCE ovsOpenInstanceArray[OVS_MAX_OPEN_INSTANCES];
345 UINT32 ovsNumberOfOpenInstances;
346 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
348 NDIS_SPIN_LOCK ovsCtrlLockObj;
349 PNDIS_SPIN_LOCK gOvsCtrlLock;
352 InitUserDumpState(POVS_OPEN_INSTANCE instance,
355 /* Clear the dumpState from a previous dump sequence. */
356 ASSERT(instance->dumpState.ovsMsg == NULL);
359 instance->dumpState.ovsMsg =
360 (POVS_MESSAGE)OvsAllocateMemoryWithTag(sizeof(OVS_MESSAGE),
361 OVS_DATAPATH_POOL_TAG);
362 if (instance->dumpState.ovsMsg == NULL) {
363 return STATUS_NO_MEMORY;
365 RtlCopyMemory(instance->dumpState.ovsMsg, ovsMsg,
366 sizeof *instance->dumpState.ovsMsg);
367 RtlZeroMemory(instance->dumpState.index,
368 sizeof instance->dumpState.index);
370 return STATUS_SUCCESS;
374 FreeUserDumpState(POVS_OPEN_INSTANCE instance)
376 if (instance->dumpState.ovsMsg != NULL) {
377 OvsFreeMemoryWithTag(instance->dumpState.ovsMsg,
378 OVS_DATAPATH_POOL_TAG);
379 RtlZeroMemory(&instance->dumpState, sizeof instance->dumpState);
386 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
388 gOvsCtrlLock = &ovsCtrlLockObj;
389 NdisAllocateSpinLock(gOvsCtrlLock);
392 status = OvsPerCpuDataInit();
400 OvsPerCpuDataCleanup();
401 OvsCleanupEventQueue();
403 NdisFreeSpinLock(gOvsCtrlLock);
411 NdisAcquireSpinLock(gOvsCtrlLock);
417 NdisReleaseSpinLock(gOvsCtrlLock);
422 * --------------------------------------------------------------------------
423 * Creates the communication device between user and kernel, and also
424 * initializes the data associated data structures.
425 * --------------------------------------------------------------------------
428 OvsCreateDeviceObject(NDIS_HANDLE ovsExtDriverHandle)
430 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
431 UNICODE_STRING deviceName;
432 UNICODE_STRING symbolicDeviceName;
433 PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
434 NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttributes;
435 OVS_LOG_TRACE("ovsExtDriverHandle: %p", ovsExtDriverHandle);
437 RtlZeroMemory(dispatchTable,
438 (IRP_MJ_MAXIMUM_FUNCTION + 1) * sizeof (PDRIVER_DISPATCH));
439 dispatchTable[IRP_MJ_CREATE] = OvsOpenCloseDevice;
440 dispatchTable[IRP_MJ_CLOSE] = OvsOpenCloseDevice;
441 dispatchTable[IRP_MJ_CLEANUP] = OvsCleanupDevice;
442 dispatchTable[IRP_MJ_DEVICE_CONTROL] = OvsDeviceControl;
444 NdisInitUnicodeString(&deviceName, OVS_DEVICE_NAME_NT);
445 NdisInitUnicodeString(&symbolicDeviceName, OVS_DEVICE_NAME_DOS);
447 RtlZeroMemory(&deviceAttributes, sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
449 OVS_INIT_OBJECT_HEADER(&deviceAttributes.Header,
450 NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES,
451 NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1,
452 sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
454 deviceAttributes.DeviceName = &deviceName;
455 deviceAttributes.SymbolicName = &symbolicDeviceName;
456 deviceAttributes.MajorFunctions = dispatchTable;
457 deviceAttributes.ExtensionSize = sizeof (OVS_DEVICE_EXTENSION);
459 status = NdisRegisterDeviceEx(ovsExtDriverHandle,
463 if (status == NDIS_STATUS_SUCCESS) {
464 OvsRegisterSystemProvider((PVOID)gOvsDeviceObject);
466 OVS_LOG_ERROR("Failed to regiser pseudo device, error: 0x%08x",
470 OVS_LOG_TRACE("DeviceObject: %p", gOvsDeviceObject);
476 OvsDeleteDeviceObject()
478 if (gOvsDeviceHandle) {
480 POVS_DEVICE_EXTENSION ovsExt = (POVS_DEVICE_EXTENSION)
481 NdisGetDeviceReservedExtension(gOvsDeviceObject);
483 ASSERT(ovsExt->numberOpenInstance == 0);
487 ASSERT(gOvsDeviceObject);
488 NdisDeregisterDeviceEx(gOvsDeviceHandle);
489 gOvsDeviceHandle = NULL;
490 gOvsDeviceObject = NULL;
492 OvsUnregisterSystemProvider();
497 OvsGetOpenInstance(PFILE_OBJECT fileObject,
500 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
502 ASSERT(instance->fileObject == fileObject);
503 if (gOvsSwitchContext->dpNo != dpNo) {
511 OvsFindOpenInstance(PFILE_OBJECT fileObject)
514 for (i = 0, j = 0; i < OVS_MAX_OPEN_INSTANCES &&
515 j < ovsNumberOfOpenInstances; i++) {
516 if (ovsOpenInstanceArray[i]) {
517 if (ovsOpenInstanceArray[i]->fileObject == fileObject) {
518 return ovsOpenInstanceArray[i];
527 OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt,
528 PFILE_OBJECT fileObject)
530 POVS_OPEN_INSTANCE instance =
531 (POVS_OPEN_INSTANCE)OvsAllocateMemoryWithTag(sizeof(OVS_OPEN_INSTANCE),
532 OVS_DATAPATH_POOL_TAG);
535 if (instance == NULL) {
536 return STATUS_NO_MEMORY;
538 OvsAcquireCtrlLock();
539 ASSERT(OvsFindOpenInstance(fileObject) == NULL);
541 if (ovsNumberOfOpenInstances >= OVS_MAX_OPEN_INSTANCES) {
542 OvsReleaseCtrlLock();
543 OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG);
544 return STATUS_INSUFFICIENT_RESOURCES;
546 RtlZeroMemory(instance, sizeof (OVS_OPEN_INSTANCE));
548 for (i = 0; i < OVS_MAX_OPEN_INSTANCES; i++) {
549 if (ovsOpenInstanceArray[i] == NULL) {
550 ovsOpenInstanceArray[i] = instance;
551 ovsNumberOfOpenInstances++;
552 instance->cookie = i;
556 ASSERT(i < OVS_MAX_OPEN_INSTANCES);
557 instance->fileObject = fileObject;
558 ASSERT(fileObject->FsContext == NULL);
559 instance->pid = (UINT32)InterlockedIncrement((LONG volatile *)&ovsExt->pidCount);
560 if (instance->pid == 0) {
561 /* XXX: check for rollover. */
563 fileObject->FsContext = instance;
564 OvsReleaseCtrlLock();
565 return STATUS_SUCCESS;
569 OvsCleanupOpenInstance(PFILE_OBJECT fileObject)
571 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
573 ASSERT(fileObject == instance->fileObject);
574 OvsCleanupEvent(instance);
575 OvsCleanupPacketQueue(instance);
579 OvsRemoveOpenInstance(PFILE_OBJECT fileObject)
581 POVS_OPEN_INSTANCE instance;
582 ASSERT(fileObject->FsContext);
583 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
584 ASSERT(instance->cookie < OVS_MAX_OPEN_INSTANCES);
586 OvsAcquireCtrlLock();
587 fileObject->FsContext = NULL;
588 ASSERT(ovsOpenInstanceArray[instance->cookie] == instance);
589 ovsOpenInstanceArray[instance->cookie] = NULL;
590 ovsNumberOfOpenInstances--;
591 OvsReleaseCtrlLock();
592 ASSERT(instance->eventQueue == NULL);
593 ASSERT (instance->packetQueue == NULL);
594 FreeUserDumpState(instance);
595 OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG);
599 OvsCompleteIrpRequest(PIRP irp,
603 irp->IoStatus.Information = infoPtr;
604 irp->IoStatus.Status = status;
605 IoCompleteRequest(irp, IO_NO_INCREMENT);
611 OvsOpenCloseDevice(PDEVICE_OBJECT deviceObject,
614 PIO_STACK_LOCATION irpSp;
615 NTSTATUS status = STATUS_SUCCESS;
616 PFILE_OBJECT fileObject;
617 POVS_DEVICE_EXTENSION ovsExt =
618 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
621 ASSERT(deviceObject == gOvsDeviceObject);
622 ASSERT(ovsExt != NULL);
624 irpSp = IoGetCurrentIrpStackLocation(irp);
625 fileObject = irpSp->FileObject;
626 OVS_LOG_TRACE("DeviceObject: %p, fileObject:%p, instance: %u",
627 deviceObject, fileObject,
628 ovsExt->numberOpenInstance);
630 switch (irpSp->MajorFunction) {
632 status = OvsAddOpenInstance(ovsExt, fileObject);
633 if (STATUS_SUCCESS == status) {
634 InterlockedIncrement((LONG volatile *)&ovsExt->numberOpenInstance);
638 ASSERT(ovsExt->numberOpenInstance > 0);
639 OvsRemoveOpenInstance(fileObject);
640 InterlockedDecrement((LONG volatile *)&ovsExt->numberOpenInstance);
645 return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
648 _Use_decl_annotations_
650 OvsCleanupDevice(PDEVICE_OBJECT deviceObject,
654 PIO_STACK_LOCATION irpSp;
655 PFILE_OBJECT fileObject;
657 NTSTATUS status = STATUS_SUCCESS;
659 POVS_DEVICE_EXTENSION ovsExt =
660 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
662 ASSERT(ovsExt->numberOpenInstance > 0);
665 UNREFERENCED_PARAMETER(deviceObject);
667 ASSERT(deviceObject == gOvsDeviceObject);
668 irpSp = IoGetCurrentIrpStackLocation(irp);
669 fileObject = irpSp->FileObject;
671 ASSERT(irpSp->MajorFunction == IRP_MJ_CLEANUP);
673 OvsCleanupOpenInstance(fileObject);
675 return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
679 * --------------------------------------------------------------------------
680 * IOCTL function handler for the device.
681 * --------------------------------------------------------------------------
684 OvsDeviceControl(PDEVICE_OBJECT deviceObject,
687 PIO_STACK_LOCATION irpSp;
688 NTSTATUS status = STATUS_SUCCESS;
689 PFILE_OBJECT fileObject;
690 PVOID inputBuffer = NULL;
691 PVOID outputBuffer = NULL;
692 UINT32 inputBufferLen, outputBufferLen;
693 UINT32 code, replyLen = 0;
694 POVS_OPEN_INSTANCE instance;
696 OVS_MESSAGE ovsMsgReadOp;
698 UINT32 ovsMsgLength = 0;
699 NETLINK_FAMILY *nlFamilyOps;
700 OVS_USER_PARAMS_CONTEXT usrParamsCtx;
704 POVS_DEVICE_EXTENSION ovsExt =
705 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
706 ASSERT(deviceObject == gOvsDeviceObject);
708 ASSERT(ovsExt->numberOpenInstance > 0);
710 UNREFERENCED_PARAMETER(deviceObject);
713 irpSp = IoGetCurrentIrpStackLocation(irp);
715 ASSERT(irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
716 ASSERT(irpSp->FileObject != NULL);
718 fileObject = irpSp->FileObject;
719 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
720 code = irpSp->Parameters.DeviceIoControl.IoControlCode;
721 inputBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
722 outputBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
723 inputBuffer = irp->AssociatedIrp.SystemBuffer;
725 /* Check if the extension is enabled. */
726 if (NULL == gOvsSwitchContext) {
727 status = STATUS_NOT_FOUND;
731 if (!OvsAcquireSwitchContext()) {
732 status = STATUS_NOT_FOUND;
737 * Validate the input/output buffer arguments depending on the type of the
741 case OVS_IOCTL_GET_PID:
742 /* Both input buffer and output buffer use the same location. */
743 outputBuffer = irp->AssociatedIrp.SystemBuffer;
744 if (outputBufferLen != 0) {
745 InitUserParamsCtx(irp, instance, 0, NULL,
746 inputBuffer, inputBufferLen,
747 outputBuffer, outputBufferLen,
750 ASSERT(outputBuffer);
752 status = STATUS_NDIS_INVALID_LENGTH;
756 status = OvsGetPidHandler(&usrParamsCtx, &replyLen);
759 case OVS_IOCTL_TRANSACT:
760 /* Both input buffer and output buffer are mandatory. */
761 if (outputBufferLen != 0) {
762 status = MapIrpOutputBuffer(irp, outputBufferLen,
763 sizeof *ovsMsg, &outputBuffer);
764 if (status != STATUS_SUCCESS) {
767 ASSERT(outputBuffer);
769 status = STATUS_NDIS_INVALID_LENGTH;
773 if (inputBufferLen < sizeof (*ovsMsg)) {
774 status = STATUS_NDIS_INVALID_LENGTH;
778 ovsMsg = inputBuffer;
779 ovsMsgLength = inputBufferLen;
780 devOp = OVS_TRANSACTION_DEV_OP;
783 case OVS_IOCTL_READ_EVENT:
784 case OVS_IOCTL_READ_PACKET:
786 * Output buffer is mandatory. These IOCTLs are used to read events and
787 * packets respectively. It is convenient to have separate ioctls.
789 if (outputBufferLen != 0) {
790 status = MapIrpOutputBuffer(irp, outputBufferLen,
791 sizeof *ovsMsg, &outputBuffer);
792 if (status != STATUS_SUCCESS) {
795 ASSERT(outputBuffer);
797 status = STATUS_NDIS_INVALID_LENGTH;
803 ovsMsg = &ovsMsgReadOp;
804 RtlZeroMemory(ovsMsg, sizeof *ovsMsg);
805 ovsMsg->nlMsg.nlmsgLen = sizeof *ovsMsg;
806 ovsMsg->nlMsg.nlmsgType = nlControlFamilyOps.id;
807 ovsMsg->nlMsg.nlmsgPid = instance->pid;
809 /* An "artificial" command so we can use NL family function table*/
810 ovsMsg->genlMsg.cmd = (code == OVS_IOCTL_READ_EVENT) ?
811 OVS_CTRL_CMD_EVENT_NOTIFY :
812 OVS_CTRL_CMD_READ_NOTIFY;
813 ovsMsg->genlMsg.version = nlControlFamilyOps.version;
814 ovsMsgLength = outputBufferLen;
816 devOp = OVS_READ_DEV_OP;
820 /* Output buffer is mandatory. */
821 if (outputBufferLen != 0) {
822 status = MapIrpOutputBuffer(irp, outputBufferLen,
823 sizeof *ovsMsg, &outputBuffer);
824 if (status != STATUS_SUCCESS) {
827 ASSERT(outputBuffer);
829 status = STATUS_NDIS_INVALID_LENGTH;
834 * Operate in the mode that read ioctl is similar to ReadFile(). This
835 * might change as the userspace code gets implemented.
841 * For implementing read (ioctl or otherwise), we need to store some
842 * state in the instance to indicate the command that started the dump
843 * operation. The state can setup 'ovsMsgReadOp' appropriately. Note
844 * that 'ovsMsgReadOp' is needed only in this function to call into the
845 * appropriate handler. The handler itself can access the state in the
848 * In the absence of a dump start, return 0 bytes.
850 if (instance->dumpState.ovsMsg == NULL) {
852 status = STATUS_SUCCESS;
855 RtlCopyMemory(&ovsMsgReadOp, instance->dumpState.ovsMsg,
856 sizeof (ovsMsgReadOp));
858 /* Create an NL message for consumption. */
859 ovsMsg = &ovsMsgReadOp;
860 ovsMsgLength = sizeof (ovsMsgReadOp);
861 devOp = OVS_READ_DEV_OP;
865 case OVS_IOCTL_WRITE:
866 /* Input buffer is mandatory. */
867 if (inputBufferLen < sizeof (*ovsMsg)) {
868 status = STATUS_NDIS_INVALID_LENGTH;
873 * Output buffer not mandatory but map it in case we have something
874 * to return to requester.
876 if (outputBufferLen != 0) {
877 status = MapIrpOutputBuffer(irp, outputBufferLen,
878 sizeof *ovsMsg, &outputBuffer);
879 if (status != STATUS_SUCCESS) {
882 ASSERT(outputBuffer);
885 ovsMsg = inputBuffer;
886 ovsMsgLength = inputBufferLen;
887 devOp = OVS_WRITE_DEV_OP;
891 status = STATUS_INVALID_DEVICE_REQUEST;
896 switch (ovsMsg->nlMsg.nlmsgType) {
897 case OVS_WIN_NL_CTRL_FAMILY_ID:
898 nlFamilyOps = &nlControlFamilyOps;
900 case OVS_WIN_NL_DATAPATH_FAMILY_ID:
901 nlFamilyOps = &nlDatapathFamilyOps;
903 case OVS_WIN_NL_FLOW_FAMILY_ID:
904 nlFamilyOps = &nlFLowFamilyOps;
906 case OVS_WIN_NL_PACKET_FAMILY_ID:
907 nlFamilyOps = &nlPacketFamilyOps;
909 case OVS_WIN_NL_VPORT_FAMILY_ID:
910 nlFamilyOps = &nlVportFamilyOps;
912 case OVS_WIN_NL_NETDEV_FAMILY_ID:
913 nlFamilyOps = &nlNetdevFamilyOps;
916 status = STATUS_INVALID_PARAMETER;
921 * For read operation, avoid duplicate validation since 'ovsMsg' is either
922 * "artificial" or was copied from a previously validated 'ovsMsg'.
924 if (devOp != OVS_READ_DEV_OP) {
925 status = ValidateNetlinkCmd(devOp, instance, ovsMsg,
926 ovsMsgLength, nlFamilyOps);
927 if (status != STATUS_SUCCESS) {
932 InitUserParamsCtx(irp, instance, devOp, ovsMsg,
933 inputBuffer, inputBufferLen,
934 outputBuffer, outputBufferLen,
937 status = InvokeNetlinkCmdHandler(&usrParamsCtx, nlFamilyOps, &replyLen);
940 OvsReleaseSwitchContext(gOvsSwitchContext);
943 /* Should not complete a pending IRP unless proceesing is completed. */
944 if (status == STATUS_PENDING) {
947 return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status);
952 * --------------------------------------------------------------------------
953 * Function to validate a netlink command. Only certain combinations of
954 * (device operation, netlink family, command) are valid.
955 * --------------------------------------------------------------------------
958 ValidateNetlinkCmd(UINT32 devOp,
959 POVS_OPEN_INSTANCE instance,
962 NETLINK_FAMILY *nlFamilyOps)
964 NTSTATUS status = STATUS_INVALID_PARAMETER;
967 // We need to ensure we have enough data to process
968 if (NlMsgSize(&ovsMsg->nlMsg) > ovsMsgLength) {
969 status = STATUS_INVALID_PARAMETER;
973 for (i = 0; i < nlFamilyOps->opsCount; i++) {
974 if (nlFamilyOps->cmds[i].cmd == ovsMsg->genlMsg.cmd) {
975 /* Validate if the command is valid for the device operation. */
976 if ((devOp & nlFamilyOps->cmds[i].supportedDevOp) == 0) {
977 status = STATUS_INVALID_PARAMETER;
981 /* Validate the version. */
982 if (nlFamilyOps->version > ovsMsg->genlMsg.version) {
983 status = STATUS_INVALID_PARAMETER;
987 /* Validate the DP for commands that require a DP. */
988 if (nlFamilyOps->cmds[i].validateDpIndex == TRUE) {
989 if (ovsMsg->ovsHdr.dp_ifindex !=
990 (INT)gOvsSwitchContext->dpNo) {
991 status = STATUS_INVALID_PARAMETER;
996 /* Validate the PID. */
997 if (ovsMsg->nlMsg.nlmsgPid != instance->pid) {
998 status = STATUS_INVALID_PARAMETER;
1002 status = STATUS_SUCCESS;
1007 // validate all NlAttrs
1008 if (!NlValidateAllAttrs(&ovsMsg->nlMsg, sizeof(*ovsMsg),
1009 NlMsgAttrsLen((PNL_MSG_HDR)ovsMsg),
1011 status = STATUS_INVALID_PARAMETER;
1020 * --------------------------------------------------------------------------
1021 * Function to invoke the netlink command handler. The function also stores
1022 * the return value of the handler function to construct a 'NL_ERROR' message,
1023 * and in turn returns success to the caller.
1024 * --------------------------------------------------------------------------
1027 InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1028 NETLINK_FAMILY *nlFamilyOps,
1031 NTSTATUS status = STATUS_INVALID_PARAMETER;
1034 for (i = 0; i < nlFamilyOps->opsCount; i++) {
1035 if (nlFamilyOps->cmds[i].cmd == usrParamsCtx->ovsMsg->genlMsg.cmd) {
1036 NetlinkCmdHandler *handler = nlFamilyOps->cmds[i].handler;
1039 status = handler(usrParamsCtx, replyLen);
1046 * Netlink socket semantics dictate that the return value of the netlink
1047 * function should be an error ONLY under fatal conditions. If the message
1048 * made it all the way to the handler function, it is not a fatal condition.
1049 * Absorb the error returned by the handler function into a 'struct
1050 * NL_ERROR' and populate the 'output buffer' to return to userspace.
1052 * This behavior is obviously applicable only to netlink commands that
1053 * specify an 'output buffer'. For other commands, we return the error as
1056 * 'STATUS_PENDING' is a special return value and userspace is equipped to
1059 if (status != STATUS_SUCCESS && status != STATUS_PENDING) {
1060 if (usrParamsCtx->devOp != OVS_WRITE_DEV_OP && *replyLen == 0) {
1061 NL_ERROR nlError = NlMapStatusToNlErr(status);
1062 OVS_MESSAGE msgInTmp = { 0 };
1063 POVS_MESSAGE msgIn = NULL;
1064 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1065 usrParamsCtx->outputBuffer;
1066 UINT32 msgErrorLen = usrParamsCtx->outputLength;
1068 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_CTRL_CMD_EVENT_NOTIFY ||
1069 usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_CTRL_CMD_READ_NOTIFY) {
1070 /* There's no input buffer associated with such requests. */
1073 NlBufInit(&nlBuffer, (PCHAR)msgIn, sizeof *msgIn);
1074 NlFillNlHdr(&nlBuffer, nlFamilyOps->id, 0, 0,
1075 usrParamsCtx->ovsInstance->pid);
1077 msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1082 NlBuildErrorMsg(msgIn, msgError, msgErrorLen, nlError, replyLen);
1085 if (*replyLen != 0) {
1086 status = STATUS_SUCCESS;
1091 if (usrParamsCtx->devOp != OVS_WRITE_DEV_OP) {
1092 ASSERT(status == STATUS_PENDING || *replyLen != 0 || status == STATUS_SUCCESS);
1100 * --------------------------------------------------------------------------
1101 * Handler for 'OVS_IOCTL_GET_PID'.
1103 * Each handle on the device is assigned a unique PID when the handle is
1104 * created. This function passes the PID to userspace using METHOD_BUFFERED
1106 * --------------------------------------------------------------------------
1109 OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1112 NTSTATUS status = STATUS_SUCCESS;
1113 PUINT32 msgOut = (PUINT32)usrParamsCtx->outputBuffer;
1115 if (usrParamsCtx->outputLength >= sizeof *msgOut) {
1116 POVS_OPEN_INSTANCE instance =
1117 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1119 RtlZeroMemory(msgOut, sizeof *msgOut);
1120 RtlCopyMemory(msgOut, &instance->pid, sizeof(*msgOut));
1121 *replyLen = sizeof *msgOut;
1123 *replyLen = sizeof *msgOut;
1124 status = STATUS_NDIS_INVALID_LENGTH;
1131 * --------------------------------------------------------------------------
1132 * Utility function to fill up information about the datapath in a reply to
1134 * --------------------------------------------------------------------------
1137 OvsDpFillInfo(POVS_SWITCH_CONTEXT ovsSwitchContext,
1142 OVS_MESSAGE msgOutTmp;
1143 OVS_DATAPATH *datapath = &ovsSwitchContext->datapath;
1146 ASSERT(NlBufAt(nlBuf, 0, 0) != 0 && NlBufRemLen(nlBuf) >= sizeof *msgIn);
1148 msgOutTmp.nlMsg.nlmsgType = OVS_WIN_NL_DATAPATH_FAMILY_ID;
1149 msgOutTmp.nlMsg.nlmsgFlags = 0; /* XXX: ? */
1150 msgOutTmp.nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
1151 msgOutTmp.nlMsg.nlmsgPid = msgIn->nlMsg.nlmsgPid;
1153 msgOutTmp.genlMsg.cmd = OVS_DP_CMD_GET;
1154 msgOutTmp.genlMsg.version = nlDatapathFamilyOps.version;
1155 msgOutTmp.genlMsg.reserved = 0;
1157 msgOutTmp.ovsHdr.dp_ifindex = ovsSwitchContext->dpNo;
1159 writeOk = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
1161 writeOk = NlMsgPutTailString(nlBuf, OVS_DP_ATTR_NAME,
1162 OVS_SYSTEM_DP_NAME);
1165 OVS_DP_STATS dpStats;
1167 dpStats.n_hit = datapath->hits;
1168 dpStats.n_missed = datapath->misses;
1169 dpStats.n_lost = datapath->lost;
1170 dpStats.n_flows = datapath->nFlows;
1171 writeOk = NlMsgPutTailUnspec(nlBuf, OVS_DP_ATTR_STATS,
1172 (PCHAR)&dpStats, sizeof dpStats);
1174 nlMsg = (PNL_MSG_HDR)NlBufAt(nlBuf, 0, 0);
1175 nlMsg->nlmsgLen = NlBufSize(nlBuf);
1177 return writeOk ? STATUS_SUCCESS : STATUS_INVALID_BUFFER_SIZE;
1181 * --------------------------------------------------------------------------
1182 * Handler for queueing an IRP used for event notification. The IRP is
1183 * completed when a port state changes. STATUS_PENDING is returned on
1184 * success. User mode keep a pending IRP at all times.
1185 * --------------------------------------------------------------------------
1188 OvsPendEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1193 UNREFERENCED_PARAMETER(replyLen);
1195 POVS_OPEN_INSTANCE instance =
1196 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1197 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1198 OVS_EVENT_POLL poll;
1200 poll.dpNo = msgIn->ovsHdr.dp_ifindex;
1201 status = OvsWaitEventIoctl(usrParamsCtx->irp, instance->fileObject,
1202 &poll, sizeof poll);
1207 * --------------------------------------------------------------------------
1208 * Handler for the subscription for the event queue
1209 * --------------------------------------------------------------------------
1212 OvsSubscribeEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1216 OVS_EVENT_SUBSCRIBE request;
1220 const NL_POLICY policy[] = {
1221 [OVS_NL_ATTR_MCAST_GRP] = {.type = NL_A_U32 },
1222 [OVS_NL_ATTR_MCAST_JOIN] = {.type = NL_A_U8 },
1225 UNREFERENCED_PARAMETER(replyLen);
1227 POVS_OPEN_INSTANCE instance =
1228 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1229 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1231 rc = NlAttrParse(&msgIn->nlMsg, sizeof (*msgIn),
1232 NlMsgAttrsLen((PNL_MSG_HDR)msgIn), policy, ARRAY_SIZE(policy),
1233 attrs, ARRAY_SIZE(attrs));
1235 status = STATUS_INVALID_PARAMETER;
1239 /* XXX Ignore the MC group for now */
1240 join = NlAttrGetU8(attrs[OVS_NL_ATTR_MCAST_JOIN]);
1241 request.dpNo = msgIn->ovsHdr.dp_ifindex;
1242 request.subscribe = join;
1243 request.mask = OVS_EVENT_MASK_ALL;
1245 status = OvsSubscribeEventIoctl(instance->fileObject, &request,
1252 * --------------------------------------------------------------------------
1253 * Command Handler for 'OVS_DP_CMD_NEW'.
1254 * --------------------------------------------------------------------------
1257 OvsNewDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1260 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1264 * --------------------------------------------------------------------------
1265 * Command Handler for 'OVS_DP_CMD_GET'.
1267 * The function handles both the dump based as well as the transaction based
1268 * 'OVS_DP_CMD_GET' command. In the dump command, it handles the initial
1269 * call to setup dump state, as well as subsequent calls to continue dumping
1271 * --------------------------------------------------------------------------
1274 OvsGetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1277 if (usrParamsCtx->devOp == OVS_TRANSACTION_DEV_OP) {
1278 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1280 return HandleGetDpDump(usrParamsCtx, replyLen);
1285 * --------------------------------------------------------------------------
1286 * Function for handling the transaction based 'OVS_DP_CMD_GET' command.
1287 * --------------------------------------------------------------------------
1290 HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1293 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1298 * --------------------------------------------------------------------------
1299 * Function for handling the dump-based 'OVS_DP_CMD_GET' command.
1300 * --------------------------------------------------------------------------
1303 HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1306 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1307 POVS_OPEN_INSTANCE instance =
1308 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1310 if (usrParamsCtx->devOp == OVS_WRITE_DEV_OP) {
1312 OvsSetupDumpStart(usrParamsCtx);
1316 POVS_MESSAGE msgIn = instance->dumpState.ovsMsg;
1318 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1320 if (instance->dumpState.ovsMsg == NULL) {
1322 return STATUS_INVALID_DEVICE_STATE;
1325 /* Dump state must have been deleted after previous dump operation. */
1326 ASSERT(instance->dumpState.index[0] == 0);
1328 /* Output buffer has been validated while validating read dev op. */
1329 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1331 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
1332 usrParamsCtx->outputLength);
1334 status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
1336 if (status != STATUS_SUCCESS) {
1338 FreeUserDumpState(instance);
1342 /* Increment the dump index. */
1343 instance->dumpState.index[0] = 1;
1344 *replyLen = msgOut->nlMsg.nlmsgLen;
1346 /* Free up the dump state, since there's no more data to continue. */
1347 FreeUserDumpState(instance);
1350 return STATUS_SUCCESS;
1355 * --------------------------------------------------------------------------
1356 * Command Handler for 'OVS_DP_CMD_SET'.
1357 * --------------------------------------------------------------------------
1360 OvsSetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1363 return HandleDpTransactionCommon(usrParamsCtx, replyLen);
1367 * --------------------------------------------------------------------------
1368 * Function for handling transaction based 'OVS_DP_CMD_NEW', 'OVS_DP_CMD_GET'
1369 * and 'OVS_DP_CMD_SET' commands.
1371 * 'OVS_DP_CMD_NEW' is implemented to keep userspace code happy. Creation of a
1372 * new datapath is not supported currently.
1373 * --------------------------------------------------------------------------
1376 HandleDpTransactionCommon(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1379 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1380 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1381 NTSTATUS status = STATUS_SUCCESS;
1383 NL_ERROR nlError = NL_ERROR_SUCCESS;
1384 static const NL_POLICY ovsDatapathSetPolicy[] = {
1385 [OVS_DP_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ },
1386 [OVS_DP_ATTR_UPCALL_PID] = { .type = NL_A_U32, .optional = TRUE },
1387 [OVS_DP_ATTR_USER_FEATURES] = { .type = NL_A_U32, .optional = TRUE },
1389 PNL_ATTR dpAttrs[ARRAY_SIZE(ovsDatapathSetPolicy)];
1391 UNREFERENCED_PARAMETER(msgOut);
1393 /* input buffer has been validated while validating write dev op. */
1394 ASSERT(msgIn != NULL && usrParamsCtx->inputLength >= sizeof *msgIn);
1396 /* Parse any attributes in the request. */
1397 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_SET ||
1398 usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_NEW) {
1399 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1400 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1401 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1402 ovsDatapathSetPolicy,
1403 ARRAY_SIZE(ovsDatapathSetPolicy),
1404 dpAttrs, ARRAY_SIZE(dpAttrs))) {
1405 return STATUS_INVALID_PARAMETER;
1409 * XXX: Not clear at this stage if there's any role for the
1410 * OVS_DP_ATTR_UPCALL_PID and OVS_DP_ATTR_USER_FEATURES attributes passed
1415 RtlZeroMemory(dpAttrs, sizeof dpAttrs);
1418 /* Output buffer has been validated while validating transact dev op. */
1419 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1421 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
1423 if (dpAttrs[OVS_DP_ATTR_NAME] != NULL) {
1424 if (!OvsCompareString(NlAttrGet(dpAttrs[OVS_DP_ATTR_NAME]),
1425 OVS_SYSTEM_DP_NAME)) {
1427 /* Creation of new datapaths is not supported. */
1428 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_SET) {
1429 nlError = NL_ERROR_NOTSUPP;
1433 nlError = NL_ERROR_NODEV;
1436 } else if ((UINT32)msgIn->ovsHdr.dp_ifindex != gOvsSwitchContext->dpNo) {
1437 nlError = NL_ERROR_NODEV;
1441 if (usrParamsCtx->ovsMsg->genlMsg.cmd == OVS_DP_CMD_NEW) {
1442 nlError = NL_ERROR_EXIST;
1446 status = OvsDpFillInfo(gOvsSwitchContext, msgIn, &nlBuf);
1448 *replyLen = NlBufSize(&nlBuf);
1451 if (nlError != NL_ERROR_SUCCESS) {
1452 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1453 usrParamsCtx->outputBuffer;
1454 UINT32 msgErrorLen = usrParamsCtx->outputLength;
1456 NlBuildErrorMsg(msgIn, msgError, msgErrorLen, nlError, replyLen);
1459 return STATUS_SUCCESS;
1464 OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx)
1466 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1467 POVS_OPEN_INSTANCE instance =
1468 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1470 /* input buffer has been validated while validating write dev op. */
1471 ASSERT(msgIn != NULL && usrParamsCtx->inputLength >= sizeof *msgIn);
1473 /* A write operation that does not indicate dump start is invalid. */
1474 if ((msgIn->nlMsg.nlmsgFlags & NLM_F_DUMP) != NLM_F_DUMP) {
1475 return STATUS_INVALID_PARAMETER;
1477 /* XXX: Handle other NLM_F_* flags in the future. */
1480 * This operation should be setting up the dump state. If there's any
1481 * previous state, clear it up so as to set it up afresh.
1483 FreeUserDumpState(instance);
1485 return InitUserDumpState(instance, msgIn);
1490 * --------------------------------------------------------------------------
1491 * Utility function to map the output buffer in an IRP. The buffer is assumed
1492 * to have been passed down using METHOD_OUT_DIRECT (Direct I/O).
1493 * --------------------------------------------------------------------------
1496 MapIrpOutputBuffer(PIRP irp,
1497 UINT32 bufferLength,
1498 UINT32 requiredLength,
1503 ASSERT(bufferLength);
1504 ASSERT(requiredLength);
1505 if (!buffer || !irp || bufferLength == 0 || requiredLength == 0) {
1506 return STATUS_INVALID_PARAMETER;
1509 if (bufferLength < requiredLength) {
1510 return STATUS_NDIS_INVALID_LENGTH;
1512 if (irp->MdlAddress == NULL) {
1513 return STATUS_INVALID_PARAMETER;
1515 *buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress,
1516 NormalPagePriority);
1517 if (*buffer == NULL) {
1518 return STATUS_INSUFFICIENT_RESOURCES;
1521 return STATUS_SUCCESS;
1525 * --------------------------------------------------------------------------
1526 * Utility function to fill up information about the state of a port in a reply
1528 * --------------------------------------------------------------------------
1531 OvsPortFillInfo(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1532 POVS_EVENT_ENTRY eventEntry,
1537 OVS_MESSAGE msgOutTmp;
1540 ASSERT(NlBufAt(nlBuf, 0, 0) != 0 && nlBuf->bufRemLen >= sizeof msgOutTmp);
1542 msgOutTmp.nlMsg.nlmsgType = OVS_WIN_NL_VPORT_FAMILY_ID;
1543 msgOutTmp.nlMsg.nlmsgFlags = 0; /* XXX: ? */
1545 /* driver intiated messages should have zerp seq number*/
1546 msgOutTmp.nlMsg.nlmsgSeq = 0;
1547 msgOutTmp.nlMsg.nlmsgPid = usrParamsCtx->ovsInstance->pid;
1549 msgOutTmp.genlMsg.version = nlVportFamilyOps.version;
1550 msgOutTmp.genlMsg.reserved = 0;
1552 /* we don't have netdev yet, treat link up/down a adding/removing a port*/
1553 if (eventEntry->type & (OVS_EVENT_LINK_UP | OVS_EVENT_CONNECT)) {
1554 msgOutTmp.genlMsg.cmd = OVS_VPORT_CMD_NEW;
1555 } else if (eventEntry->type &
1556 (OVS_EVENT_LINK_DOWN | OVS_EVENT_DISCONNECT)) {
1557 msgOutTmp.genlMsg.cmd = OVS_VPORT_CMD_DEL;
1560 return STATUS_UNSUCCESSFUL;
1562 msgOutTmp.ovsHdr.dp_ifindex = gOvsSwitchContext->dpNo;
1564 ok = NlMsgPutHead(nlBuf, (PCHAR)&msgOutTmp, sizeof msgOutTmp);
1566 status = STATUS_INVALID_BUFFER_SIZE;
1570 ok = NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_PORT_NO, eventEntry->portNo) &&
1571 NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_TYPE, eventEntry->ovsType) &&
1572 NlMsgPutTailU32(nlBuf, OVS_VPORT_ATTR_UPCALL_PID,
1573 eventEntry->upcallPid) &&
1574 NlMsgPutTailString(nlBuf, OVS_VPORT_ATTR_NAME, eventEntry->ovsName);
1576 status = STATUS_INVALID_BUFFER_SIZE;
1580 /* XXXX Should we add the port stats attributes?*/
1581 nlMsg = (PNL_MSG_HDR)NlBufAt(nlBuf, 0, 0);
1582 nlMsg->nlmsgLen = NlBufSize(nlBuf);
1583 status = STATUS_SUCCESS;
1591 * --------------------------------------------------------------------------
1592 * Handler for reading events from the driver event queue. This handler is
1593 * executed when user modes issues a socket receive on a socket assocaited
1594 * with the MC group for events.
1595 * XXX user mode should read multiple events in one system call
1596 * --------------------------------------------------------------------------
1599 OvsReadEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1603 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1604 POVS_OPEN_INSTANCE instance =
1605 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1609 OVS_EVENT_ENTRY eventEntry;
1611 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1613 /* Should never read events with a dump socket */
1614 ASSERT(instance->dumpState.ovsMsg == NULL);
1616 /* Must have an event queue */
1617 ASSERT(instance->eventQueue != NULL);
1619 /* Output buffer has been validated while validating read dev op. */
1620 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1622 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
1624 /* remove an event entry from the event queue */
1625 status = OvsRemoveEventEntry(usrParamsCtx->ovsInstance, &eventEntry);
1626 if (status != STATUS_SUCCESS) {
1627 /* If there were not elements, read should return no data. */
1628 status = STATUS_SUCCESS;
1633 status = OvsPortFillInfo(usrParamsCtx, &eventEntry, &nlBuf);
1634 if (status == NDIS_STATUS_SUCCESS) {
1635 *replyLen = NlBufSize(&nlBuf);