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);
107 * Function updating the port properties
110 HvUpdatePort(POVS_SWITCH_CONTEXT switchContext,
111 PNDIS_SWITCH_PORT_PARAMETERS portParam)
113 POVS_VPORT_ENTRY vport;
114 LOCK_STATE_EX lockState;
115 OVS_VPORT_STATE ovsState;
116 NDIS_SWITCH_NIC_STATE nicState;
118 VPORT_PORT_ENTER(portParam);
120 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
121 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
122 portParam->PortId, 0);
124 * Update properties only for NETDEV ports for supprting PS script
125 * We don't allow changing the names of the internal or external ports
127 if (vport == NULL || ( vport->portType != NdisSwitchPortTypeSynthetic) ||
128 ( vport->portType != NdisSwitchPortTypeEmulated)) {
129 goto update_port_done;
132 /* Store the nic and the OVS states as Nic Create won't be called */
133 ovsState = vport->ovsState;
134 nicState = vport->nicState;
137 * Currently only the port friendly name is being updated
138 * Make sure that no other properties are changed
140 ASSERT(portParam->PortId == vport->portId);
141 ASSERT(portParam->PortState == vport->portState);
142 ASSERT(portParam->PortType == vport->portType);
145 * Call the set parameters function the handle all properties
146 * change in a single place in case future version supports change of
149 OvsInitVportWithPortParam(vport, portParam);
150 /* Retore the nic and OVS states */
151 vport->nicState = nicState;
152 vport->ovsState = ovsState;
155 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
156 VPORT_PORT_EXIT(portParam);
158 /* Must always return success */
159 return NDIS_STATUS_SUCCESS;
163 HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
164 PNDIS_SWITCH_PORT_PARAMETERS portParam)
166 POVS_VPORT_ENTRY vport;
167 LOCK_STATE_EX lockState;
169 VPORT_PORT_ENTER(portParam);
171 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
172 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
173 portParam->PortId, 0);
175 /* add assertion here
177 vport->portState = NdisSwitchPortStateTeardown;
178 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
180 OVS_LOG_WARN("Vport not present.");
182 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
184 VPORT_PORT_EXIT(portParam);
190 HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
191 PNDIS_SWITCH_PORT_PARAMETERS portParams)
193 POVS_VPORT_ENTRY vport;
194 LOCK_STATE_EX lockState;
196 VPORT_PORT_ENTER(portParams);
198 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
199 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
200 portParams->PortId, 0);
203 * XXX: we can only destroy and remove the port if its datapath port
204 * counterpart was deleted. If the datapath port counterpart is present,
205 * we only mark the vport for deletion, so that a netlink command vport
206 * delete will delete the vport.
209 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
210 OvsRemoveAndDeleteVport(switchContext, vport);
212 vport->hvDeleted = TRUE;
215 OVS_LOG_WARN("Vport not present.");
217 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
219 VPORT_PORT_EXIT(portParams);
224 * Functions implemented in relaton to NDIS NIC manipulation.
227 HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
228 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
230 POVS_VPORT_ENTRY vport;
233 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
235 LOCK_STATE_EX lockState;
237 VPORT_NIC_ENTER(nicParam);
239 /* Wait for lists to be initialized. */
240 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
242 if (!switchContext->isActivated) {
243 OVS_LOG_WARN("Switch is not activated yet.");
244 /* Veto the creation of nic */
245 status = NDIS_STATUS_NOT_SUPPORTED;
249 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
250 vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId, 0);
252 OVS_LOG_ERROR("Create NIC without Switch Port,"
253 " PortId: %x, NicIndex: %d",
254 nicParam->PortId, nicParam->NicIndex);
255 status = NDIS_STATUS_INVALID_PARAMETER;
259 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
260 nicParam->NicIndex != 0) {
261 POVS_VPORT_ENTRY virtExtVport =
262 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
264 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
266 status = NDIS_STATUS_RESOURCES;
269 OvsInitPhysNicVport(vport, virtExtVport, nicParam->NicIndex);
270 status = InitHvVportCommon(switchContext, vport);
271 if (status != NDIS_STATUS_SUCCESS) {
272 OvsFreeMemory(vport);
276 OvsInitVportWithNicParam(switchContext, vport, nicParam);
277 portNo = vport->portNo;
278 if (vport->ovsState == OVS_STATE_CONNECTED) {
279 event = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
280 } else if (vport->ovsState == OVS_STATE_NIC_CREATED) {
281 event = OVS_EVENT_CONNECT;
285 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
286 if (portNo != OVS_DPPORT_NUMBER_INVALID && event) {
287 OvsPostEvent(portNo, event);
291 VPORT_NIC_EXIT(nicParam);
292 OVS_LOG_TRACE("Exit: status %8x.\n", status);
298 /* Mark already created NIC as connected. */
300 HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
301 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
303 LOCK_STATE_EX lockState;
304 POVS_VPORT_ENTRY vport;
307 VPORT_NIC_ENTER(nicParam);
309 /* Wait for lists to be initialized. */
310 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
312 if (!switchContext->isActivated) {
313 OVS_LOG_WARN("Switch is not activated yet.");
317 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
318 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
323 OVS_LOG_WARN("Vport not present.");
324 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
329 vport->ovsState = OVS_STATE_CONNECTED;
330 vport->nicState = NdisSwitchNicStateConnected;
331 portNo = vport->portNo;
333 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
335 /* XXX only if portNo != INVALID or always? */
336 OvsPostEvent(portNo, OVS_EVENT_LINK_UP);
338 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
339 OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
343 VPORT_NIC_EXIT(nicParam);
347 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
348 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
350 POVS_VPORT_ENTRY vport;
351 LOCK_STATE_EX lockState;
353 UINT32 status = 0, portNo = 0;
355 VPORT_NIC_ENTER(nicParam);
357 /* Wait for lists to be initialized. */
358 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
360 if (!switchContext->isActivated) {
361 OVS_LOG_WARN("Switch is not activated yet.");
362 goto update_nic_done;
365 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
366 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
370 OVS_LOG_WARN("Vport search failed.");
371 goto update_nic_done;
373 switch (nicParam->NicType) {
374 case NdisSwitchNicTypeExternal:
375 case NdisSwitchNicTypeInternal:
376 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
379 case NdisSwitchNicTypeSynthetic:
380 case NdisSwitchNicTypeEmulated:
381 if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
382 sizeof (vport->vmMacAddress))) {
383 status |= OVS_EVENT_MAC_CHANGE;
384 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
385 sizeof (vport->vmMacAddress));
391 if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
392 sizeof (vport->permMacAddress))) {
393 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
394 sizeof (vport->permMacAddress));
395 status |= OVS_EVENT_MAC_CHANGE;
397 if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
398 sizeof (vport->currMacAddress))) {
399 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
400 sizeof (vport->currMacAddress));
401 status |= OVS_EVENT_MAC_CHANGE;
404 if (vport->mtu != nicParam->MTU) {
405 vport->mtu = nicParam->MTU;
406 status |= OVS_EVENT_MTU_CHANGE;
408 vport->numaNodeId = nicParam->NumaNodeId;
409 portNo = vport->portNo;
411 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
412 if (status && portNo) {
413 OvsPostEvent(portNo, status);
416 VPORT_NIC_EXIT(nicParam);
421 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
422 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
424 POVS_VPORT_ENTRY vport;
426 LOCK_STATE_EX lockState;
427 BOOLEAN isInternalPort = FALSE;
429 VPORT_NIC_ENTER(nicParam);
431 /* Wait for lists to be initialized. */
432 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
434 if (!switchContext->isActivated) {
435 OVS_LOG_WARN("Switch is not activated yet.");
439 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
440 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
445 OVS_LOG_WARN("Vport not present.");
446 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
450 vport->nicState = NdisSwitchNicStateDisconnected;
451 vport->ovsState = OVS_STATE_NIC_CREATED;
452 portNo = vport->portNo;
454 if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
455 isInternalPort = TRUE;
458 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
460 /* XXX if portNo != INVALID or always? */
461 OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
463 if (isInternalPort) {
464 OvsInternalAdapterDown();
468 VPORT_NIC_EXIT(nicParam);
473 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
474 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
476 LOCK_STATE_EX lockState;
477 POVS_VPORT_ENTRY vport;
480 VPORT_NIC_ENTER(nicParam);
481 /* Wait for lists to be initialized. */
482 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
484 if (!switchContext->isActivated) {
485 OVS_LOG_WARN("Switch is not activated yet.");
489 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
490 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
495 OVS_LOG_WARN("Vport not present.");
496 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
500 portNo = vport->portNo;
501 if (vport->portType == NdisSwitchPortTypeExternal &&
502 vport->nicIndex != 0) {
503 OvsRemoveAndDeleteVport(switchContext, vport);
505 vport->nicState = NdisSwitchNicStateUnknown;
506 vport->ovsState = OVS_STATE_PORT_CREATED;
508 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
509 /* XXX if portNo != INVALID or always? */
510 OvsPostEvent(portNo, OVS_EVENT_DISCONNECT);
513 VPORT_NIC_EXIT(nicParam);
518 * OVS Vport related functionality.
521 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
524 POVS_VPORT_ENTRY vport;
525 PLIST_ENTRY head, link;
526 UINT32 hash = OvsJhashBytes((const VOID *)&portNo, sizeof(portNo),
528 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
529 LIST_FORALL(head, link) {
530 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
531 if (vport->portNo == portNo) {
540 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
543 POVS_VPORT_ENTRY vport;
544 PLIST_ENTRY head, link;
546 SIZE_T length = strlen(name) + 1;
548 hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
549 head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
551 LIST_FORALL(head, link) {
552 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
553 if (!strcmp(name, vport->ovsName)) {
561 /* OvsFindVportByHvName: "name" is assumed to be null-terminated */
563 OvsFindVportByHvName(POVS_SWITCH_CONTEXT switchContext,
566 POVS_VPORT_ENTRY vport = NULL;
567 PLIST_ENTRY head, link;
568 /* 'portFriendlyName' is not NUL-terminated. */
569 SIZE_T length = strlen(name);
570 SIZE_T wstrSize = length * sizeof(WCHAR);
573 PWSTR wsName = OvsAllocateMemory(wstrSize);
577 for (i = 0; i < length; i++) {
581 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
582 head = &(switchContext->portIdHashArray[i]);
583 LIST_FORALL(head, link) {
584 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
587 * NOTE about portFriendlyName:
588 * If the string is NULL-terminated, the Length member does not
589 * include the terminating NULL character.
591 if (vport->portFriendlyName.Length == wstrSize &&
592 RtlEqualMemory(wsName, vport->portFriendlyName.String,
593 vport->portFriendlyName.Length)) {
602 OvsFreeMemory(wsName);
608 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
609 NDIS_SWITCH_PORT_ID portId,
610 NDIS_SWITCH_NIC_INDEX index)
612 if (switchContext->virtualExternalVport &&
613 portId == switchContext->virtualExternalPortId &&
614 index == switchContext->virtualExternalVport->nicIndex) {
615 return (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
616 } else if (switchContext->internalVport &&
617 portId == switchContext->internalPortId &&
618 index == switchContext->internalVport->nicIndex) {
619 return (POVS_VPORT_ENTRY)switchContext->internalVport;
621 PLIST_ENTRY head, link;
622 POVS_VPORT_ENTRY vport;
624 hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
625 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
626 LIST_FORALL(head, link) {
627 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
628 if (portId == vport->portId && index == vport->nicIndex) {
637 OvsAllocateVport(VOID)
639 POVS_VPORT_ENTRY vport;
640 vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY));
644 RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
645 vport->ovsState = OVS_STATE_UNKNOWN;
646 vport->hvDeleted = FALSE;
647 vport->portNo = OVS_DPPORT_NUMBER_INVALID;
649 InitializeListHead(&vport->ovsNameLink);
650 InitializeListHead(&vport->portIdLink);
651 InitializeListHead(&vport->portNoLink);
657 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
658 PNDIS_SWITCH_PORT_PARAMETERS portParam)
660 vport->portType = portParam->PortType;
661 vport->portState = portParam->PortState;
662 vport->portId = portParam->PortId;
663 vport->nicState = NdisSwitchNicStateUnknown;
664 vport->isExternal = FALSE;
665 vport->isBridgeInternal = FALSE;
667 switch (vport->portType) {
668 case NdisSwitchPortTypeExternal:
669 vport->isExternal = TRUE;
670 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
672 case NdisSwitchPortTypeInternal:
673 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
675 case NdisSwitchPortTypeSynthetic:
676 case NdisSwitchPortTypeEmulated:
677 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
680 RtlCopyMemory(&vport->hvPortName, &portParam->PortName,
681 sizeof (NDIS_SWITCH_PORT_NAME));
682 /* For external and internal ports, 'portFriendlyName' is overwritten
684 RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName,
685 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
687 switch (vport->portState) {
688 case NdisSwitchPortStateCreated:
689 vport->ovsState = OVS_STATE_PORT_CREATED;
691 case NdisSwitchPortStateTeardown:
692 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
694 case NdisSwitchPortStateDeleted:
695 vport->ovsState = OVS_STATE_PORT_DELETED;
702 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
703 POVS_VPORT_ENTRY vport,
704 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
706 ASSERT(vport->portId == nicParam->PortId);
707 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
709 UNREFERENCED_PARAMETER(switchContext);
711 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
712 sizeof (nicParam->PermanentMacAddress));
713 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
714 sizeof (nicParam->CurrentMacAddress));
716 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
717 nicParam->NicType == NdisSwitchNicTypeEmulated) {
718 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
719 sizeof (nicParam->VMMacAddress));
720 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
721 sizeof (nicParam->VmName));
723 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
724 sizeof (nicParam->NetCfgInstanceId));
726 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
727 sizeof (nicParam->NicName));
728 vport->mtu = nicParam->MTU;
729 vport->nicState = nicParam->NicState;
730 vport->nicIndex = nicParam->NicIndex;
731 vport->numaNodeId = nicParam->NumaNodeId;
733 switch (vport->nicState) {
734 case NdisSwitchNicStateCreated:
735 vport->ovsState = OVS_STATE_NIC_CREATED;
737 case NdisSwitchNicStateConnected:
738 vport->ovsState = OVS_STATE_CONNECTED;
740 case NdisSwitchNicStateDisconnected:
741 vport->ovsState = OVS_STATE_NIC_CREATED;
743 case NdisSwitchNicStateDeleted:
744 vport->ovsState = OVS_STATE_PORT_CREATED;
750 * --------------------------------------------------------------------------
751 * Copies the relevant NDIS port properties from a virtual (pseudo) external
752 * NIC to a physical (real) external NIC.
753 * --------------------------------------------------------------------------
756 OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVport,
757 POVS_VPORT_ENTRY virtExtVport,
760 physExtVport->portType = virtExtVport->portType;
761 physExtVport->portState = virtExtVport->portState;
762 physExtVport->portId = virtExtVport->portId;
763 physExtVport->nicState = NdisSwitchNicStateUnknown;
764 physExtVport->ovsType = OVS_VPORT_TYPE_NETDEV;
765 physExtVport->isExternal = TRUE;
766 physExtVport->isBridgeInternal = FALSE;
767 physExtVport->nicIndex = (NDIS_SWITCH_NIC_INDEX)physNicIndex;
769 RtlCopyMemory(&physExtVport->hvPortName, &virtExtVport->hvPortName,
770 sizeof (NDIS_SWITCH_PORT_NAME));
772 /* 'portFriendlyName' is overwritten later. */
773 RtlCopyMemory(&physExtVport->portFriendlyName,
774 &virtExtVport->portFriendlyName,
775 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
777 physExtVport->ovsState = OVS_STATE_PORT_CREATED;
781 * --------------------------------------------------------------------------
782 * Initializes a tunnel vport.
783 * --------------------------------------------------------------------------
786 OvsInitTunnelVport(POVS_VPORT_ENTRY vport,
787 OVS_VPORT_TYPE ovsType,
790 NTSTATUS status = STATUS_SUCCESS;
792 vport->isBridgeInternal = FALSE;
793 vport->ovsType = ovsType;
794 vport->ovsState = OVS_STATE_PORT_CREATED;
796 case OVS_VPORT_TYPE_GRE:
798 case OVS_VPORT_TYPE_GRE64:
800 case OVS_VPORT_TYPE_VXLAN:
801 status = OvsInitVxlanTunnel(vport, dstPort);
810 * --------------------------------------------------------------------------
811 * Initializes a bridge internal vport ie. a port of type
812 * OVS_VPORT_TYPE_INTERNAL but not present on the Hyper-V switch.
813 * --------------------------------------------------------------------------
816 OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport)
818 vport->isBridgeInternal = TRUE;
819 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
820 /* Mark the status to be connected, since there is no other initialization
822 vport->ovsState = OVS_STATE_CONNECTED;
823 return STATUS_SUCCESS;
827 * --------------------------------------------------------------------------
828 * For external vports 'portFriendlyName' provided by Hyper-V is over-written
829 * by synthetic names.
830 * --------------------------------------------------------------------------
833 AssignNicNameSpecial(POVS_VPORT_ENTRY vport)
837 if (vport->portType == NdisSwitchPortTypeExternal) {
838 if (vport->nicIndex == 0) {
839 ASSERT(vport->nicIndex == 0);
840 RtlStringCbPrintfW(vport->portFriendlyName.String,
842 L"%s.virtualAdapter", OVS_DPPORT_EXTERNAL_NAME_W);
844 RtlStringCbPrintfW(vport->portFriendlyName.String,
846 L"%s.%lu", OVS_DPPORT_EXTERNAL_NAME_W,
847 (UINT32)vport->nicIndex);
850 RtlStringCbPrintfW(vport->portFriendlyName.String,
852 L"%s", OVS_DPPORT_INTERNAL_NAME_W);
855 RtlStringCbLengthW(vport->portFriendlyName.String, IF_MAX_STRING_SIZE,
857 vport->portFriendlyName.Length = (USHORT)len;
862 * --------------------------------------------------------------------------
863 * Functionality common to any port on the Hyper-V switch. This function is not
864 * to be called for a port that is not on the Hyper-V switch.
866 * Inserts the port into 'portIdHashArray' and caches the pointer in the
867 * 'switchContext' if needed.
869 * For external NIC, assigns the name for the NIC.
870 * --------------------------------------------------------------------------
873 InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext,
874 POVS_VPORT_ENTRY vport)
877 ASSERT(vport->portNo == OVS_DPPORT_NUMBER_INVALID);
879 switch (vport->portType) {
880 case NdisSwitchPortTypeExternal:
882 * Overwrite the 'portFriendlyName' of this external vport. The reason
883 * for having this in common code is to be able to call it from the NDIS
884 * Port callback as well as the NDIS NIC callback.
886 AssignNicNameSpecial(vport);
888 if (vport->nicIndex == 0) {
889 switchContext->virtualExternalPortId = vport->portId;
890 switchContext->virtualExternalVport = vport;
892 switchContext->numPhysicalNics++;
895 case NdisSwitchPortTypeInternal:
896 ASSERT(vport->isBridgeInternal == FALSE);
898 /* Overwrite the 'portFriendlyName' of the internal vport. */
899 AssignNicNameSpecial(vport);
900 switchContext->internalPortId = vport->portId;
901 switchContext->internalVport = vport;
903 case NdisSwitchPortTypeSynthetic:
904 case NdisSwitchPortTypeEmulated:
909 * It is important to not insert vport corresponding to virtual external
910 * port into the 'portIdHashArray' since the port should not be exposed to
913 if (vport->portType == NdisSwitchPortTypeExternal &&
914 vport->nicIndex == 0) {
915 return NDIS_STATUS_SUCCESS;
919 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
920 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
921 * hyper-v switch seems to use only 2 bytes out of 4.
923 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
924 InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK],
926 switchContext->numHvVports++;
927 return NDIS_STATUS_SUCCESS;
931 * --------------------------------------------------------------------------
932 * Functionality common to any port added from OVS userspace.
934 * Inserts the port into 'portIdHashArray', 'ovsPortNameHashArray' and caches
935 * the pointer in the 'switchContext' if needed.
936 * --------------------------------------------------------------------------
939 InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext,
940 POVS_VPORT_ENTRY vport)
944 switch(vport->ovsType) {
945 case OVS_VPORT_TYPE_VXLAN:
946 ASSERT(switchContext->vxlanVport == NULL);
947 switchContext->vxlanVport = vport;
948 switchContext->numNonHvVports++;
950 case OVS_VPORT_TYPE_INTERNAL:
951 if (vport->isBridgeInternal) {
952 switchContext->numNonHvVports++;
959 * Insert the port into the hash array of ports: by port number and ovs
960 * and ovs (datapath) port name.
961 * NOTE: OvsJhashWords has portNo as "1" word. This is ok, because the
962 * portNo is stored in 2 bytes only (max port number = MAXUINT16).
964 hash = OvsJhashWords(&vport->portNo, 1, OVS_HASH_BASIS);
965 InsertHeadList(&gOvsSwitchContext->portNoHashArray[hash & OVS_VPORT_MASK],
968 hash = OvsJhashBytes(vport->ovsName, strlen(vport->ovsName) + 1,
970 InsertHeadList(&gOvsSwitchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK],
971 &vport->ovsNameLink);
973 return STATUS_SUCCESS;
978 * --------------------------------------------------------------------------
979 * Provides functionality that is partly complementatry to
980 * InitOvsVportCommon()/InitHvVportCommon().
981 * --------------------------------------------------------------------------
984 OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
985 POVS_VPORT_ENTRY vport)
987 BOOLEAN hvSwitchPort = FALSE;
989 if (vport->isExternal) {
990 if (vport->nicIndex == 0) {
991 ASSERT(switchContext->numPhysicalNics == 0);
992 switchContext->virtualExternalPortId = 0;
993 switchContext->virtualExternalVport = NULL;
994 OvsFreeMemory(vport);
997 ASSERT(switchContext->numPhysicalNics);
998 switchContext->numPhysicalNics--;
1003 switch (vport->ovsType) {
1004 case OVS_VPORT_TYPE_INTERNAL:
1005 if (!vport->isBridgeInternal) {
1006 switchContext->internalPortId = 0;
1007 switchContext->internalVport = NULL;
1008 OvsInternalAdapterDown();
1009 hvSwitchPort = TRUE;
1012 case OVS_VPORT_TYPE_VXLAN:
1013 OvsCleanupVxlanTunnel(vport);
1014 switchContext->vxlanVport = NULL;
1016 case OVS_VPORT_TYPE_GRE:
1017 case OVS_VPORT_TYPE_GRE64:
1019 case OVS_VPORT_TYPE_NETDEV:
1020 hvSwitchPort = TRUE;
1025 RemoveEntryList(&vport->ovsNameLink);
1026 RemoveEntryList(&vport->portIdLink);
1027 RemoveEntryList(&vport->portNoLink);
1029 switchContext->numHvVports--;
1031 switchContext->numNonHvVports--;
1033 OvsFreeMemory(vport);
1038 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
1040 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1042 PNDIS_SWITCH_PORT_PARAMETERS portParam;
1043 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
1044 POVS_VPORT_ENTRY vport;
1046 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
1048 status = OvsGetPortsOnSwitch(switchContext, &portArray);
1049 if (status != NDIS_STATUS_SUCCESS) {
1053 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
1054 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
1056 if (portParam->IsValidationPort) {
1060 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
1061 if (vport == NULL) {
1062 status = NDIS_STATUS_RESOURCES;
1065 OvsInitVportWithPortParam(vport, portParam);
1066 status = InitHvVportCommon(switchContext, vport);
1067 if (status != NDIS_STATUS_SUCCESS) {
1068 OvsFreeMemory(vport);
1073 if (status != NDIS_STATUS_SUCCESS) {
1074 OvsClearAllSwitchVports(switchContext);
1077 if (portArray != NULL) {
1078 OvsFreeMemory(portArray);
1080 OVS_LOG_TRACE("Exit: status: %x", status);
1086 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
1088 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1089 PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
1091 PNDIS_SWITCH_NIC_PARAMETERS nicParam;
1092 POVS_VPORT_ENTRY vport;
1094 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
1096 * Now, get NIC list.
1098 status = OvsGetNicsOnSwitch(switchContext, &nicArray);
1099 if (status != NDIS_STATUS_SUCCESS) {
1102 for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
1104 nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
1107 * XXX: Check if the port is configured with a VLAN. Disallow such a
1108 * configuration, since we don't support tag-in-tag.
1112 * XXX: Check if the port is connected to a VF. Disconnect the VF in
1116 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
1117 nicParam->NicIndex != 0) {
1118 POVS_VPORT_ENTRY virtExtVport =
1119 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
1121 vport = OvsAllocateVport();
1123 OvsInitPhysNicVport(vport, virtExtVport,
1124 nicParam->NicIndex);
1125 status = InitHvVportCommon(switchContext, vport);
1126 if (status != NDIS_STATUS_SUCCESS) {
1127 OvsFreeMemory(vport);
1132 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
1134 nicParam->NicIndex);
1136 if (vport == NULL) {
1137 OVS_LOG_ERROR("Fail to allocate vport");
1140 OvsInitVportWithNicParam(switchContext, vport, nicParam);
1141 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
1142 OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId);
1147 if (nicArray != NULL) {
1148 OvsFreeMemory(nicArray);
1150 OVS_LOG_TRACE("Exit: status: %x", status);
1155 * --------------------------------------------------------------------------
1156 * Deletes ports added from the Hyper-V switch as well as OVS usersapce. The
1157 * function deletes ports in 'portIdHashArray'. This will delete most of the
1158 * ports that are in the 'portNoHashArray' as well. Any remaining ports
1159 * are deleted by walking the the 'portNoHashArray'.
1160 * --------------------------------------------------------------------------
1163 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
1165 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
1166 PLIST_ENTRY head, link, next;
1168 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
1169 LIST_FORALL_SAFE(head, link, next) {
1170 POVS_VPORT_ENTRY vport;
1171 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
1172 OvsRemoveAndDeleteVport(switchContext, vport);
1176 * Remove 'virtualExternalVport' as well. This port is not part of the
1177 * 'portIdHashArray'.
1179 if (switchContext->virtualExternalVport) {
1180 OvsRemoveAndDeleteVport(switchContext,
1181 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport);
1184 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
1185 PLIST_ENTRY head, link, next;
1187 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
1188 LIST_FORALL_SAFE(head, link, next) {
1189 POVS_VPORT_ENTRY vport;
1190 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
1191 ASSERT(OvsIsTunnelVportType(vport->ovsType) ||
1192 (vport->ovsType == OVS_VPORT_TYPE_INTERNAL &&
1193 vport->isBridgeInternal));
1194 OvsRemoveAndDeleteVport(switchContext, vport);
1198 ASSERT(switchContext->virtualExternalVport == NULL);
1199 ASSERT(switchContext->internalVport == NULL);
1200 ASSERT(switchContext->vxlanVport == NULL);
1205 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
1210 UNICODE_STRING ustr;
1214 ustr.Buffer = wStr->String;
1215 ustr.Length = wStr->Length;
1216 ustr.MaximumLength = IF_MAX_STRING_SIZE;
1219 astr.MaximumLength = maxStrLen;
1222 size = RtlUnicodeStringToAnsiSize(&ustr);
1223 if (size > maxStrLen) {
1224 return STATUS_BUFFER_OVERFLOW;
1227 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
1229 ASSERT(status == STATUS_SUCCESS);
1230 if (status != STATUS_SUCCESS) {
1233 ASSERT(astr.Length <= maxStrLen);
1234 str[astr.Length] = 0;
1235 return STATUS_SUCCESS;
1240 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
1241 POVS_VPORT_EXT_INFO extInfo)
1243 POVS_VPORT_ENTRY vport;
1245 LOCK_STATE_EX lockState;
1246 NTSTATUS status = STATUS_SUCCESS;
1247 BOOLEAN doConvert = FALSE;
1249 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
1250 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1251 NDIS_RWL_AT_DISPATCH_LEVEL);
1252 if (vportGet->portNo == 0) {
1253 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1254 vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name);
1256 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
1258 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1259 vport->ovsState != OVS_STATE_NIC_CREATED)) {
1260 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1261 if (vportGet->portNo) {
1262 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
1264 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
1266 status = STATUS_DEVICE_DOES_NOT_EXIST;
1269 extInfo->dpNo = vportGet->dpNo;
1270 extInfo->portNo = vport->portNo;
1271 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1272 sizeof (vport->currMacAddress));
1273 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1274 sizeof (vport->permMacAddress));
1275 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1276 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1277 sizeof (vport->vmMacAddress));
1279 extInfo->nicIndex = vport->nicIndex;
1280 extInfo->portId = vport->portId;
1281 extInfo->type = vport->ovsType;
1282 extInfo->mtu = vport->mtu;
1286 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1287 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1288 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
1289 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1291 extInfo->status = OVS_EVENT_DISCONNECT;
1293 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1294 (vport->ovsState == OVS_STATE_NIC_CREATED ||
1295 vport->ovsState == OVS_STATE_CONNECTED)) {
1298 extInfo->vmUUID[0] = 0;
1299 extInfo->vifUUID[0] = 0;
1301 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1302 NdisReleaseSpinLock(gOvsCtrlLock);
1304 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1306 OVS_MAX_PORT_NAME_LENGTH);
1307 if (status != STATUS_SUCCESS) {
1308 OVS_LOG_INFO("Fail to convert NIC name.");
1309 extInfo->vmUUID[0] = 0;
1312 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1314 OVS_MAX_VM_UUID_LEN);
1315 if (status != STATUS_SUCCESS) {
1316 OVS_LOG_INFO("Fail to convert VM name.");
1317 extInfo->vmUUID[0] = 0;
1320 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1322 OVS_MAX_VIF_UUID_LEN);
1323 if (status != STATUS_SUCCESS) {
1324 OVS_LOG_INFO("Fail to convert nic UUID");
1325 extInfo->vifUUID[0] = 0;
1328 * for now ignore status
1330 status = STATUS_SUCCESS;
1338 * --------------------------------------------------------------------------
1339 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1340 * --------------------------------------------------------------------------
1343 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1346 NTSTATUS status = STATUS_SUCCESS;
1347 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1348 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1349 NL_ERROR nlError = NL_ERROR_SUCCESS;
1350 OVS_VPORT_GET vportGet;
1351 OVS_VPORT_EXT_INFO info;
1353 static const NL_POLICY ovsNetdevPolicy[] = {
1354 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1356 .maxLen = IFNAMSIZ },
1358 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1360 /* input buffer has been validated while validating transaction dev op. */
1361 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1362 usrParamsCtx->inputLength > sizeof *msgIn);
1364 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1365 return STATUS_INVALID_BUFFER_SIZE;
1368 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1369 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1370 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1371 ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1372 return STATUS_INVALID_PARAMETER;
1375 OvsAcquireCtrlLock();
1376 if (!gOvsSwitchContext) {
1377 OvsReleaseCtrlLock();
1378 return STATUS_INVALID_PARAMETER;
1381 vportGet.portNo = 0;
1382 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1383 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1385 status = OvsGetExtInfoIoctl(&vportGet, &info);
1386 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1387 nlError = NL_ERROR_NODEV;
1388 OvsReleaseCtrlLock();
1392 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1393 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1394 gOvsSwitchContext->dpNo);
1395 if (status == STATUS_SUCCESS) {
1396 *replyLen = msgOut->nlMsg.nlmsgLen;
1398 OvsReleaseCtrlLock();
1401 if (nlError != NL_ERROR_SUCCESS) {
1402 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1403 usrParamsCtx->outputBuffer;
1405 BuildErrorMsg(msgIn, msgError, nlError);
1406 *replyLen = msgError->nlMsg.nlmsgLen;
1409 return STATUS_SUCCESS;
1414 * --------------------------------------------------------------------------
1415 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1416 * OVS_MESSAGE contains the output of a netdev command.
1417 * --------------------------------------------------------------------------
1420 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1430 UINT32 netdevFlags = 0;
1432 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1434 BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1435 msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1437 ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1439 return STATUS_INSUFFICIENT_RESOURCES;
1442 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1445 return STATUS_INSUFFICIENT_RESOURCES;
1448 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1450 return STATUS_INSUFFICIENT_RESOURCES;
1453 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1456 return STATUS_INSUFFICIENT_RESOURCES;
1459 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1460 (PCHAR)info->macAddress, sizeof (info->macAddress));
1462 return STATUS_INSUFFICIENT_RESOURCES;
1465 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1467 return STATUS_INSUFFICIENT_RESOURCES;
1470 if (info->status != OVS_EVENT_CONNECT) {
1471 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1473 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1476 return STATUS_INSUFFICIENT_RESOURCES;
1480 * XXX: add netdev_stats when we have the definition available in the
1484 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1485 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1487 return STATUS_SUCCESS;
1490 static __inline VOID
1491 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1493 while ((!switchContext->isActivated) &&
1494 (!switchContext->isActivateFailed)) {
1495 /* Wait for the switch to be active and
1496 * the list of ports in OVS to be initialized. */
1497 NdisMSleep(sleepMicroSec);