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
23 #if defined OVS_USE_NL_INTERFACE && OVS_USE_NL_INTERFACE == 1
40 #define OVS_DBG_MOD OVS_DBG_DATAPATH
43 #define NETLINK_FAMILY_NAME_LEN 48
47 * Netlink messages are grouped by family (aka type), and each family supports
48 * a set of commands, and can be passed both from kernel -> userspace or
49 * vice-versa. To call into the kernel, userspace uses a device operation which
50 * is outside of a netlink message.
52 * Each command results in the invocation of a handler function to implement the
53 * request functionality.
55 * Expectedly, only certain combinations of (device operation, netlink family,
58 * Here, we implement the basic infrastructure to perform validation on the
59 * incoming message, version checking, and also to invoke the corresponding
60 * handler to do the heavy-lifting.
64 * Handler for a given netlink command. Not all the parameters are used by all
67 typedef NTSTATUS (*NetlinkCmdHandler)(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
70 typedef struct _NETLINK_CMD {
72 NetlinkCmdHandler handler;
73 UINT32 supportedDevOp; /* Supported device operations. */
74 BOOLEAN validateDpIndex; /* Does command require a valid DP argument. */
75 } NETLINK_CMD, *PNETLINK_CMD;
77 /* A netlink family is a group of commands. */
78 typedef struct _NETLINK_FAMILY {
84 NETLINK_CMD *cmds; /* Array of netlink commands and handlers. */
86 } NETLINK_FAMILY, *PNETLINK_FAMILY;
89 * Device operations to tag netlink commands with. This is a bitmask since it is
90 * possible that a particular command can be invoked via different device
93 #define OVS_READ_DEV_OP (1 << 0)
94 #define OVS_WRITE_DEV_OP (1 << 1)
95 #define OVS_TRANSACTION_DEV_OP (1 << 2)
97 /* Handlers for the various netlink commands. */
98 static NTSTATUS OvsGetPidCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
101 static NTSTATUS OvsGetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
105 * The various netlink families, along with the supported commands. Most of
106 * these families and commands are part of the openvswitch specification for a
107 * netlink datapath. In addition, each platform can implement a few families
108 * and commands as extensions.
111 /* Netlink control family: this is a Windows specific family. */
112 NETLINK_CMD nlControlFamilyCmdOps[] = {
113 { .cmd = OVS_CTRL_CMD_WIN_GET_PID,
114 .handler = OvsGetPidCmdHandler,
115 .supportedDevOp = OVS_TRANSACTION_DEV_OP,
116 .validateDpIndex = FALSE
120 NETLINK_FAMILY nlControlFamilyOps = {
121 .name = OVS_WIN_CONTROL_FAMILY,
122 .id = OVS_WIN_NL_CTRL_FAMILY_ID,
123 .version = OVS_WIN_CONTROL_VERSION,
124 .maxAttr = OVS_WIN_CONTROL_ATTR_MAX,
125 .cmds = nlControlFamilyCmdOps,
126 .opsCount = ARRAY_SIZE(nlControlFamilyCmdOps)
129 /* Netlink datapath family. */
130 NETLINK_CMD nlDatapathFamilyCmdOps[] = {
131 { .cmd = OVS_DP_CMD_GET,
132 .handler = OvsGetDpCmdHandler,
133 .supportedDevOp = OVS_WRITE_DEV_OP | OVS_READ_DEV_OP,
134 .validateDpIndex = FALSE
138 NETLINK_FAMILY nlDatapathFamilyOps = {
139 .name = OVS_DATAPATH_FAMILY,
140 .id = OVS_WIN_NL_DATAPATH_FAMILY_ID,
141 .version = OVS_DATAPATH_VERSION,
142 .maxAttr = OVS_DP_ATTR_MAX,
143 .cmds = nlDatapathFamilyCmdOps,
144 .opsCount = ARRAY_SIZE(nlDatapathFamilyCmdOps)
147 /* Netlink packet family. */
148 /* XXX: Add commands here. */
149 NETLINK_FAMILY nlPacketFamilyOps = {
150 .name = OVS_PACKET_FAMILY,
151 .id = OVS_WIN_NL_PACKET_FAMILY_ID,
152 .version = OVS_PACKET_VERSION,
153 .maxAttr = OVS_PACKET_ATTR_MAX,
154 .cmds = NULL, /* XXX: placeholder. */
158 /* Netlink vport family. */
159 /* XXX: Add commands here. */
160 NETLINK_FAMILY nlVportFamilyOps = {
161 .name = OVS_VPORT_FAMILY,
162 .id = OVS_WIN_NL_VPORT_FAMILY_ID,
163 .version = OVS_VPORT_VERSION,
164 .maxAttr = OVS_VPORT_ATTR_MAX,
165 .cmds = NULL, /* XXX: placeholder. */
169 /* Netlink flow family. */
170 /* XXX: Add commands here. */
171 NETLINK_FAMILY nlFLowFamilyOps = {
172 .name = OVS_FLOW_FAMILY,
173 .id = OVS_WIN_NL_FLOW_FAMILY_ID,
174 .version = OVS_FLOW_VERSION,
175 .maxAttr = OVS_FLOW_ATTR_MAX,
176 .cmds = NULL, /* XXX: placeholder. */
180 static NTSTATUS MapIrpOutputBuffer(PIRP irp,
182 UINT32 requiredLength,
184 static NTSTATUS ValidateNetlinkCmd(UINT32 devOp,
185 POVS_OPEN_INSTANCE instance,
187 NETLINK_FAMILY *nlFamilyOps);
188 static NTSTATUS InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
189 NETLINK_FAMILY *nlFamilyOps,
191 static NTSTATUS OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx);
194 /* Handles to the device object for communication with userspace. */
195 NDIS_HANDLE gOvsDeviceHandle;
196 PDEVICE_OBJECT gOvsDeviceObject;
198 _Dispatch_type_(IRP_MJ_CREATE)
199 _Dispatch_type_(IRP_MJ_CLOSE)
200 DRIVER_DISPATCH OvsOpenCloseDevice;
202 _Dispatch_type_(IRP_MJ_CLEANUP)
203 DRIVER_DISPATCH OvsCleanupDevice;
205 _Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
206 DRIVER_DISPATCH OvsDeviceControl;
209 #pragma alloc_text(INIT, OvsCreateDeviceObject)
210 #pragma alloc_text(PAGE, OvsOpenCloseDevice)
211 #pragma alloc_text(PAGE, OvsCleanupDevice)
212 #pragma alloc_text(PAGE, OvsDeviceControl)
213 #endif // ALLOC_PRAGMA
216 * We might hit this limit easily since userspace opens a netlink descriptor for
217 * each thread, and at least one descriptor per vport. Revisit this later.
219 #define OVS_MAX_OPEN_INSTANCES 512
220 #define OVS_SYSTEM_DP_NAME "ovs-system"
222 POVS_OPEN_INSTANCE ovsOpenInstanceArray[OVS_MAX_OPEN_INSTANCES];
223 UINT32 ovsNumberOfOpenInstances;
224 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
226 NDIS_SPIN_LOCK ovsCtrlLockObj;
227 PNDIS_SPIN_LOCK gOvsCtrlLock;
233 gOvsCtrlLock = &ovsCtrlLockObj;
234 NdisAllocateSpinLock(gOvsCtrlLock);
242 OvsCleanupEventQueue();
244 NdisFreeSpinLock(gOvsCtrlLock);
253 NdisAcquireSpinLock(gOvsCtrlLock);
259 NdisReleaseSpinLock(gOvsCtrlLock);
264 * --------------------------------------------------------------------------
265 * Creates the communication device between user and kernel, and also
266 * initializes the data associated data structures.
267 * --------------------------------------------------------------------------
270 OvsCreateDeviceObject(NDIS_HANDLE ovsExtDriverHandle)
272 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
273 UNICODE_STRING deviceName;
274 UNICODE_STRING symbolicDeviceName;
275 PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
276 NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttributes;
277 OVS_LOG_TRACE("ovsExtDriverHandle: %p", ovsExtDriverHandle);
279 RtlZeroMemory(dispatchTable,
280 (IRP_MJ_MAXIMUM_FUNCTION + 1) * sizeof (PDRIVER_DISPATCH));
281 dispatchTable[IRP_MJ_CREATE] = OvsOpenCloseDevice;
282 dispatchTable[IRP_MJ_CLOSE] = OvsOpenCloseDevice;
283 dispatchTable[IRP_MJ_CLEANUP] = OvsCleanupDevice;
284 dispatchTable[IRP_MJ_DEVICE_CONTROL] = OvsDeviceControl;
286 NdisInitUnicodeString(&deviceName, OVS_DEVICE_NAME_NT);
287 NdisInitUnicodeString(&symbolicDeviceName, OVS_DEVICE_NAME_DOS);
289 RtlZeroMemory(&deviceAttributes, sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
291 OVS_INIT_OBJECT_HEADER(&deviceAttributes.Header,
292 NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES,
293 NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1,
294 sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES));
296 deviceAttributes.DeviceName = &deviceName;
297 deviceAttributes.SymbolicName = &symbolicDeviceName;
298 deviceAttributes.MajorFunctions = dispatchTable;
299 deviceAttributes.ExtensionSize = sizeof (OVS_DEVICE_EXTENSION);
301 status = NdisRegisterDeviceEx(ovsExtDriverHandle,
305 if (status != NDIS_STATUS_SUCCESS) {
306 POVS_DEVICE_EXTENSION ovsExt =
307 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(gOvsDeviceObject);
308 ASSERT(gOvsDeviceObject != NULL);
309 ASSERT(gOvsDeviceHandle != NULL);
312 ovsExt->numberOpenInstance = 0;
315 /* Initialize the associated data structures. */
318 OVS_LOG_TRACE("DeviceObject: %p", gOvsDeviceObject);
324 OvsDeleteDeviceObject()
326 if (gOvsDeviceHandle) {
328 POVS_DEVICE_EXTENSION ovsExt = (POVS_DEVICE_EXTENSION)
329 NdisGetDeviceReservedExtension(gOvsDeviceObject);
331 ASSERT(ovsExt->numberOpenInstance == 0);
335 ASSERT(gOvsDeviceObject);
336 NdisDeregisterDeviceEx(gOvsDeviceHandle);
337 gOvsDeviceHandle = NULL;
338 gOvsDeviceObject = NULL;
344 OvsGetOpenInstance(PFILE_OBJECT fileObject,
347 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
349 ASSERT(instance->fileObject == fileObject);
350 if (gOvsSwitchContext == NULL ||
351 gOvsSwitchContext->dpNo != dpNo) {
359 OvsFindOpenInstance(PFILE_OBJECT fileObject)
362 for (i = 0, j = 0; i < OVS_MAX_OPEN_INSTANCES &&
363 j < ovsNumberOfOpenInstances; i++) {
364 if (ovsOpenInstanceArray[i]) {
365 if (ovsOpenInstanceArray[i]->fileObject == fileObject) {
366 return ovsOpenInstanceArray[i];
375 OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt,
376 PFILE_OBJECT fileObject)
378 POVS_OPEN_INSTANCE instance =
379 (POVS_OPEN_INSTANCE) OvsAllocateMemory(sizeof (OVS_OPEN_INSTANCE));
382 if (instance == NULL) {
383 return STATUS_NO_MEMORY;
385 OvsAcquireCtrlLock();
386 ASSERT(OvsFindOpenInstance(fileObject) == NULL);
388 if (ovsNumberOfOpenInstances >= OVS_MAX_OPEN_INSTANCES) {
389 OvsReleaseCtrlLock();
390 OvsFreeMemory(instance);
391 return STATUS_INSUFFICIENT_RESOURCES;
393 RtlZeroMemory(instance, sizeof (OVS_OPEN_INSTANCE));
395 for (i = 0; i < OVS_MAX_OPEN_INSTANCES; i++) {
396 if (ovsOpenInstanceArray[i] == NULL) {
397 ovsOpenInstanceArray[i] = instance;
398 instance->cookie = i;
402 ASSERT(i < OVS_MAX_OPEN_INSTANCES);
403 instance->fileObject = fileObject;
404 ASSERT(fileObject->FsContext == NULL);
405 instance->pid = (UINT32)InterlockedIncrement((LONG volatile *)&ovsExt->pidCount);
406 if (instance->pid == 0) {
407 /* XXX: check for rollover. */
409 fileObject->FsContext = instance;
410 OvsReleaseCtrlLock();
411 return STATUS_SUCCESS;
415 OvsCleanupOpenInstance(PFILE_OBJECT fileObject)
417 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
419 ASSERT(fileObject == instance->fileObject);
420 OvsCleanupEvent(instance);
421 OvsCleanupPacketQueue(instance);
425 OvsRemoveOpenInstance(PFILE_OBJECT fileObject)
427 POVS_OPEN_INSTANCE instance;
428 ASSERT(fileObject->FsContext);
429 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
430 ASSERT(instance->cookie < OVS_MAX_OPEN_INSTANCES);
432 OvsAcquireCtrlLock();
433 fileObject->FsContext = NULL;
434 ASSERT(ovsOpenInstanceArray[instance->cookie] == instance);
435 ovsOpenInstanceArray[instance->cookie] = NULL;
436 OvsReleaseCtrlLock();
437 ASSERT(instance->eventQueue == NULL);
438 ASSERT (instance->packetQueue == NULL);
439 OvsFreeMemory(instance);
443 OvsCompleteIrpRequest(PIRP irp,
447 irp->IoStatus.Information = infoPtr;
448 irp->IoStatus.Status = status;
449 IoCompleteRequest(irp, IO_NO_INCREMENT);
455 OvsOpenCloseDevice(PDEVICE_OBJECT deviceObject,
458 PIO_STACK_LOCATION irpSp;
459 NTSTATUS status = STATUS_SUCCESS;
460 PFILE_OBJECT fileObject;
461 POVS_DEVICE_EXTENSION ovsExt =
462 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
464 ASSERT(deviceObject == gOvsDeviceObject);
465 ASSERT(ovsExt != NULL);
467 irpSp = IoGetCurrentIrpStackLocation(irp);
468 fileObject = irpSp->FileObject;
469 OVS_LOG_TRACE("DeviceObject: %p, fileObject:%p, instance: %u",
470 deviceObject, fileObject,
471 ovsExt->numberOpenInstance);
473 switch (irpSp->MajorFunction) {
475 status = OvsAddOpenInstance(ovsExt, fileObject);
476 if (STATUS_SUCCESS == status) {
477 InterlockedIncrement((LONG volatile *)&ovsExt->numberOpenInstance);
481 ASSERT(ovsExt->numberOpenInstance > 0);
482 OvsRemoveOpenInstance(fileObject);
483 InterlockedDecrement((LONG volatile *)&ovsExt->numberOpenInstance);
488 return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
491 _Use_decl_annotations_
493 OvsCleanupDevice(PDEVICE_OBJECT deviceObject,
497 PIO_STACK_LOCATION irpSp;
498 PFILE_OBJECT fileObject;
500 NTSTATUS status = STATUS_SUCCESS;
502 POVS_DEVICE_EXTENSION ovsExt =
503 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
505 ASSERT(ovsExt->numberOpenInstance > 0);
508 UNREFERENCED_PARAMETER(deviceObject);
510 ASSERT(deviceObject == gOvsDeviceObject);
511 irpSp = IoGetCurrentIrpStackLocation(irp);
512 fileObject = irpSp->FileObject;
514 ASSERT(irpSp->MajorFunction == IRP_MJ_CLEANUP);
516 OvsCleanupOpenInstance(fileObject);
518 return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status);
523 * --------------------------------------------------------------------------
524 * IOCTL function handler for the device.
525 * --------------------------------------------------------------------------
528 OvsDeviceControl(PDEVICE_OBJECT deviceObject,
532 PIO_STACK_LOCATION irpSp;
533 NTSTATUS status = STATUS_SUCCESS;
534 PFILE_OBJECT fileObject;
535 PVOID inputBuffer = NULL;
536 PVOID outputBuffer = NULL;
537 UINT32 inputBufferLen, outputBufferLen;
538 UINT32 code, replyLen = 0;
539 POVS_OPEN_INSTANCE instance;
541 OVS_MESSAGE ovsMsgReadOp;
543 NETLINK_FAMILY *nlFamilyOps;
544 OVS_USER_PARAMS_CONTEXT usrParamsCtx;
547 POVS_DEVICE_EXTENSION ovsExt =
548 (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject);
549 ASSERT(deviceObject == gOvsDeviceObject);
551 ASSERT(ovsExt->numberOpenInstance > 0);
553 UNREFERENCED_PARAMETER(deviceObject);
556 irpSp = IoGetCurrentIrpStackLocation(irp);
558 ASSERT(irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
559 ASSERT(irpSp->FileObject != NULL);
561 fileObject = irpSp->FileObject;
562 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
563 code = irpSp->Parameters.DeviceIoControl.IoControlCode;
564 inputBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
565 outputBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
566 inputBuffer = irp->AssociatedIrp.SystemBuffer;
568 /* Concurrent netlink operations are not supported. */
569 if (InterlockedCompareExchange((LONG volatile *)&instance->inUse, 1, 0)) {
570 status = STATUS_RESOURCE_IN_USE;
575 * Validate the input/output buffer arguments depending on the type of the
579 case OVS_IOCTL_TRANSACT:
580 /* Input buffer is mandatory, output buffer is optional. */
581 if (outputBufferLen != 0) {
582 status = MapIrpOutputBuffer(irp, outputBufferLen,
583 sizeof *ovsMsg, &outputBuffer);
584 if (status != STATUS_SUCCESS) {
587 ASSERT(outputBuffer);
590 if (inputBufferLen < sizeof (*ovsMsg)) {
591 status = STATUS_NDIS_INVALID_LENGTH;
595 ovsMsg = inputBuffer;
596 devOp = OVS_TRANSACTION_DEV_OP;
600 /* Output buffer is mandatory. */
601 if (outputBufferLen != 0) {
602 status = MapIrpOutputBuffer(irp, outputBufferLen,
603 sizeof *ovsMsg, &outputBuffer);
604 if (status != STATUS_SUCCESS) {
607 ASSERT(outputBuffer);
609 status = STATUS_NDIS_INVALID_LENGTH;
614 * Operate in the mode that read ioctl is similar to ReadFile(). This
615 * might change as the userspace code gets implemented.
621 * For implementing read (ioctl or otherwise), we need to store some
622 * state in the instance to indicate the command that started the dump
623 * operation. The state can setup 'ovsMsgReadOp' appropriately. Note
624 * that 'ovsMsgReadOp' is needed only in this function to call into the
625 * appropraite handler. The handler itself can access the state in the
628 * In the absence of a dump start, return 0 bytes.
630 if (instance->dumpState.ovsMsg == NULL) {
632 status = STATUS_SUCCESS;
635 RtlCopyMemory(&ovsMsgReadOp, instance->dumpState.ovsMsg,
636 sizeof (ovsMsgReadOp));
638 /* Create an NL message for consumption. */
639 ovsMsg = &ovsMsgReadOp;
640 devOp = OVS_READ_DEV_OP;
644 case OVS_IOCTL_WRITE:
645 /* Input buffer is mandatory. */
646 if (inputBufferLen < sizeof (*ovsMsg)) {
647 status = STATUS_NDIS_INVALID_LENGTH;
651 ovsMsg = inputBuffer;
652 devOp = OVS_WRITE_DEV_OP;
656 status = STATUS_INVALID_DEVICE_REQUEST;
661 switch (ovsMsg->nlMsg.nlmsgType) {
662 case OVS_WIN_NL_CTRL_FAMILY_ID:
663 nlFamilyOps = &nlControlFamilyOps;
665 case OVS_WIN_NL_DATAPATH_FAMILY_ID:
666 nlFamilyOps = &nlDatapathFamilyOps;
668 case OVS_WIN_NL_PACKET_FAMILY_ID:
669 case OVS_WIN_NL_FLOW_FAMILY_ID:
670 case OVS_WIN_NL_VPORT_FAMILY_ID:
671 status = STATUS_NOT_IMPLEMENTED;
675 status = STATUS_INVALID_PARAMETER;
680 * For read operation, the netlink command has already been validated
683 if (devOp != OVS_READ_DEV_OP) {
684 status = ValidateNetlinkCmd(devOp, instance, ovsMsg, nlFamilyOps);
685 if (status != STATUS_SUCCESS) {
690 InitUserParamsCtx(irp, instance, devOp, ovsMsg,
691 inputBuffer, inputBufferLen,
692 outputBuffer, outputBufferLen,
695 status = InvokeNetlinkCmdHandler(&usrParamsCtx, nlFamilyOps, &replyLen);
700 return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status);
705 * --------------------------------------------------------------------------
706 * Function to validate a netlink command. Only certain combinations of
707 * (device operation, netlink family, command) are valid.
709 * XXX: Take policy into consideration.
710 * --------------------------------------------------------------------------
713 ValidateNetlinkCmd(UINT32 devOp,
714 POVS_OPEN_INSTANCE instance,
716 NETLINK_FAMILY *nlFamilyOps)
718 NTSTATUS status = STATUS_INVALID_PARAMETER;
721 for (i = 0; i < nlFamilyOps->opsCount; i++) {
722 if (nlFamilyOps->cmds[i].cmd == ovsMsg->genlMsg.cmd) {
723 /* Validate if the command is valid for the device operation. */
724 if ((devOp & nlFamilyOps->cmds[i].supportedDevOp) == 0) {
725 status = STATUS_INVALID_PARAMETER;
729 /* Validate the version. */
730 if (nlFamilyOps->version > ovsMsg->genlMsg.version) {
731 status = STATUS_INVALID_PARAMETER;
735 /* Validate the DP for commands that require a DP. */
736 if (nlFamilyOps->cmds[i].validateDpIndex == TRUE) {
737 OvsAcquireCtrlLock();
738 if (ovsMsg->ovsHdr.dp_ifindex !=
739 (INT)gOvsSwitchContext->dpNo) {
740 status = STATUS_INVALID_PARAMETER;
741 OvsReleaseCtrlLock();
744 OvsReleaseCtrlLock();
747 /* Validate the PID. */
748 if (ovsMsg->genlMsg.cmd != OVS_CTRL_CMD_WIN_GET_PID) {
749 if (ovsMsg->nlMsg.nlmsgPid != instance->pid) {
750 status = STATUS_INVALID_PARAMETER;
755 status = STATUS_SUCCESS;
765 * --------------------------------------------------------------------------
766 * Function to invoke the netlink command handler.
767 * --------------------------------------------------------------------------
770 InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
771 NETLINK_FAMILY *nlFamilyOps,
774 NTSTATUS status = STATUS_INVALID_PARAMETER;
777 for (i = 0; i < nlFamilyOps->opsCount; i++) {
778 if (nlFamilyOps->cmds[i].cmd == usrParamsCtx->ovsMsg->genlMsg.cmd) {
779 status = nlFamilyOps->cmds[i].handler(usrParamsCtx, replyLen);
789 * --------------------------------------------------------------------------
790 * Each handle on the device is assigned a unique PID when the handle is
791 * created. On platforms that support netlink natively, the PID is available
792 * to userspace when the netlink socket is created. However, without native
793 * netlink support on Windows, OVS datapath generates the PID and lets the
794 * userspace query it.
796 * This function implements the query.
797 * --------------------------------------------------------------------------
800 OvsGetPidCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
803 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
804 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
806 if (usrParamsCtx->outputLength >= sizeof *msgOut) {
807 POVS_OPEN_INSTANCE instance =
808 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
810 RtlZeroMemory(msgOut, sizeof *msgOut);
811 msgOut->nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
812 msgOut->nlMsg.nlmsgPid = instance->pid;
813 *replyLen = sizeof *msgOut;
814 /* XXX: We might need to return the DP index as well. */
816 return STATUS_NDIS_INVALID_LENGTH;
819 return STATUS_SUCCESS;
823 * --------------------------------------------------------------------------
824 * Handler for the get dp command. The function handles the initial call to
825 * setup the dump state, as well as subsequent calls to continue dumping data.
826 * --------------------------------------------------------------------------
829 OvsGetDpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
832 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
833 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
834 POVS_OPEN_INSTANCE instance =
835 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
837 if (usrParamsCtx->devOp == OVS_WRITE_DEV_OP) {
839 OvsSetupDumpStart(usrParamsCtx);
841 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
843 if (instance->dumpState.ovsMsg == NULL) {
845 return STATUS_INVALID_DEVICE_STATE;
848 /* Dump state must have been deleted after previous dump operation. */
849 ASSERT(instance->dumpState.index[0] == 0);
850 /* Output buffer has been validated while validating read dev op. */
851 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
853 /* XXX: Replace this with the netlink set API. */
854 msgIn = instance->dumpState.ovsMsg;
855 msgOut->nlMsg.nlmsgType = OVS_WIN_NL_DATAPATH_FAMILY_ID;
856 msgOut->nlMsg.nlmsgFlags = 0; /* XXX: ? */
857 msgOut->nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
858 msgOut->nlMsg.nlmsgPid = msgIn->nlMsg.nlmsgPid;
859 msgOut->nlMsg.nlmsgLen = sizeof *msgOut;
861 msgOut->genlMsg.cmd = OVS_DP_CMD_GET;
862 msgOut->genlMsg.version = nlDatapathFamilyOps.version;
863 msgOut->genlMsg.reserved = 0;
865 OvsAcquireCtrlLock();
866 if (gOvsSwitchContext) {
867 msgOut->ovsHdr.dp_ifindex = gOvsSwitchContext->dpNo;
869 /* Treat this as a dump done. */
870 OvsReleaseCtrlLock();
872 FreeUserDumpState(instance);
873 return STATUS_SUCCESS;
876 /* XXX: Replace this with the netlink set API. */
879 * Assume that the output buffer is at least 512 bytes. Once the
880 * netlink set API is implemented, the netlink buffer manipulation
881 * API should provide for checking the remaining number of bytes as
882 * we write out the message.
884 if (usrParamsCtx->outputLength <= 512) {
885 OvsReleaseCtrlLock();
886 return STATUS_NDIS_INVALID_LENGTH;
888 UINT16 attrTotalSize = 0;
890 PNL_ATTR nlAttr = (PNL_ATTR) ((PCHAR)msgOut + sizeof (*msgOut));
891 struct ovs_dp_stats *dpStats;
892 OVS_DATAPATH *datapath = &gOvsSwitchContext->datapath;
894 nlAttr->nlaType = OVS_DP_ATTR_NAME;
895 /* 'nlaLen' must not include the pad. */
896 nlAttr->nlaLen = sizeof (*nlAttr) + sizeof (OVS_SYSTEM_DP_NAME);
897 attrSize = sizeof (*nlAttr) +
898 NLA_ALIGN(sizeof (OVS_SYSTEM_DP_NAME));
899 attrTotalSize += attrSize;
901 PNL_ATTR nlAttrNext = NlAttrGet(nlAttr);
902 RtlCopyMemory((PCHAR)nlAttrNext, OVS_SYSTEM_DP_NAME,
903 sizeof (OVS_SYSTEM_DP_NAME));
905 nlAttr = (PNL_ATTR)((PCHAR)nlAttr + attrSize);
906 nlAttr->nlaType = OVS_DP_ATTR_STATS;
907 nlAttr->nlaLen = sizeof (*nlAttr) + sizeof (*dpStats);
908 attrSize = sizeof (*nlAttr) + NLA_ALIGN(sizeof (*dpStats));
909 attrTotalSize += attrSize;
911 dpStats = NlAttrGet(nlAttr);
912 dpStats->n_hit = datapath->hits;
913 dpStats->n_missed = datapath->misses;
914 dpStats->n_lost = datapath->lost;
915 dpStats->n_flows = datapath->nFlows;
917 msgOut->nlMsg.nlmsgLen += attrTotalSize;
919 OvsReleaseCtrlLock();
921 /* Increment the dump index. */
922 instance->dumpState.index[0] = 1;
923 *replyLen = msgOut->nlMsg.nlmsgLen;
924 ASSERT(*replyLen <= 512);
926 /* Free up the dump state, since there's no more data to continue. */
927 FreeUserDumpState(instance);
930 return STATUS_SUCCESS;
934 OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx)
936 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
937 POVS_OPEN_INSTANCE instance =
938 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
940 /* input buffer has been validated while validating write dev op. */
941 ASSERT(msgIn != NULL && usrParamsCtx->inputLength >= sizeof *msgIn);
943 /* A write operation that does not indicate dump start is invalid. */
944 if ((msgIn->nlMsg.nlmsgFlags & NLM_F_DUMP) != NLM_F_DUMP) {
945 return STATUS_INVALID_PARAMETER;
947 /* XXX: Handle other NLM_F_* flags in the future. */
950 * This operation should be setting up the dump state. If there's any
951 * previous state, clear it up so as to set it up afresh.
953 if (instance->dumpState.ovsMsg != NULL) {
954 FreeUserDumpState(instance);
957 return InitUserDumpState(instance, msgIn);
961 * --------------------------------------------------------------------------
962 * Utility function to map the output buffer in an IRP. The buffer is assumed
963 * to have been passed down using METHOD_OUT_DIRECT (Direct I/O).
964 * --------------------------------------------------------------------------
967 MapIrpOutputBuffer(PIRP irp,
969 UINT32 requiredLength,
974 ASSERT(bufferLength);
975 ASSERT(requiredLength);
976 if (!buffer || !irp || bufferLength == 0 || requiredLength == 0) {
977 return STATUS_INVALID_PARAMETER;
980 if (bufferLength < requiredLength) {
981 return STATUS_NDIS_INVALID_LENGTH;
983 if (irp->MdlAddress == NULL) {
984 return STATUS_INVALID_PARAMETER;
986 *buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress,
988 if (*buffer == NULL) {
989 return STATUS_INSUFFICIENT_RESOURCES;
992 return STATUS_SUCCESS;
995 #endif /* OVS_USE_NL_INTERFACE */