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,
70 * Functions implemented in relaton to NDIS port manipulation.
73 HvCreatePort(POVS_SWITCH_CONTEXT switchContext,
74 PNDIS_SWITCH_PORT_PARAMETERS portParam)
76 POVS_VPORT_ENTRY vport;
77 LOCK_STATE_EX lockState;
78 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
80 VPORT_PORT_ENTER(portParam);
82 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
83 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
84 portParam->PortId, 0);
85 if (vport != NULL && !vport->hvDeleted) {
86 status = STATUS_DATA_NOT_ACCEPTED;
87 goto create_port_done;
89 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
91 status = NDIS_STATUS_RESOURCES;
92 goto create_port_done;
96 OvsInitVportWithPortParam(vport, portParam);
97 InitHvVportCommon(switchContext, vport);
100 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
101 VPORT_PORT_EXIT(portParam);
106 HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
107 PNDIS_SWITCH_PORT_PARAMETERS portParam)
109 POVS_VPORT_ENTRY vport;
110 LOCK_STATE_EX lockState;
112 VPORT_PORT_ENTER(portParam);
114 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
115 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
116 portParam->PortId, 0);
118 /* add assertion here
120 vport->portState = NdisSwitchPortStateTeardown;
121 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
123 OVS_LOG_WARN("Vport not present.");
125 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
127 VPORT_PORT_EXIT(portParam);
133 HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
134 PNDIS_SWITCH_PORT_PARAMETERS portParams)
136 POVS_VPORT_ENTRY vport;
137 LOCK_STATE_EX lockState;
139 VPORT_PORT_ENTER(portParams);
141 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
142 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
143 portParams->PortId, 0);
146 * XXX: we can only destroy and remove the port if its datapath port
147 * counterpart was deleted. If the datapath port counterpart is present,
148 * we only mark the vport for deletion, so that a netlink command vport
149 * delete will delete the vport.
152 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
153 OvsRemoveAndDeleteVport(switchContext, vport);
155 vport->hvDeleted = TRUE;
158 OVS_LOG_WARN("Vport not present.");
160 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
162 VPORT_PORT_EXIT(portParams);
167 * Functions implemented in relaton to NDIS NIC manipulation.
170 HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
171 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
173 POVS_VPORT_ENTRY vport;
176 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
178 LOCK_STATE_EX lockState;
180 VPORT_NIC_ENTER(nicParam);
182 /* Wait for lists to be initialized. */
183 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
185 if (!switchContext->isActivated) {
186 OVS_LOG_WARN("Switch is not activated yet.");
187 /* Veto the creation of nic */
188 status = NDIS_STATUS_NOT_SUPPORTED;
192 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
193 vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId, 0);
195 OVS_LOG_ERROR("Create NIC without Switch Port,"
196 " PortId: %x, NicIndex: %d",
197 nicParam->PortId, nicParam->NicIndex);
198 status = NDIS_STATUS_INVALID_PARAMETER;
202 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
203 nicParam->NicIndex != 0) {
204 POVS_VPORT_ENTRY virtExtVport =
205 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
207 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
209 status = NDIS_STATUS_RESOURCES;
212 OvsInitPhysNicVport(vport, virtExtVport, nicParam->NicIndex);
213 status = InitHvVportCommon(switchContext, vport);
214 if (status != NDIS_STATUS_SUCCESS) {
215 OvsFreeMemory(vport);
219 OvsInitVportWithNicParam(switchContext, vport, nicParam);
220 portNo = vport->portNo;
221 if (vport->ovsState == OVS_STATE_CONNECTED) {
222 event = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
223 } else if (vport->ovsState == OVS_STATE_NIC_CREATED) {
224 event = OVS_EVENT_CONNECT;
228 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
229 if (portNo != OVS_DPPORT_NUMBER_INVALID && event) {
230 OvsPostEvent(portNo, event);
234 VPORT_NIC_EXIT(nicParam);
235 OVS_LOG_TRACE("Exit: status %8x.\n", status);
241 /* Mark already created NIC as connected. */
243 HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
244 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
246 LOCK_STATE_EX lockState;
247 POVS_VPORT_ENTRY vport;
250 VPORT_NIC_ENTER(nicParam);
252 /* Wait for lists to be initialized. */
253 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
255 if (!switchContext->isActivated) {
256 OVS_LOG_WARN("Switch is not activated yet.");
260 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
261 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
266 OVS_LOG_WARN("Vport not present.");
267 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
272 vport->ovsState = OVS_STATE_CONNECTED;
273 vport->nicState = NdisSwitchNicStateConnected;
274 portNo = vport->portNo;
276 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
278 /* XXX only if portNo != INVALID or always? */
279 OvsPostEvent(portNo, OVS_EVENT_LINK_UP);
281 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
282 OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
286 VPORT_NIC_EXIT(nicParam);
290 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
291 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
293 POVS_VPORT_ENTRY vport;
294 LOCK_STATE_EX lockState;
296 UINT32 status = 0, portNo = 0;
298 VPORT_NIC_ENTER(nicParam);
300 /* Wait for lists to be initialized. */
301 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
303 if (!switchContext->isActivated) {
304 OVS_LOG_WARN("Switch is not activated yet.");
305 goto update_nic_done;
308 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
309 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
313 OVS_LOG_WARN("Vport search failed.");
314 goto update_nic_done;
316 switch (nicParam->NicType) {
317 case NdisSwitchNicTypeExternal:
318 case NdisSwitchNicTypeInternal:
319 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
322 case NdisSwitchNicTypeSynthetic:
323 case NdisSwitchNicTypeEmulated:
324 if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
325 sizeof (vport->vmMacAddress))) {
326 status |= OVS_EVENT_MAC_CHANGE;
327 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
328 sizeof (vport->vmMacAddress));
334 if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
335 sizeof (vport->permMacAddress))) {
336 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
337 sizeof (vport->permMacAddress));
338 status |= OVS_EVENT_MAC_CHANGE;
340 if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
341 sizeof (vport->currMacAddress))) {
342 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
343 sizeof (vport->currMacAddress));
344 status |= OVS_EVENT_MAC_CHANGE;
347 if (vport->mtu != nicParam->MTU) {
348 vport->mtu = nicParam->MTU;
349 status |= OVS_EVENT_MTU_CHANGE;
351 vport->numaNodeId = nicParam->NumaNodeId;
352 portNo = vport->portNo;
354 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
355 if (status && portNo) {
356 OvsPostEvent(portNo, status);
359 VPORT_NIC_EXIT(nicParam);
364 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
365 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
367 POVS_VPORT_ENTRY vport;
369 LOCK_STATE_EX lockState;
370 BOOLEAN isInternalPort = FALSE;
372 VPORT_NIC_ENTER(nicParam);
374 /* Wait for lists to be initialized. */
375 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
377 if (!switchContext->isActivated) {
378 OVS_LOG_WARN("Switch is not activated yet.");
382 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
383 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
388 OVS_LOG_WARN("Vport not present.");
389 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
393 vport->nicState = NdisSwitchNicStateDisconnected;
394 vport->ovsState = OVS_STATE_NIC_CREATED;
395 portNo = vport->portNo;
397 if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
398 isInternalPort = TRUE;
401 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
403 /* XXX if portNo != INVALID or always? */
404 OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
406 if (isInternalPort) {
407 OvsInternalAdapterDown();
411 VPORT_NIC_EXIT(nicParam);
416 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
417 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
419 LOCK_STATE_EX lockState;
420 POVS_VPORT_ENTRY vport;
423 VPORT_NIC_ENTER(nicParam);
424 /* Wait for lists to be initialized. */
425 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
427 if (!switchContext->isActivated) {
428 OVS_LOG_WARN("Switch is not activated yet.");
432 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
433 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
438 OVS_LOG_WARN("Vport not present.");
439 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
443 portNo = vport->portNo;
444 if (vport->portType == NdisSwitchPortTypeExternal &&
445 vport->nicIndex != 0) {
446 OvsRemoveAndDeleteVport(switchContext, vport);
448 vport->nicState = NdisSwitchNicStateUnknown;
449 vport->ovsState = OVS_STATE_PORT_CREATED;
451 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
452 /* XXX if portNo != INVALID or always? */
453 OvsPostEvent(portNo, OVS_EVENT_DISCONNECT);
456 VPORT_NIC_EXIT(nicParam);
461 * OVS Vport related functionality.
464 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
467 POVS_VPORT_ENTRY vport;
468 PLIST_ENTRY head, link;
469 UINT32 hash = OvsJhashBytes((const VOID *)&portNo, sizeof(portNo),
471 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
472 LIST_FORALL(head, link) {
473 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
474 if (vport->portNo == portNo) {
483 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
486 POVS_VPORT_ENTRY vport;
487 PLIST_ENTRY head, link;
489 SIZE_T length = strlen(name) + 1;
491 hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
492 head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
494 LIST_FORALL(head, link) {
495 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
496 if (!strcmp(name, vport->ovsName)) {
504 /* OvsFindVportByHvName: "name" is assumed to be null-terminated */
506 OvsFindVportByHvName(POVS_SWITCH_CONTEXT switchContext,
509 POVS_VPORT_ENTRY vport = NULL;
510 PLIST_ENTRY head, link;
511 /* 'portFriendlyName' is not NUL-terminated. */
512 SIZE_T length = strlen(name);
513 SIZE_T wstrSize = length * sizeof(WCHAR);
516 PWSTR wsName = OvsAllocateMemory(wstrSize);
520 for (i = 0; i < length; i++) {
524 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
525 head = &(switchContext->portIdHashArray[i]);
526 LIST_FORALL(head, link) {
527 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
530 * NOTE about portFriendlyName:
531 * If the string is NULL-terminated, the Length member does not
532 * include the terminating NULL character.
534 if (vport->portFriendlyName.Length == wstrSize &&
535 RtlEqualMemory(wsName, vport->portFriendlyName.String,
536 vport->portFriendlyName.Length)) {
545 OvsFreeMemory(wsName);
551 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
552 NDIS_SWITCH_PORT_ID portId,
553 NDIS_SWITCH_NIC_INDEX index)
555 if (switchContext->virtualExternalVport &&
556 portId == switchContext->virtualExternalPortId &&
557 index == switchContext->virtualExternalVport->nicIndex) {
558 return (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
559 } else if (switchContext->internalVport &&
560 portId == switchContext->internalPortId &&
561 index == switchContext->internalVport->nicIndex) {
562 return (POVS_VPORT_ENTRY)switchContext->internalVport;
564 PLIST_ENTRY head, link;
565 POVS_VPORT_ENTRY vport;
567 hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
568 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
569 LIST_FORALL(head, link) {
570 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
571 if (portId == vport->portId && index == vport->nicIndex) {
580 OvsAllocateVport(VOID)
582 POVS_VPORT_ENTRY vport;
583 vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY));
587 RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
588 vport->ovsState = OVS_STATE_UNKNOWN;
589 vport->hvDeleted = FALSE;
590 vport->portNo = OVS_DPPORT_NUMBER_INVALID;
592 InitializeListHead(&vport->ovsNameLink);
593 InitializeListHead(&vport->portIdLink);
594 InitializeListHead(&vport->portNoLink);
600 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
601 PNDIS_SWITCH_PORT_PARAMETERS portParam)
603 vport->portType = portParam->PortType;
604 vport->portState = portParam->PortState;
605 vport->portId = portParam->PortId;
606 vport->nicState = NdisSwitchNicStateUnknown;
607 vport->isExternal = FALSE;
608 vport->isBridgeInternal = FALSE;
610 switch (vport->portType) {
611 case NdisSwitchPortTypeExternal:
612 vport->isExternal = TRUE;
613 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
615 case NdisSwitchPortTypeInternal:
616 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
618 case NdisSwitchPortTypeSynthetic:
619 case NdisSwitchPortTypeEmulated:
620 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
623 RtlCopyMemory(&vport->hvPortName, &portParam->PortName,
624 sizeof (NDIS_SWITCH_PORT_NAME));
625 /* For external and internal ports, 'portFriendlyName' is overwritten
627 RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName,
628 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
630 switch (vport->portState) {
631 case NdisSwitchPortStateCreated:
632 vport->ovsState = OVS_STATE_PORT_CREATED;
634 case NdisSwitchPortStateTeardown:
635 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
637 case NdisSwitchPortStateDeleted:
638 vport->ovsState = OVS_STATE_PORT_DELETED;
645 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
646 POVS_VPORT_ENTRY vport,
647 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
649 ASSERT(vport->portId == nicParam->PortId);
650 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
652 UNREFERENCED_PARAMETER(switchContext);
654 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
655 sizeof (nicParam->PermanentMacAddress));
656 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
657 sizeof (nicParam->CurrentMacAddress));
659 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
660 nicParam->NicType == NdisSwitchNicTypeEmulated) {
661 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
662 sizeof (nicParam->VMMacAddress));
663 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
664 sizeof (nicParam->VmName));
666 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
667 sizeof (nicParam->NetCfgInstanceId));
669 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
670 sizeof (nicParam->NicName));
671 vport->mtu = nicParam->MTU;
672 vport->nicState = nicParam->NicState;
673 vport->nicIndex = nicParam->NicIndex;
674 vport->numaNodeId = nicParam->NumaNodeId;
676 switch (vport->nicState) {
677 case NdisSwitchNicStateCreated:
678 vport->ovsState = OVS_STATE_NIC_CREATED;
680 case NdisSwitchNicStateConnected:
681 vport->ovsState = OVS_STATE_CONNECTED;
683 case NdisSwitchNicStateDisconnected:
684 vport->ovsState = OVS_STATE_NIC_CREATED;
686 case NdisSwitchNicStateDeleted:
687 vport->ovsState = OVS_STATE_PORT_CREATED;
693 * --------------------------------------------------------------------------
694 * Copies the relevant NDIS port properties from a virtual (pseudo) external
695 * NIC to a physical (real) external NIC.
696 * --------------------------------------------------------------------------
699 OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVport,
700 POVS_VPORT_ENTRY virtExtVport,
703 physExtVport->portType = virtExtVport->portType;
704 physExtVport->portState = virtExtVport->portState;
705 physExtVport->portId = virtExtVport->portId;
706 physExtVport->nicState = NdisSwitchNicStateUnknown;
707 physExtVport->ovsType = OVS_VPORT_TYPE_NETDEV;
708 physExtVport->isExternal = TRUE;
709 physExtVport->isBridgeInternal = FALSE;
710 physExtVport->nicIndex = (NDIS_SWITCH_NIC_INDEX)physNicIndex;
712 RtlCopyMemory(&physExtVport->hvPortName, &virtExtVport->hvPortName,
713 sizeof (NDIS_SWITCH_PORT_NAME));
715 /* 'portFriendlyName' is overwritten later. */
716 RtlCopyMemory(&physExtVport->portFriendlyName,
717 &virtExtVport->portFriendlyName,
718 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
720 physExtVport->ovsState = OVS_STATE_PORT_CREATED;
724 * --------------------------------------------------------------------------
725 * Initializes a tunnel vport.
726 * --------------------------------------------------------------------------
729 OvsInitTunnelVport(POVS_VPORT_ENTRY vport,
730 OVS_VPORT_TYPE ovsType,
733 NTSTATUS status = STATUS_SUCCESS;
735 vport->isBridgeInternal = FALSE;
736 vport->ovsType = ovsType;
737 vport->ovsState = OVS_STATE_PORT_CREATED;
739 case OVS_VPORT_TYPE_GRE:
741 case OVS_VPORT_TYPE_GRE64:
743 case OVS_VPORT_TYPE_VXLAN:
744 status = OvsInitVxlanTunnel(vport, dstPort);
753 * --------------------------------------------------------------------------
754 * Initializes a bridge internal vport ie. a port of type
755 * OVS_VPORT_TYPE_INTERNAL but not present on the Hyper-V switch.
756 * --------------------------------------------------------------------------
759 OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport)
761 vport->isBridgeInternal = TRUE;
762 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
763 /* Mark the status to be connected, since there is no other initialization
765 vport->ovsState = OVS_STATE_CONNECTED;
766 return STATUS_SUCCESS;
770 * --------------------------------------------------------------------------
771 * For external vports 'portFriendlyName' provided by Hyper-V is over-written
772 * by synthetic names.
773 * --------------------------------------------------------------------------
776 AssignNicNameSpecial(POVS_VPORT_ENTRY vport)
780 if (vport->portType == NdisSwitchPortTypeExternal) {
781 if (vport->nicIndex == 0) {
782 ASSERT(vport->nicIndex == 0);
783 RtlStringCbPrintfW(vport->portFriendlyName.String,
785 L"%s.virtualAdapter", OVS_DPPORT_EXTERNAL_NAME_W);
787 RtlStringCbPrintfW(vport->portFriendlyName.String,
789 L"%s.%lu", OVS_DPPORT_EXTERNAL_NAME_W,
790 (UINT32)vport->nicIndex);
793 RtlStringCbPrintfW(vport->portFriendlyName.String,
795 L"%s", OVS_DPPORT_INTERNAL_NAME_W);
798 RtlStringCbLengthW(vport->portFriendlyName.String, IF_MAX_STRING_SIZE,
800 vport->portFriendlyName.Length = (USHORT)len;
805 * --------------------------------------------------------------------------
806 * Functionality common to any port on the Hyper-V switch. This function is not
807 * to be called for a port that is not on the Hyper-V switch.
809 * Inserts the port into 'portIdHashArray' and caches the pointer in the
810 * 'switchContext' if needed.
812 * For external NIC, assigns the name for the NIC.
813 * --------------------------------------------------------------------------
816 InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext,
817 POVS_VPORT_ENTRY vport)
820 ASSERT(vport->portNo == OVS_DPPORT_NUMBER_INVALID);
822 switch (vport->portType) {
823 case NdisSwitchPortTypeExternal:
825 * Overwrite the 'portFriendlyName' of this external vport. The reason
826 * for having this in common code is to be able to call it from the NDIS
827 * Port callback as well as the NDIS NIC callback.
829 AssignNicNameSpecial(vport);
831 if (vport->nicIndex == 0) {
832 switchContext->virtualExternalPortId = vport->portId;
833 switchContext->virtualExternalVport = vport;
835 switchContext->numPhysicalNics++;
838 case NdisSwitchPortTypeInternal:
839 ASSERT(vport->isBridgeInternal == FALSE);
841 /* Overwrite the 'portFriendlyName' of the internal vport. */
842 AssignNicNameSpecial(vport);
843 switchContext->internalPortId = vport->portId;
844 switchContext->internalVport = vport;
846 case NdisSwitchPortTypeSynthetic:
847 case NdisSwitchPortTypeEmulated:
852 * It is important to not insert vport corresponding to virtual external
853 * port into the 'portIdHashArray' since the port should not be exposed to
856 if (vport->portType == NdisSwitchPortTypeExternal &&
857 vport->nicIndex == 0) {
858 return NDIS_STATUS_SUCCESS;
862 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
863 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
864 * hyper-v switch seems to use only 2 bytes out of 4.
866 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
867 InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK],
869 switchContext->numHvVports++;
870 return NDIS_STATUS_SUCCESS;
874 * --------------------------------------------------------------------------
875 * Functionality common to any port added from OVS userspace.
877 * Inserts the port into 'portIdHashArray', 'ovsPortNameHashArray' and caches
878 * the pointer in the 'switchContext' if needed.
879 * --------------------------------------------------------------------------
882 InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext,
883 POVS_VPORT_ENTRY vport)
887 switch(vport->ovsType) {
888 case OVS_VPORT_TYPE_VXLAN:
889 ASSERT(switchContext->vxlanVport == NULL);
890 switchContext->vxlanVport = vport;
891 switchContext->numNonHvVports++;
893 case OVS_VPORT_TYPE_INTERNAL:
894 if (vport->isBridgeInternal) {
895 switchContext->numNonHvVports++;
902 * Insert the port into the hash array of ports: by port number and ovs
903 * and ovs (datapath) port name.
904 * NOTE: OvsJhashWords has portNo as "1" word. This is ok, because the
905 * portNo is stored in 2 bytes only (max port number = MAXUINT16).
907 hash = OvsJhashWords(&vport->portNo, 1, OVS_HASH_BASIS);
908 InsertHeadList(&gOvsSwitchContext->portNoHashArray[hash & OVS_VPORT_MASK],
911 hash = OvsJhashBytes(vport->ovsName, strlen(vport->ovsName) + 1,
913 InsertHeadList(&gOvsSwitchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK],
914 &vport->ovsNameLink);
916 return STATUS_SUCCESS;
921 * --------------------------------------------------------------------------
922 * Provides functionality that is partly complementatry to
923 * InitOvsVportCommon()/InitHvVportCommon().
924 * --------------------------------------------------------------------------
927 OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
928 POVS_VPORT_ENTRY vport)
930 BOOLEAN hvSwitchPort = FALSE;
932 if (vport->isExternal) {
933 if (vport->nicIndex == 0) {
934 ASSERT(switchContext->numPhysicalNics == 0);
935 switchContext->virtualExternalPortId = 0;
936 switchContext->virtualExternalVport = NULL;
937 OvsFreeMemory(vport);
940 ASSERT(switchContext->numPhysicalNics);
941 switchContext->numPhysicalNics--;
946 switch (vport->ovsType) {
947 case OVS_VPORT_TYPE_INTERNAL:
948 if (!vport->isBridgeInternal) {
949 switchContext->internalPortId = 0;
950 switchContext->internalVport = NULL;
951 OvsInternalAdapterDown();
955 case OVS_VPORT_TYPE_VXLAN:
956 OvsCleanupVxlanTunnel(vport);
957 switchContext->vxlanVport = NULL;
959 case OVS_VPORT_TYPE_GRE:
960 case OVS_VPORT_TYPE_GRE64:
962 case OVS_VPORT_TYPE_NETDEV:
968 RemoveEntryList(&vport->ovsNameLink);
969 RemoveEntryList(&vport->portIdLink);
970 RemoveEntryList(&vport->portNoLink);
972 switchContext->numHvVports--;
974 switchContext->numNonHvVports--;
976 OvsFreeMemory(vport);
981 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
983 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
985 PNDIS_SWITCH_PORT_PARAMETERS portParam;
986 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
987 POVS_VPORT_ENTRY vport;
989 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
991 status = OvsGetPortsOnSwitch(switchContext, &portArray);
992 if (status != NDIS_STATUS_SUCCESS) {
996 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
997 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
999 if (portParam->IsValidationPort) {
1003 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
1004 if (vport == NULL) {
1005 status = NDIS_STATUS_RESOURCES;
1008 OvsInitVportWithPortParam(vport, portParam);
1009 status = InitHvVportCommon(switchContext, vport);
1010 if (status != NDIS_STATUS_SUCCESS) {
1011 OvsFreeMemory(vport);
1016 if (status != NDIS_STATUS_SUCCESS) {
1017 OvsClearAllSwitchVports(switchContext);
1020 if (portArray != NULL) {
1021 OvsFreeMemory(portArray);
1023 OVS_LOG_TRACE("Exit: status: %x", status);
1029 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
1031 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1032 PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
1034 PNDIS_SWITCH_NIC_PARAMETERS nicParam;
1035 POVS_VPORT_ENTRY vport;
1037 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
1039 * Now, get NIC list.
1041 status = OvsGetNicsOnSwitch(switchContext, &nicArray);
1042 if (status != NDIS_STATUS_SUCCESS) {
1045 for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
1047 nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
1050 * XXX: Check if the port is configured with a VLAN. Disallow such a
1051 * configuration, since we don't support tag-in-tag.
1055 * XXX: Check if the port is connected to a VF. Disconnect the VF in
1059 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
1060 nicParam->NicIndex != 0) {
1061 POVS_VPORT_ENTRY virtExtVport =
1062 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
1064 vport = OvsAllocateVport();
1066 OvsInitPhysNicVport(vport, virtExtVport,
1067 nicParam->NicIndex);
1068 status = InitHvVportCommon(switchContext, vport);
1069 if (status != NDIS_STATUS_SUCCESS) {
1070 OvsFreeMemory(vport);
1075 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
1077 nicParam->NicIndex);
1079 if (vport == NULL) {
1080 OVS_LOG_ERROR("Fail to allocate vport");
1083 OvsInitVportWithNicParam(switchContext, vport, nicParam);
1084 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
1085 OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId);
1090 if (nicArray != NULL) {
1091 OvsFreeMemory(nicArray);
1093 OVS_LOG_TRACE("Exit: status: %x", status);
1098 * --------------------------------------------------------------------------
1099 * Deletes ports added from the Hyper-V switch as well as OVS usersapce. The
1100 * function deletes ports in 'portIdHashArray'. This will delete most of the
1101 * ports that are in the 'portNoHashArray' as well. Any remaining ports
1102 * are deleted by walking the the 'portNoHashArray'.
1103 * --------------------------------------------------------------------------
1106 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
1108 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
1109 PLIST_ENTRY head, link, next;
1111 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
1112 LIST_FORALL_SAFE(head, link, next) {
1113 POVS_VPORT_ENTRY vport;
1114 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
1115 OvsRemoveAndDeleteVport(switchContext, vport);
1119 * Remove 'virtualExternalVport' as well. This port is not part of the
1120 * 'portIdHashArray'.
1122 if (switchContext->virtualExternalVport) {
1123 OvsRemoveAndDeleteVport(switchContext,
1124 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport);
1127 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
1128 PLIST_ENTRY head, link, next;
1130 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
1131 LIST_FORALL_SAFE(head, link, next) {
1132 POVS_VPORT_ENTRY vport;
1133 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
1134 ASSERT(OvsIsTunnelVportType(vport->ovsType) ||
1135 (vport->ovsType == OVS_VPORT_TYPE_INTERNAL &&
1136 vport->isBridgeInternal));
1137 OvsRemoveAndDeleteVport(switchContext, vport);
1141 ASSERT(switchContext->virtualExternalVport == NULL);
1142 ASSERT(switchContext->internalVport == NULL);
1143 ASSERT(switchContext->vxlanVport == NULL);
1148 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
1153 UNICODE_STRING ustr;
1157 ustr.Buffer = wStr->String;
1158 ustr.Length = wStr->Length;
1159 ustr.MaximumLength = IF_MAX_STRING_SIZE;
1162 astr.MaximumLength = maxStrLen;
1165 size = RtlUnicodeStringToAnsiSize(&ustr);
1166 if (size > maxStrLen) {
1167 return STATUS_BUFFER_OVERFLOW;
1170 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
1172 ASSERT(status == STATUS_SUCCESS);
1173 if (status != STATUS_SUCCESS) {
1176 ASSERT(astr.Length <= maxStrLen);
1177 str[astr.Length] = 0;
1178 return STATUS_SUCCESS;
1183 * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for
1184 * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1.
1186 #define USE_NEW_VPORT_ADD_WORKFLOW 1
1188 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
1189 POVS_VPORT_EXT_INFO extInfo)
1191 POVS_VPORT_ENTRY vport;
1193 LOCK_STATE_EX lockState;
1194 NTSTATUS status = STATUS_SUCCESS;
1195 BOOLEAN doConvert = FALSE;
1197 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
1198 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1199 NDIS_RWL_AT_DISPATCH_LEVEL);
1200 if (vportGet->portNo == 0) {
1201 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1202 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1203 vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name,
1206 vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name);
1209 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
1211 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1212 vport->ovsState != OVS_STATE_NIC_CREATED)) {
1213 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1214 NdisReleaseSpinLock(gOvsCtrlLock);
1215 if (vportGet->portNo) {
1216 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
1218 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
1220 status = STATUS_DEVICE_DOES_NOT_EXIST;
1223 extInfo->dpNo = vportGet->dpNo;
1224 extInfo->portNo = vport->portNo;
1225 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1226 sizeof (vport->currMacAddress));
1227 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1228 sizeof (vport->permMacAddress));
1229 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1230 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1231 sizeof (vport->vmMacAddress));
1233 extInfo->nicIndex = vport->nicIndex;
1234 extInfo->portId = vport->portId;
1235 extInfo->type = vport->ovsType;
1236 extInfo->mtu = vport->mtu;
1240 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1241 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1242 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
1243 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1245 extInfo->status = OVS_EVENT_DISCONNECT;
1247 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1248 (vport->ovsState == OVS_STATE_NIC_CREATED ||
1249 vport->ovsState == OVS_STATE_CONNECTED)) {
1252 extInfo->vmUUID[0] = 0;
1253 extInfo->vifUUID[0] = 0;
1255 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1256 RtlCopyMemory(extInfo->name, vport->ovsName, vport->ovsNameLen + 1);
1258 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1259 NdisReleaseSpinLock(gOvsCtrlLock);
1261 #if USE_NEW_VPORT_ADD_WORKFLOW == 1
1262 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1264 OVS_MAX_PORT_NAME_LENGTH);
1265 if (status != STATUS_SUCCESS) {
1266 OVS_LOG_INFO("Fail to convert NIC name.");
1267 extInfo->vmUUID[0] = 0;
1271 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1273 OVS_MAX_VM_UUID_LEN);
1274 if (status != STATUS_SUCCESS) {
1275 OVS_LOG_INFO("Fail to convert VM name.");
1276 extInfo->vmUUID[0] = 0;
1279 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1281 OVS_MAX_VIF_UUID_LEN);
1282 if (status != STATUS_SUCCESS) {
1283 OVS_LOG_INFO("Fail to convert nic UUID");
1284 extInfo->vifUUID[0] = 0;
1287 * for now ignore status
1289 status = STATUS_SUCCESS;
1297 * --------------------------------------------------------------------------
1298 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1299 * --------------------------------------------------------------------------
1302 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1305 NTSTATUS status = STATUS_SUCCESS;
1306 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1307 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1308 NL_ERROR nlError = NL_ERROR_SUCCESS;
1309 OVS_VPORT_GET vportGet;
1310 OVS_VPORT_EXT_INFO info;
1311 LOCK_STATE_EX lockState;
1313 static const NL_POLICY ovsNetdevPolicy[] = {
1314 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1316 .maxLen = IFNAMSIZ },
1318 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1320 /* input buffer has been validated while validating transaction dev op. */
1321 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1322 usrParamsCtx->inputLength > sizeof *msgIn);
1324 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1325 return STATUS_INVALID_BUFFER_SIZE;
1328 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1329 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1330 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1331 ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1332 return STATUS_INVALID_PARAMETER;
1335 OvsAcquireCtrlLock();
1336 if (!gOvsSwitchContext) {
1337 OvsReleaseCtrlLock();
1338 return STATUS_INVALID_PARAMETER;
1341 vportGet.portNo = 0;
1342 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1343 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1345 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1346 status = OvsGetExtInfoIoctl(&vportGet, &info);
1347 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1348 nlError = NL_ERROR_NODEV;
1349 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1350 OvsReleaseCtrlLock();
1353 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1355 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1356 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1357 gOvsSwitchContext->dpNo);
1358 if (status == STATUS_SUCCESS) {
1359 *replyLen = msgOut->nlMsg.nlmsgLen;
1361 OvsReleaseCtrlLock();
1364 if (nlError != NL_ERROR_SUCCESS) {
1365 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1366 usrParamsCtx->outputBuffer;
1368 BuildErrorMsg(msgIn, msgError, nlError);
1369 *replyLen = msgError->nlMsg.nlmsgLen;
1372 return STATUS_SUCCESS;
1377 * --------------------------------------------------------------------------
1378 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1379 * OVS_MESSAGE contains the output of a netdev command.
1380 * --------------------------------------------------------------------------
1383 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1393 UINT32 netdevFlags = 0;
1395 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1397 BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1398 msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1400 ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1402 return STATUS_INSUFFICIENT_RESOURCES;
1405 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1408 return STATUS_INSUFFICIENT_RESOURCES;
1411 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1413 return STATUS_INSUFFICIENT_RESOURCES;
1416 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1419 return STATUS_INSUFFICIENT_RESOURCES;
1422 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1423 (PCHAR)info->macAddress, sizeof (info->macAddress));
1425 return STATUS_INSUFFICIENT_RESOURCES;
1428 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1430 return STATUS_INSUFFICIENT_RESOURCES;
1433 if (info->status != OVS_EVENT_CONNECT) {
1434 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1436 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1439 return STATUS_INSUFFICIENT_RESOURCES;
1443 * XXX: add netdev_stats when we have the definition available in the
1447 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1448 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1450 return STATUS_SUCCESS;
1453 static __inline VOID
1454 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1456 while ((!switchContext->isActivated) &&
1457 (!switchContext->isActivateFailed)) {
1458 /* Wait for the switch to be active and
1459 * the list of ports in OVS to be initialized. */
1460 NdisMSleep(sleepMicroSec);