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.
31 #define OVS_DBG_MOD OVS_DBG_VPORT
34 #define VPORT_NIC_ENTER(_nic) \
35 OVS_LOG_TRACE("Enter: PortId: %x, NicIndex: %d", _nic->PortId, \
38 #define VPORT_NIC_EXIT(_nic) \
39 OVS_LOG_TRACE("Exit: PortId: %x, NicIndex: %d", _nic->PortId, \
42 #define VPORT_PORT_ENTER(_port) \
43 OVS_LOG_TRACE("Enter: PortId: %x", _port->PortId)
45 #define VPORT_PORT_EXIT(_port) \
46 OVS_LOG_TRACE("Exit: PortId: %x", _port->PortId)
48 #define OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC 100
50 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
51 extern PNDIS_SPIN_LOCK gOvsCtrlLock;
53 static VOID OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
54 PNDIS_SWITCH_PORT_PARAMETERS portParam);
55 static VOID OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
56 POVS_VPORT_ENTRY vport, PNDIS_SWITCH_NIC_PARAMETERS nicParam);
57 static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVPort,
58 POVS_VPORT_ENTRY virtExtVport, UINT32 nicIndex);
59 static __inline VOID OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext,
61 static NTSTATUS OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
62 POVS_VPORT_EXT_INFO extInfo);
63 static NTSTATUS CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
68 static POVS_VPORT_ENTRY OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext,
69 PWSTR wsName, SIZE_T wstrSize);
72 * Functions implemented in relaton to NDIS port manipulation.
75 HvCreatePort(POVS_SWITCH_CONTEXT switchContext,
76 PNDIS_SWITCH_PORT_PARAMETERS portParam)
78 POVS_VPORT_ENTRY vport;
79 LOCK_STATE_EX lockState;
80 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
82 VPORT_PORT_ENTER(portParam);
84 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
85 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
86 portParam->PortId, 0);
87 if (vport != NULL && !vport->hvDeleted) {
88 status = STATUS_DATA_NOT_ACCEPTED;
89 goto create_port_done;
91 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
93 status = NDIS_STATUS_RESOURCES;
94 goto create_port_done;
98 OvsInitVportWithPortParam(vport, portParam);
99 InitHvVportCommon(switchContext, vport);
102 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
103 VPORT_PORT_EXIT(portParam);
109 * Function updating the port properties
112 HvUpdatePort(POVS_SWITCH_CONTEXT switchContext,
113 PNDIS_SWITCH_PORT_PARAMETERS portParam)
115 POVS_VPORT_ENTRY vport;
116 LOCK_STATE_EX lockState;
117 OVS_VPORT_STATE ovsState;
118 NDIS_SWITCH_NIC_STATE nicState;
120 VPORT_PORT_ENTER(portParam);
122 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
123 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
124 portParam->PortId, 0);
126 * Update properties only for NETDEV ports for supprting PS script
127 * We don't allow changing the names of the internal or external ports
129 if (vport == NULL || ( vport->portType != NdisSwitchPortTypeSynthetic) ||
130 ( vport->portType != NdisSwitchPortTypeEmulated)) {
131 goto update_port_done;
134 /* Store the nic and the OVS states as Nic Create won't be called */
135 ovsState = vport->ovsState;
136 nicState = vport->nicState;
139 * Currently only the port friendly name is being updated
140 * Make sure that no other properties are changed
142 ASSERT(portParam->PortId == vport->portId);
143 ASSERT(portParam->PortState == vport->portState);
144 ASSERT(portParam->PortType == vport->portType);
147 * Call the set parameters function the handle all properties
148 * change in a single place in case future version supports change of
151 OvsInitVportWithPortParam(vport, portParam);
152 /* Retore the nic and OVS states */
153 vport->nicState = nicState;
154 vport->ovsState = ovsState;
157 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
158 VPORT_PORT_EXIT(portParam);
160 /* Must always return success */
161 return NDIS_STATUS_SUCCESS;
165 HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
166 PNDIS_SWITCH_PORT_PARAMETERS portParam)
168 POVS_VPORT_ENTRY vport;
169 LOCK_STATE_EX lockState;
171 VPORT_PORT_ENTER(portParam);
173 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
174 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
175 portParam->PortId, 0);
177 /* add assertion here
179 vport->portState = NdisSwitchPortStateTeardown;
180 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
182 OVS_LOG_WARN("Vport not present.");
184 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
186 VPORT_PORT_EXIT(portParam);
192 HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
193 PNDIS_SWITCH_PORT_PARAMETERS portParams)
195 POVS_VPORT_ENTRY vport;
196 LOCK_STATE_EX lockState;
198 VPORT_PORT_ENTER(portParams);
200 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
201 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
202 portParams->PortId, 0);
205 * XXX: we can only destroy and remove the port if its datapath port
206 * counterpart was deleted. If the datapath port counterpart is present,
207 * we only mark the vport for deletion, so that a netlink command vport
208 * delete will delete the vport.
211 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
212 OvsRemoveAndDeleteVport(switchContext, vport);
214 vport->hvDeleted = TRUE;
217 OVS_LOG_WARN("Vport not present.");
219 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
221 VPORT_PORT_EXIT(portParams);
226 * Functions implemented in relaton to NDIS NIC manipulation.
229 HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
230 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
232 POVS_VPORT_ENTRY vport;
235 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
237 LOCK_STATE_EX lockState;
239 VPORT_NIC_ENTER(nicParam);
241 /* Wait for lists to be initialized. */
242 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
244 if (!switchContext->isActivated) {
245 OVS_LOG_WARN("Switch is not activated yet.");
246 /* Veto the creation of nic */
247 status = NDIS_STATUS_NOT_SUPPORTED;
251 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
252 vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId, 0);
254 OVS_LOG_ERROR("Create NIC without Switch Port,"
255 " PortId: %x, NicIndex: %d",
256 nicParam->PortId, nicParam->NicIndex);
257 status = NDIS_STATUS_INVALID_PARAMETER;
261 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
262 nicParam->NicIndex != 0) {
263 POVS_VPORT_ENTRY virtExtVport =
264 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
266 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
268 status = NDIS_STATUS_RESOURCES;
271 OvsInitPhysNicVport(vport, virtExtVport, nicParam->NicIndex);
272 status = InitHvVportCommon(switchContext, vport);
273 if (status != NDIS_STATUS_SUCCESS) {
274 OvsFreeMemory(vport);
278 OvsInitVportWithNicParam(switchContext, vport, nicParam);
279 portNo = vport->portNo;
280 if (vport->ovsState == OVS_STATE_CONNECTED) {
281 event = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
282 } else if (vport->ovsState == OVS_STATE_NIC_CREATED) {
283 event = OVS_EVENT_CONNECT;
287 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
288 if (portNo != OVS_DPPORT_NUMBER_INVALID && event) {
289 OvsPostEvent(portNo, event);
293 VPORT_NIC_EXIT(nicParam);
294 OVS_LOG_TRACE("Exit: status %8x.\n", status);
300 /* Mark already created NIC as connected. */
302 HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
303 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
305 LOCK_STATE_EX lockState;
306 POVS_VPORT_ENTRY vport;
309 VPORT_NIC_ENTER(nicParam);
311 /* Wait for lists to be initialized. */
312 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
314 if (!switchContext->isActivated) {
315 OVS_LOG_WARN("Switch is not activated yet.");
319 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
320 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
325 OVS_LOG_WARN("Vport not present.");
326 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
331 vport->ovsState = OVS_STATE_CONNECTED;
332 vport->nicState = NdisSwitchNicStateConnected;
333 portNo = vport->portNo;
335 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
337 /* XXX only if portNo != INVALID or always? */
338 OvsPostEvent(portNo, OVS_EVENT_LINK_UP);
340 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
341 OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
345 VPORT_NIC_EXIT(nicParam);
349 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
350 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
352 POVS_VPORT_ENTRY vport;
353 LOCK_STATE_EX lockState;
355 UINT32 status = 0, portNo = 0;
357 VPORT_NIC_ENTER(nicParam);
359 /* Wait for lists to be initialized. */
360 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
362 if (!switchContext->isActivated) {
363 OVS_LOG_WARN("Switch is not activated yet.");
364 goto update_nic_done;
367 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
368 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
372 OVS_LOG_WARN("Vport search failed.");
373 goto update_nic_done;
375 switch (nicParam->NicType) {
376 case NdisSwitchNicTypeExternal:
377 case NdisSwitchNicTypeInternal:
378 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
381 case NdisSwitchNicTypeSynthetic:
382 case NdisSwitchNicTypeEmulated:
383 if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
384 sizeof (vport->vmMacAddress))) {
385 status |= OVS_EVENT_MAC_CHANGE;
386 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
387 sizeof (vport->vmMacAddress));
393 if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
394 sizeof (vport->permMacAddress))) {
395 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
396 sizeof (vport->permMacAddress));
397 status |= OVS_EVENT_MAC_CHANGE;
399 if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
400 sizeof (vport->currMacAddress))) {
401 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
402 sizeof (vport->currMacAddress));
403 status |= OVS_EVENT_MAC_CHANGE;
406 if (vport->mtu != nicParam->MTU) {
407 vport->mtu = nicParam->MTU;
408 status |= OVS_EVENT_MTU_CHANGE;
410 vport->numaNodeId = nicParam->NumaNodeId;
411 portNo = vport->portNo;
413 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
414 if (status && portNo) {
415 OvsPostEvent(portNo, status);
418 VPORT_NIC_EXIT(nicParam);
423 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
424 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
426 POVS_VPORT_ENTRY vport;
428 LOCK_STATE_EX lockState;
429 BOOLEAN isInternalPort = FALSE;
431 VPORT_NIC_ENTER(nicParam);
433 /* Wait for lists to be initialized. */
434 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
436 if (!switchContext->isActivated) {
437 OVS_LOG_WARN("Switch is not activated yet.");
441 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
442 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
447 OVS_LOG_WARN("Vport not present.");
448 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
452 vport->nicState = NdisSwitchNicStateDisconnected;
453 vport->ovsState = OVS_STATE_NIC_CREATED;
454 portNo = vport->portNo;
456 if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
457 isInternalPort = TRUE;
460 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
462 /* XXX if portNo != INVALID or always? */
463 OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
465 if (isInternalPort) {
466 OvsInternalAdapterDown();
470 VPORT_NIC_EXIT(nicParam);
475 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
476 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
478 LOCK_STATE_EX lockState;
479 POVS_VPORT_ENTRY vport;
482 VPORT_NIC_ENTER(nicParam);
483 /* Wait for lists to be initialized. */
484 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
486 if (!switchContext->isActivated) {
487 OVS_LOG_WARN("Switch is not activated yet.");
491 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
492 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
497 OVS_LOG_WARN("Vport not present.");
498 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
502 portNo = vport->portNo;
503 if (vport->portType == NdisSwitchPortTypeExternal &&
504 vport->nicIndex != 0) {
505 OvsRemoveAndDeleteVport(switchContext, vport);
507 vport->nicState = NdisSwitchNicStateUnknown;
508 vport->ovsState = OVS_STATE_PORT_CREATED;
510 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
511 /* XXX if portNo != INVALID or always? */
512 OvsPostEvent(portNo, OVS_EVENT_DISCONNECT);
515 VPORT_NIC_EXIT(nicParam);
520 * OVS Vport related functionality.
523 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
526 POVS_VPORT_ENTRY vport;
527 PLIST_ENTRY head, link;
528 UINT32 hash = OvsJhashBytes((const VOID *)&portNo, sizeof(portNo),
530 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
531 LIST_FORALL(head, link) {
532 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
533 if (vport->portNo == portNo) {
542 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
545 POVS_VPORT_ENTRY vport;
546 PLIST_ENTRY head, link;
548 SIZE_T length = strlen(name) + 1;
550 hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
551 head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
553 LIST_FORALL(head, link) {
554 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
555 if (!strcmp(name, vport->ovsName)) {
563 /* OvsFindVportByHvName: "name" is assumed to be null-terminated */
565 OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext,
566 PWSTR wsName, SIZE_T wstrSize)
568 POVS_VPORT_ENTRY vport = NULL;
569 PLIST_ENTRY head, link;
572 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
573 head = &(switchContext->portIdHashArray[i]);
574 LIST_FORALL(head, link) {
575 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
578 * NOTE about portFriendlyName:
579 * If the string is NULL-terminated, the Length member does not
580 * include the terminating NULL character.
582 if (vport->portFriendlyName.Length == wstrSize &&
583 RtlEqualMemory(wsName, vport->portFriendlyName.String,
584 vport->portFriendlyName.Length)) {
593 OvsFreeMemory(wsName);
599 OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext,
602 POVS_VPORT_ENTRY vport = NULL;
603 /* 'portFriendlyName' is not NUL-terminated. */
604 SIZE_T length = strlen(name);
605 SIZE_T wstrSize = length * sizeof(WCHAR);
608 PWSTR wsName = OvsAllocateMemory(wstrSize);
612 for (i = 0; i < length; i++) {
615 vport = OvsFindVportByHvNameW(switchContext, wsName, wstrSize);
616 OvsFreeMemory(wsName);
620 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
621 NDIS_SWITCH_PORT_ID portId,
622 NDIS_SWITCH_NIC_INDEX index)
624 if (switchContext->virtualExternalVport &&
625 portId == switchContext->virtualExternalPortId &&
626 index == switchContext->virtualExternalVport->nicIndex) {
627 return (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
628 } else if (switchContext->internalVport &&
629 portId == switchContext->internalPortId &&
630 index == switchContext->internalVport->nicIndex) {
631 return (POVS_VPORT_ENTRY)switchContext->internalVport;
633 PLIST_ENTRY head, link;
634 POVS_VPORT_ENTRY vport;
636 hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
637 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
638 LIST_FORALL(head, link) {
639 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
640 if (portId == vport->portId && index == vport->nicIndex) {
649 OvsAllocateVport(VOID)
651 POVS_VPORT_ENTRY vport;
652 vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY));
656 RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
657 vport->ovsState = OVS_STATE_UNKNOWN;
658 vport->hvDeleted = FALSE;
659 vport->portNo = OVS_DPPORT_NUMBER_INVALID;
661 InitializeListHead(&vport->ovsNameLink);
662 InitializeListHead(&vport->portIdLink);
663 InitializeListHead(&vport->portNoLink);
669 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
670 PNDIS_SWITCH_PORT_PARAMETERS portParam)
672 vport->portType = portParam->PortType;
673 vport->portState = portParam->PortState;
674 vport->portId = portParam->PortId;
675 vport->nicState = NdisSwitchNicStateUnknown;
676 vport->isExternal = FALSE;
677 vport->isBridgeInternal = FALSE;
679 switch (vport->portType) {
680 case NdisSwitchPortTypeExternal:
681 vport->isExternal = TRUE;
682 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
684 case NdisSwitchPortTypeInternal:
685 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
687 case NdisSwitchPortTypeSynthetic:
688 case NdisSwitchPortTypeEmulated:
689 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
692 RtlCopyMemory(&vport->hvPortName, &portParam->PortName,
693 sizeof (NDIS_SWITCH_PORT_NAME));
694 /* For external and internal ports, 'portFriendlyName' is overwritten
696 RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName,
697 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
699 switch (vport->portState) {
700 case NdisSwitchPortStateCreated:
701 vport->ovsState = OVS_STATE_PORT_CREATED;
703 case NdisSwitchPortStateTeardown:
704 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
706 case NdisSwitchPortStateDeleted:
707 vport->ovsState = OVS_STATE_PORT_DELETED;
714 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
715 POVS_VPORT_ENTRY vport,
716 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
718 ASSERT(vport->portId == nicParam->PortId);
719 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
721 UNREFERENCED_PARAMETER(switchContext);
723 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
724 sizeof (nicParam->PermanentMacAddress));
725 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
726 sizeof (nicParam->CurrentMacAddress));
728 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
729 nicParam->NicType == NdisSwitchNicTypeEmulated) {
730 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
731 sizeof (nicParam->VMMacAddress));
732 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
733 sizeof (nicParam->VmName));
735 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
736 sizeof (nicParam->NetCfgInstanceId));
738 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
739 sizeof (nicParam->NicName));
740 vport->mtu = nicParam->MTU;
741 vport->nicState = nicParam->NicState;
742 vport->nicIndex = nicParam->NicIndex;
743 vport->numaNodeId = nicParam->NumaNodeId;
745 switch (vport->nicState) {
746 case NdisSwitchNicStateCreated:
747 vport->ovsState = OVS_STATE_NIC_CREATED;
749 case NdisSwitchNicStateConnected:
750 vport->ovsState = OVS_STATE_CONNECTED;
752 case NdisSwitchNicStateDisconnected:
753 vport->ovsState = OVS_STATE_NIC_CREATED;
755 case NdisSwitchNicStateDeleted:
756 vport->ovsState = OVS_STATE_PORT_CREATED;
762 * --------------------------------------------------------------------------
763 * Copies the relevant NDIS port properties from a virtual (pseudo) external
764 * NIC to a physical (real) external NIC.
765 * --------------------------------------------------------------------------
768 OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVport,
769 POVS_VPORT_ENTRY virtExtVport,
772 physExtVport->portType = virtExtVport->portType;
773 physExtVport->portState = virtExtVport->portState;
774 physExtVport->portId = virtExtVport->portId;
775 physExtVport->nicState = NdisSwitchNicStateUnknown;
776 physExtVport->ovsType = OVS_VPORT_TYPE_NETDEV;
777 physExtVport->isExternal = TRUE;
778 physExtVport->isBridgeInternal = FALSE;
779 physExtVport->nicIndex = (NDIS_SWITCH_NIC_INDEX)physNicIndex;
781 RtlCopyMemory(&physExtVport->hvPortName, &virtExtVport->hvPortName,
782 sizeof (NDIS_SWITCH_PORT_NAME));
784 /* 'portFriendlyName' is overwritten later. */
785 RtlCopyMemory(&physExtVport->portFriendlyName,
786 &virtExtVport->portFriendlyName,
787 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
789 physExtVport->ovsState = OVS_STATE_PORT_CREATED;
793 * --------------------------------------------------------------------------
794 * Initializes a tunnel vport.
795 * --------------------------------------------------------------------------
798 OvsInitTunnelVport(POVS_VPORT_ENTRY vport,
799 OVS_VPORT_TYPE ovsType,
802 NTSTATUS status = STATUS_SUCCESS;
804 vport->isBridgeInternal = FALSE;
805 vport->ovsType = ovsType;
806 vport->ovsState = OVS_STATE_PORT_CREATED;
808 case OVS_VPORT_TYPE_GRE:
810 case OVS_VPORT_TYPE_GRE64:
812 case OVS_VPORT_TYPE_VXLAN:
813 status = OvsInitVxlanTunnel(vport, dstPort);
822 * --------------------------------------------------------------------------
823 * Initializes a bridge internal vport ie. a port of type
824 * OVS_VPORT_TYPE_INTERNAL but not present on the Hyper-V switch.
825 * --------------------------------------------------------------------------
828 OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport)
830 vport->isBridgeInternal = TRUE;
831 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
832 /* Mark the status to be connected, since there is no other initialization
834 vport->ovsState = OVS_STATE_CONNECTED;
835 return STATUS_SUCCESS;
839 * --------------------------------------------------------------------------
840 * For external vports 'portFriendlyName' provided by Hyper-V is over-written
841 * by synthetic names.
842 * --------------------------------------------------------------------------
845 AssignNicNameSpecial(POVS_VPORT_ENTRY vport)
849 if (vport->portType == NdisSwitchPortTypeExternal) {
850 if (vport->nicIndex == 0) {
851 ASSERT(vport->nicIndex == 0);
852 RtlStringCbPrintfW(vport->portFriendlyName.String,
854 L"%s.virtualAdapter", OVS_DPPORT_EXTERNAL_NAME_W);
856 RtlStringCbPrintfW(vport->portFriendlyName.String,
858 L"%s.%lu", OVS_DPPORT_EXTERNAL_NAME_W,
859 (UINT32)vport->nicIndex);
862 RtlStringCbPrintfW(vport->portFriendlyName.String,
864 L"%s", OVS_DPPORT_INTERNAL_NAME_W);
867 RtlStringCbLengthW(vport->portFriendlyName.String, IF_MAX_STRING_SIZE,
869 vport->portFriendlyName.Length = (USHORT)len;
874 * --------------------------------------------------------------------------
875 * Functionality common to any port on the Hyper-V switch. This function is not
876 * to be called for a port that is not on the Hyper-V switch.
878 * Inserts the port into 'portIdHashArray' and caches the pointer in the
879 * 'switchContext' if needed.
881 * For external NIC, assigns the name for the NIC.
882 * --------------------------------------------------------------------------
885 InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext,
886 POVS_VPORT_ENTRY vport)
889 ASSERT(vport->portNo == OVS_DPPORT_NUMBER_INVALID);
891 switch (vport->portType) {
892 case NdisSwitchPortTypeExternal:
894 * Overwrite the 'portFriendlyName' of this external vport. The reason
895 * for having this in common code is to be able to call it from the NDIS
896 * Port callback as well as the NDIS NIC callback.
898 AssignNicNameSpecial(vport);
900 if (vport->nicIndex == 0) {
901 switchContext->virtualExternalPortId = vport->portId;
902 switchContext->virtualExternalVport = vport;
904 switchContext->numPhysicalNics++;
907 case NdisSwitchPortTypeInternal:
908 ASSERT(vport->isBridgeInternal == FALSE);
910 /* Overwrite the 'portFriendlyName' of the internal vport. */
911 AssignNicNameSpecial(vport);
912 switchContext->internalPortId = vport->portId;
913 switchContext->internalVport = vport;
915 case NdisSwitchPortTypeSynthetic:
916 case NdisSwitchPortTypeEmulated:
921 * It is important to not insert vport corresponding to virtual external
922 * port into the 'portIdHashArray' since the port should not be exposed to
925 if (vport->portType == NdisSwitchPortTypeExternal &&
926 vport->nicIndex == 0) {
927 return NDIS_STATUS_SUCCESS;
931 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
932 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
933 * hyper-v switch seems to use only 2 bytes out of 4.
935 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
936 InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK],
938 switchContext->numHvVports++;
939 return NDIS_STATUS_SUCCESS;
943 * --------------------------------------------------------------------------
944 * Functionality common to any port added from OVS userspace.
946 * Inserts the port into 'portIdHashArray', 'ovsPortNameHashArray' and caches
947 * the pointer in the 'switchContext' if needed.
948 * --------------------------------------------------------------------------
951 InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext,
952 POVS_VPORT_ENTRY vport)
956 switch(vport->ovsType) {
957 case OVS_VPORT_TYPE_VXLAN:
958 ASSERT(switchContext->vxlanVport == NULL);
959 switchContext->vxlanVport = vport;
960 switchContext->numNonHvVports++;
962 case OVS_VPORT_TYPE_INTERNAL:
963 if (vport->isBridgeInternal) {
964 switchContext->numNonHvVports++;
971 * Insert the port into the hash array of ports: by port number and ovs
972 * and ovs (datapath) port name.
973 * NOTE: OvsJhashWords has portNo as "1" word. This is ok, because the
974 * portNo is stored in 2 bytes only (max port number = MAXUINT16).
976 hash = OvsJhashWords(&vport->portNo, 1, OVS_HASH_BASIS);
977 InsertHeadList(&gOvsSwitchContext->portNoHashArray[hash & OVS_VPORT_MASK],
980 hash = OvsJhashBytes(vport->ovsName, strlen(vport->ovsName) + 1,
982 InsertHeadList(&gOvsSwitchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK],
983 &vport->ovsNameLink);
985 return STATUS_SUCCESS;
990 * --------------------------------------------------------------------------
991 * Provides functionality that is partly complementatry to
992 * InitOvsVportCommon()/InitHvVportCommon().
993 * --------------------------------------------------------------------------
996 OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
997 POVS_VPORT_ENTRY vport)
999 BOOLEAN hvSwitchPort = FALSE;
1001 if (vport->isExternal) {
1002 if (vport->nicIndex == 0) {
1003 ASSERT(switchContext->numPhysicalNics == 0);
1004 switchContext->virtualExternalPortId = 0;
1005 switchContext->virtualExternalVport = NULL;
1006 OvsFreeMemory(vport);
1009 ASSERT(switchContext->numPhysicalNics);
1010 switchContext->numPhysicalNics--;
1011 hvSwitchPort = TRUE;
1015 switch (vport->ovsType) {
1016 case OVS_VPORT_TYPE_INTERNAL:
1017 if (!vport->isBridgeInternal) {
1018 switchContext->internalPortId = 0;
1019 switchContext->internalVport = NULL;
1020 OvsInternalAdapterDown();
1021 hvSwitchPort = TRUE;
1024 case OVS_VPORT_TYPE_VXLAN:
1025 OvsCleanupVxlanTunnel(vport);
1026 switchContext->vxlanVport = NULL;
1028 case OVS_VPORT_TYPE_GRE:
1029 case OVS_VPORT_TYPE_GRE64:
1031 case OVS_VPORT_TYPE_NETDEV:
1032 hvSwitchPort = TRUE;
1037 RemoveEntryList(&vport->ovsNameLink);
1038 RemoveEntryList(&vport->portIdLink);
1039 RemoveEntryList(&vport->portNoLink);
1041 switchContext->numHvVports--;
1043 switchContext->numNonHvVports--;
1045 OvsFreeMemory(vport);
1050 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
1052 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1054 PNDIS_SWITCH_PORT_PARAMETERS portParam;
1055 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
1056 POVS_VPORT_ENTRY vport;
1058 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
1060 status = OvsGetPortsOnSwitch(switchContext, &portArray);
1061 if (status != NDIS_STATUS_SUCCESS) {
1065 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
1066 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
1068 if (portParam->IsValidationPort) {
1072 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
1073 if (vport == NULL) {
1074 status = NDIS_STATUS_RESOURCES;
1077 OvsInitVportWithPortParam(vport, portParam);
1078 status = InitHvVportCommon(switchContext, vport);
1079 if (status != NDIS_STATUS_SUCCESS) {
1080 OvsFreeMemory(vport);
1085 if (status != NDIS_STATUS_SUCCESS) {
1086 OvsClearAllSwitchVports(switchContext);
1089 if (portArray != NULL) {
1090 OvsFreeMemory(portArray);
1092 OVS_LOG_TRACE("Exit: status: %x", status);
1098 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
1100 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1101 PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
1103 PNDIS_SWITCH_NIC_PARAMETERS nicParam;
1104 POVS_VPORT_ENTRY vport;
1106 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
1108 * Now, get NIC list.
1110 status = OvsGetNicsOnSwitch(switchContext, &nicArray);
1111 if (status != NDIS_STATUS_SUCCESS) {
1114 for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
1116 nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
1119 * XXX: Check if the port is configured with a VLAN. Disallow such a
1120 * configuration, since we don't support tag-in-tag.
1124 * XXX: Check if the port is connected to a VF. Disconnect the VF in
1128 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
1129 nicParam->NicIndex != 0) {
1130 POVS_VPORT_ENTRY virtExtVport =
1131 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
1133 vport = OvsAllocateVport();
1135 OvsInitPhysNicVport(vport, virtExtVport,
1136 nicParam->NicIndex);
1137 status = InitHvVportCommon(switchContext, vport);
1138 if (status != NDIS_STATUS_SUCCESS) {
1139 OvsFreeMemory(vport);
1144 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
1146 nicParam->NicIndex);
1148 if (vport == NULL) {
1149 OVS_LOG_ERROR("Fail to allocate vport");
1152 OvsInitVportWithNicParam(switchContext, vport, nicParam);
1153 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
1154 OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId);
1159 if (nicArray != NULL) {
1160 OvsFreeMemory(nicArray);
1162 OVS_LOG_TRACE("Exit: status: %x", status);
1167 * --------------------------------------------------------------------------
1168 * Deletes ports added from the Hyper-V switch as well as OVS usersapce. The
1169 * function deletes ports in 'portIdHashArray'. This will delete most of the
1170 * ports that are in the 'portNoHashArray' as well. Any remaining ports
1171 * are deleted by walking the the 'portNoHashArray'.
1172 * --------------------------------------------------------------------------
1175 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
1177 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
1178 PLIST_ENTRY head, link, next;
1180 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
1181 LIST_FORALL_SAFE(head, link, next) {
1182 POVS_VPORT_ENTRY vport;
1183 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
1184 OvsRemoveAndDeleteVport(switchContext, vport);
1188 * Remove 'virtualExternalVport' as well. This port is not part of the
1189 * 'portIdHashArray'.
1191 if (switchContext->virtualExternalVport) {
1192 OvsRemoveAndDeleteVport(switchContext,
1193 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport);
1196 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
1197 PLIST_ENTRY head, link, next;
1199 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
1200 LIST_FORALL_SAFE(head, link, next) {
1201 POVS_VPORT_ENTRY vport;
1202 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
1203 ASSERT(OvsIsTunnelVportType(vport->ovsType) ||
1204 (vport->ovsType == OVS_VPORT_TYPE_INTERNAL &&
1205 vport->isBridgeInternal));
1206 OvsRemoveAndDeleteVport(switchContext, vport);
1210 ASSERT(switchContext->virtualExternalVport == NULL);
1211 ASSERT(switchContext->internalVport == NULL);
1212 ASSERT(switchContext->vxlanVport == NULL);
1217 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
1222 UNICODE_STRING ustr;
1226 ustr.Buffer = wStr->String;
1227 ustr.Length = wStr->Length;
1228 ustr.MaximumLength = IF_MAX_STRING_SIZE;
1231 astr.MaximumLength = maxStrLen;
1234 size = RtlUnicodeStringToAnsiSize(&ustr);
1235 if (size > maxStrLen) {
1236 return STATUS_BUFFER_OVERFLOW;
1239 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
1241 ASSERT(status == STATUS_SUCCESS);
1242 if (status != STATUS_SUCCESS) {
1245 ASSERT(astr.Length <= maxStrLen);
1246 str[astr.Length] = 0;
1247 return STATUS_SUCCESS;
1251 * --------------------------------------------------------------------------
1252 * Utility function that populates a 'OVS_VPORT_EXT_INFO' structure for the
1255 * Assumes that 'gOvsCtrlLock' is held.
1256 * --------------------------------------------------------------------------
1259 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
1260 POVS_VPORT_EXT_INFO extInfo)
1262 POVS_VPORT_ENTRY vport;
1264 LOCK_STATE_EX lockState;
1265 NTSTATUS status = STATUS_SUCCESS;
1266 BOOLEAN doConvert = FALSE;
1268 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
1269 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
1270 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1271 NDIS_RWL_AT_DISPATCH_LEVEL);
1272 if (vportGet->portNo == 0) {
1273 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1274 vport = OvsFindVportByHvNameA(gOvsSwitchContext, vportGet->name);
1275 if (vport != NULL) {
1276 /* If the port is not a Hyper-V port and it has been added earlier,
1277 * we'll find it in 'ovsPortNameHashArray'. */
1278 vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name);
1281 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
1283 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1284 vport->ovsState != OVS_STATE_NIC_CREATED)) {
1285 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1286 if (vportGet->portNo) {
1287 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
1289 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
1291 status = STATUS_DEVICE_DOES_NOT_EXIST;
1294 extInfo->dpNo = vportGet->dpNo;
1295 extInfo->portNo = vport->portNo;
1296 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1297 sizeof (vport->currMacAddress));
1298 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1299 sizeof (vport->permMacAddress));
1300 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1301 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1302 sizeof (vport->vmMacAddress));
1304 extInfo->nicIndex = vport->nicIndex;
1305 extInfo->portId = vport->portId;
1306 extInfo->type = vport->ovsType;
1307 extInfo->mtu = vport->mtu;
1311 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1312 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1313 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
1314 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1316 extInfo->status = OVS_EVENT_DISCONNECT;
1318 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1319 (vport->ovsState == OVS_STATE_NIC_CREATED ||
1320 vport->ovsState == OVS_STATE_CONNECTED)) {
1323 extInfo->vmUUID[0] = 0;
1324 extInfo->vifUUID[0] = 0;
1326 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1328 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1330 OVS_MAX_PORT_NAME_LENGTH);
1331 if (status != STATUS_SUCCESS) {
1332 OVS_LOG_INFO("Fail to convert NIC name.");
1333 extInfo->vmUUID[0] = 0;
1336 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1338 OVS_MAX_VM_UUID_LEN);
1339 if (status != STATUS_SUCCESS) {
1340 OVS_LOG_INFO("Fail to convert VM name.");
1341 extInfo->vmUUID[0] = 0;
1344 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1346 OVS_MAX_VIF_UUID_LEN);
1347 if (status != STATUS_SUCCESS) {
1348 OVS_LOG_INFO("Fail to convert nic UUID");
1349 extInfo->vifUUID[0] = 0;
1352 * for now ignore status
1354 status = STATUS_SUCCESS;
1362 * --------------------------------------------------------------------------
1363 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1364 * --------------------------------------------------------------------------
1367 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1370 NTSTATUS status = STATUS_SUCCESS;
1371 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1372 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1373 NL_ERROR nlError = NL_ERROR_SUCCESS;
1374 OVS_VPORT_GET vportGet;
1375 OVS_VPORT_EXT_INFO info;
1377 static const NL_POLICY ovsNetdevPolicy[] = {
1378 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1380 .maxLen = IFNAMSIZ },
1382 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1384 /* input buffer has been validated while validating transaction dev op. */
1385 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1386 usrParamsCtx->inputLength > sizeof *msgIn);
1388 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1389 return STATUS_INVALID_BUFFER_SIZE;
1392 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1393 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1394 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1395 ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1396 return STATUS_INVALID_PARAMETER;
1399 OvsAcquireCtrlLock();
1401 vportGet.portNo = 0;
1402 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1403 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1405 status = OvsGetExtInfoIoctl(&vportGet, &info);
1406 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1407 nlError = NL_ERROR_NODEV;
1408 OvsReleaseCtrlLock();
1412 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1413 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1414 gOvsSwitchContext->dpNo);
1415 if (status == STATUS_SUCCESS) {
1416 *replyLen = msgOut->nlMsg.nlmsgLen;
1418 OvsReleaseCtrlLock();
1421 if (nlError != NL_ERROR_SUCCESS) {
1422 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1423 usrParamsCtx->outputBuffer;
1425 BuildErrorMsg(msgIn, msgError, nlError);
1426 *replyLen = msgError->nlMsg.nlmsgLen;
1429 return STATUS_SUCCESS;
1434 * --------------------------------------------------------------------------
1435 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1436 * OVS_MESSAGE contains the output of a netdev command.
1437 * --------------------------------------------------------------------------
1440 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1450 UINT32 netdevFlags = 0;
1452 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1454 BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1455 msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1457 ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1459 return STATUS_INSUFFICIENT_RESOURCES;
1462 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1465 return STATUS_INSUFFICIENT_RESOURCES;
1468 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1470 return STATUS_INSUFFICIENT_RESOURCES;
1473 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1476 return STATUS_INSUFFICIENT_RESOURCES;
1479 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1480 (PCHAR)info->macAddress, sizeof (info->macAddress));
1482 return STATUS_INSUFFICIENT_RESOURCES;
1485 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1487 return STATUS_INSUFFICIENT_RESOURCES;
1490 if (info->status != OVS_EVENT_CONNECT) {
1491 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1493 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1496 return STATUS_INSUFFICIENT_RESOURCES;
1500 * XXX: add netdev_stats when we have the definition available in the
1504 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1505 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1507 return STATUS_SUCCESS;
1510 static __inline VOID
1511 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1513 while ((!switchContext->isActivated) &&
1514 (!switchContext->isActivateFailed)) {
1515 /* Wait for the switch to be active and
1516 * the list of ports in OVS to be initialized. */
1517 NdisMSleep(sleepMicroSec);