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 vport, POVS_VPORT_ENTRY
58 virtVport, UINT32 nicIndex);
59 static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, POVS_VPORT_ENTRY
60 virtVport, UINT32 nicIndex);
61 static __inline VOID OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext,
63 static NTSTATUS OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
64 POVS_VPORT_EXT_INFO extInfo);
65 static NTSTATUS CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
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 OvsInitVportCommon(switchContext, vport);
102 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
103 VPORT_PORT_EXIT(portParam);
108 HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
109 PNDIS_SWITCH_PORT_PARAMETERS portParam)
111 POVS_VPORT_ENTRY vport;
112 LOCK_STATE_EX lockState;
114 VPORT_PORT_ENTER(portParam);
116 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
117 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
118 portParam->PortId, 0);
120 /* add assertion here
122 vport->portState = NdisSwitchPortStateTeardown;
123 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
125 OVS_LOG_WARN("Vport not present.");
127 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
129 VPORT_PORT_EXIT(portParam);
135 HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
136 PNDIS_SWITCH_PORT_PARAMETERS portParam)
138 POVS_VPORT_ENTRY vport;
139 LOCK_STATE_EX lockState;
141 VPORT_PORT_ENTER(portParam);
143 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
144 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
145 portParam->PortId, 0);
147 OvsRemoveAndDeleteVport(switchContext, vport);
149 OVS_LOG_WARN("Vport not present.");
151 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
153 VPORT_PORT_EXIT(portParam);
158 * Functions implemented in relaton to NDIS NIC manipulation.
161 HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
162 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
164 POVS_VPORT_ENTRY vport;
167 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
169 LOCK_STATE_EX lockState;
171 VPORT_NIC_ENTER(nicParam);
173 /* Wait for lists to be initialized. */
174 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
176 if (!switchContext->isActivated) {
177 OVS_LOG_WARN("Switch is not activated yet.");
178 /* Veto the creation of nic */
179 status = NDIS_STATUS_NOT_SUPPORTED;
183 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
184 vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId, 0);
186 OVS_LOG_ERROR("Create NIC without Switch Port,"
187 " PortId: %x, NicIndex: %d",
188 nicParam->PortId, nicParam->NicIndex);
189 status = NDIS_STATUS_INVALID_PARAMETER;
193 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
194 nicParam->NicIndex != 0) {
195 POVS_VPORT_ENTRY virtVport =
196 (POVS_VPORT_ENTRY)switchContext->externalVport;
197 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
199 status = NDIS_STATUS_RESOURCES;
202 OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex);
203 status = OvsInitVportCommon(switchContext, vport);
204 if (status != NDIS_STATUS_SUCCESS) {
205 OvsFreeMemory(vport);
209 OvsInitVportWithNicParam(switchContext, vport, nicParam);
210 portNo = vport->portNo;
211 if (vport->ovsState == OVS_STATE_CONNECTED) {
212 event = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
213 } else if (vport->ovsState == OVS_STATE_NIC_CREATED) {
214 event = OVS_EVENT_CONNECT;
218 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
219 if (portNo != OVS_DPPORT_NUMBER_INVALID && event) {
220 OvsPostEvent(portNo, event);
224 VPORT_NIC_EXIT(nicParam);
225 OVS_LOG_TRACE("Exit: status %8x.\n", status);
231 /* Mark already created NIC as connected. */
233 HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
234 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
236 LOCK_STATE_EX lockState;
237 POVS_VPORT_ENTRY vport;
240 VPORT_NIC_ENTER(nicParam);
242 /* Wait for lists to be initialized. */
243 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
245 if (!switchContext->isActivated) {
246 OVS_LOG_WARN("Switch is not activated yet.");
250 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
251 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
256 OVS_LOG_WARN("Vport not present.");
257 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
262 vport->ovsState = OVS_STATE_CONNECTED;
263 vport->nicState = NdisSwitchNicStateConnected;
264 portNo = vport->portNo;
266 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
268 /* XXX only if portNo != INVALID or always? */
269 OvsPostEvent(portNo, OVS_EVENT_LINK_UP);
271 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
272 OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
276 VPORT_NIC_EXIT(nicParam);
280 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
281 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
283 POVS_VPORT_ENTRY vport;
284 LOCK_STATE_EX lockState;
286 UINT32 status = 0, portNo = 0;
288 VPORT_NIC_ENTER(nicParam);
290 /* Wait for lists to be initialized. */
291 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
293 if (!switchContext->isActivated) {
294 OVS_LOG_WARN("Switch is not activated yet.");
295 goto update_nic_done;
298 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
299 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
303 OVS_LOG_WARN("Vport search failed.");
304 goto update_nic_done;
306 switch (nicParam->NicType) {
307 case NdisSwitchNicTypeExternal:
308 case NdisSwitchNicTypeInternal:
309 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
312 case NdisSwitchNicTypeSynthetic:
313 case NdisSwitchNicTypeEmulated:
314 if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
315 sizeof (vport->vmMacAddress))) {
316 status |= OVS_EVENT_MAC_CHANGE;
317 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
318 sizeof (vport->vmMacAddress));
324 if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
325 sizeof (vport->permMacAddress))) {
326 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
327 sizeof (vport->permMacAddress));
328 status |= OVS_EVENT_MAC_CHANGE;
330 if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
331 sizeof (vport->currMacAddress))) {
332 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
333 sizeof (vport->currMacAddress));
334 status |= OVS_EVENT_MAC_CHANGE;
337 if (vport->mtu != nicParam->MTU) {
338 vport->mtu = nicParam->MTU;
339 status |= OVS_EVENT_MTU_CHANGE;
341 vport->numaNodeId = nicParam->NumaNodeId;
342 portNo = vport->portNo;
344 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
345 if (status && portNo) {
346 OvsPostEvent(portNo, status);
349 VPORT_NIC_EXIT(nicParam);
354 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
355 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
357 POVS_VPORT_ENTRY vport;
359 LOCK_STATE_EX lockState;
360 BOOLEAN isInternalPort = FALSE;
362 VPORT_NIC_ENTER(nicParam);
364 /* Wait for lists to be initialized. */
365 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
367 if (!switchContext->isActivated) {
368 OVS_LOG_WARN("Switch is not activated yet.");
372 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
373 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
378 OVS_LOG_WARN("Vport not present.");
379 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
383 vport->nicState = NdisSwitchNicStateDisconnected;
384 vport->ovsState = OVS_STATE_NIC_CREATED;
385 portNo = vport->portNo;
387 if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
388 isInternalPort = TRUE;
391 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
393 /* XXX if portNo != INVALID or always? */
394 OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
396 if (isInternalPort) {
397 OvsInternalAdapterDown();
401 VPORT_NIC_EXIT(nicParam);
406 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
407 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
409 LOCK_STATE_EX lockState;
410 POVS_VPORT_ENTRY vport;
413 VPORT_NIC_ENTER(nicParam);
414 /* Wait for lists to be initialized. */
415 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
417 if (!switchContext->isActivated) {
418 OVS_LOG_WARN("Switch is not activated yet.");
422 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
423 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
428 OVS_LOG_WARN("Vport not present.");
429 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
433 portNo = vport->portNo;
434 if (vport->portType == NdisSwitchPortTypeExternal &&
435 vport->nicIndex != 0) {
436 OvsRemoveAndDeleteVport(switchContext, vport);
438 vport->nicState = NdisSwitchNicStateUnknown;
439 vport->ovsState = OVS_STATE_PORT_CREATED;
441 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
442 /* XXX if portNo != INVALID or always? */
443 OvsPostEvent(portNo, OVS_EVENT_DISCONNECT);
446 VPORT_NIC_EXIT(nicParam);
451 * OVS Vport related functionality.
454 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
457 POVS_VPORT_ENTRY vport;
458 PLIST_ENTRY head, link;
459 UINT32 hash = OvsJhashBytes((const VOID *)&portNo, sizeof(portNo),
461 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
462 LIST_FORALL(head, link) {
463 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
464 if (vport->portNo == portNo) {
473 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
476 POVS_VPORT_ENTRY vport;
477 PLIST_ENTRY head, link;
479 SIZE_T length = strlen(name) + 1;
481 hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
482 head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
484 LIST_FORALL(head, link) {
485 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
486 if (!strcmp(name, vport->ovsName)) {
494 /* OvsFindVportByHvName: "name" is assumed to be null-terminated */
496 OvsFindVportByHvName(POVS_SWITCH_CONTEXT switchContext,
499 POVS_VPORT_ENTRY vport = NULL;
500 PLIST_ENTRY head, link;
501 /* 'portFriendlyName' is not NUL-terminated. */
502 SIZE_T length = strlen(name);
503 SIZE_T wstrSize = length * sizeof(WCHAR);
505 PWSTR wsName = OvsAllocateMemory(wstrSize);
509 for (UINT i = 0; i < length; i) {
513 for (UINT32 i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i) {
514 head = &(switchContext->portIdHashArray[i]);
515 LIST_FORALL(head, link) {
516 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
519 * NOTE about portFriendlyName:
520 * If the string is NULL-terminated, the Length member does not
521 * include the terminating NULL character.
523 if (vport->portFriendlyName.Length == wstrSize &&
524 RtlEqualMemory(wsName, vport->portFriendlyName.String,
525 vport->portFriendlyName.Length)) {
534 OvsFreeMemory(wsName);
540 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
541 NDIS_SWITCH_PORT_ID portId,
542 NDIS_SWITCH_NIC_INDEX index)
544 if (portId == switchContext->externalPortId) {
545 return (POVS_VPORT_ENTRY)switchContext->externalVport;
546 } else if (switchContext->internalPortId == portId) {
547 return (POVS_VPORT_ENTRY)switchContext->internalVport;
549 PLIST_ENTRY head, link;
550 POVS_VPORT_ENTRY vport;
552 hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
553 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
554 LIST_FORALL(head, link) {
555 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
556 if (portId == vport->portId && index == vport->nicIndex) {
565 OvsAllocateVport(VOID)
567 POVS_VPORT_ENTRY vport;
568 vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY));
572 RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
573 vport->ovsState = OVS_STATE_UNKNOWN;
574 vport->hvDeleted = FALSE;
575 vport->portNo = OVS_DPPORT_NUMBER_INVALID;
577 InitializeListHead(&vport->ovsNameLink);
578 InitializeListHead(&vport->portIdLink);
579 InitializeListHead(&vport->portNoLink);
585 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
586 PNDIS_SWITCH_PORT_PARAMETERS portParam)
588 vport->portType = portParam->PortType;
589 vport->portState = portParam->PortState;
590 vport->portId = portParam->PortId;
591 vport->nicState = NdisSwitchNicStateUnknown;
592 vport->isExternal = FALSE;
594 switch (vport->portType) {
595 case NdisSwitchPortTypeExternal:
596 vport->isExternal = TRUE;
597 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
599 case NdisSwitchPortTypeInternal:
600 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
602 case NdisSwitchPortTypeSynthetic:
603 case NdisSwitchPortTypeEmulated:
604 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
607 RtlCopyMemory(&vport->hvPortName, &portParam->PortName,
608 sizeof (NDIS_SWITCH_PORT_NAME));
610 RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName,
611 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
613 switch (vport->portState) {
614 case NdisSwitchPortStateCreated:
615 vport->ovsState = OVS_STATE_PORT_CREATED;
617 case NdisSwitchPortStateTeardown:
618 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
620 case NdisSwitchPortStateDeleted:
621 vport->ovsState = OVS_STATE_PORT_DELETED;
628 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
629 POVS_VPORT_ENTRY vport,
630 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
632 ASSERT(vport->portId == nicParam->PortId);
633 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
635 UNREFERENCED_PARAMETER(switchContext);
637 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
638 sizeof (nicParam->PermanentMacAddress));
639 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
640 sizeof (nicParam->CurrentMacAddress));
642 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
643 nicParam->NicType == NdisSwitchNicTypeEmulated) {
644 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
645 sizeof (nicParam->VMMacAddress));
646 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
647 sizeof (nicParam->VmName));
649 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
650 sizeof (nicParam->NetCfgInstanceId));
652 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
653 sizeof (nicParam->NicName));
654 vport->mtu = nicParam->MTU;
655 vport->nicState = nicParam->NicState;
656 vport->nicIndex = nicParam->NicIndex;
657 vport->numaNodeId = nicParam->NumaNodeId;
659 switch (vport->nicState) {
660 case NdisSwitchNicStateCreated:
661 vport->ovsState = OVS_STATE_NIC_CREATED;
663 case NdisSwitchNicStateConnected:
664 vport->ovsState = OVS_STATE_CONNECTED;
666 case NdisSwitchNicStateDisconnected:
667 vport->ovsState = OVS_STATE_NIC_CREATED;
669 case NdisSwitchNicStateDeleted:
670 vport->ovsState = OVS_STATE_PORT_CREATED;
676 OvsInitPhysNicVport(POVS_VPORT_ENTRY vport,
677 POVS_VPORT_ENTRY virtVport,
680 vport->portType = virtVport->portType;
681 vport->portState = virtVport->portState;
682 vport->portId = virtVport->portId;
683 vport->nicState = NdisSwitchNicStateUnknown;
684 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
685 vport->isExternal = TRUE;
686 vport->nicIndex = (NDIS_SWITCH_NIC_INDEX)nicIndex;
688 RtlCopyMemory(&vport->hvPortName, &virtVport->hvPortName,
689 sizeof (NDIS_SWITCH_PORT_NAME));
691 RtlCopyMemory(&vport->portFriendlyName, &virtVport->portFriendlyName,
692 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
694 vport->ovsState = OVS_STATE_PORT_CREATED;
698 OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext,
699 POVS_VPORT_ENTRY vport)
702 ASSERT(vport->portNo == OVS_DPPORT_NUMBER_INVALID);
704 switch (vport->portType) {
705 case NdisSwitchPortTypeExternal:
706 if (vport->nicIndex == 0) {
707 switchContext->externalPortId = vport->portId;
708 switchContext->externalVport = vport;
709 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
710 "external.virtualAdapter");
712 switchContext->numPhysicalNics++;
713 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
714 "external.%lu", (UINT32)vport->nicIndex);
717 case NdisSwitchPortTypeInternal:
718 switchContext->internalPortId = vport->portId;
719 switchContext->internalVport = vport;
721 case NdisSwitchPortTypeSynthetic:
723 case NdisSwitchPortTypeEmulated:
727 if (vport->portType == NdisSwitchPortTypeExternal &&
728 vport->nicIndex == 0) {
729 return NDIS_STATUS_SUCCESS;
733 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
734 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
735 * hyper-v switch seems to use only 2 bytes out of 4.
737 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
738 InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK],
740 switchContext->numVports++;
741 return NDIS_STATUS_SUCCESS;
745 OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
746 POVS_VPORT_ENTRY vport)
748 if (vport->isExternal) {
749 if (vport->nicIndex == 0) {
750 ASSERT(switchContext->numPhysicalNics == 0);
751 switchContext->externalPortId = 0;
752 switchContext->externalVport = NULL;
753 OvsFreeMemory(vport);
756 ASSERT(switchContext->numPhysicalNics);
757 switchContext->numPhysicalNics--;
761 switch (vport->ovsType) {
762 case OVS_VPORT_TYPE_INTERNAL:
763 switchContext->internalPortId = 0;
764 switchContext->internalVport = NULL;
765 OvsInternalAdapterDown();
767 case OVS_VPORT_TYPE_VXLAN:
768 OvsCleanupVxlanTunnel(vport);
770 case OVS_VPORT_TYPE_GRE:
771 case OVS_VPORT_TYPE_GRE64:
773 case OVS_VPORT_TYPE_NETDEV:
778 RemoveEntryList(&vport->ovsNameLink);
779 RemoveEntryList(&vport->portIdLink);
780 RemoveEntryList(&vport->portNoLink);
781 switchContext->numVports--;
782 OvsFreeMemory(vport);
787 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
789 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
791 PNDIS_SWITCH_PORT_PARAMETERS portParam;
792 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
793 POVS_VPORT_ENTRY vport;
795 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
797 status = OvsGetPortsOnSwitch(switchContext, &portArray);
798 if (status != NDIS_STATUS_SUCCESS) {
802 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
803 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
805 if (portParam->IsValidationPort) {
809 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
811 status = NDIS_STATUS_RESOURCES;
814 OvsInitVportWithPortParam(vport, portParam);
815 status = OvsInitVportCommon(switchContext, vport);
816 if (status != NDIS_STATUS_SUCCESS) {
817 OvsFreeMemory(vport);
822 if (status != NDIS_STATUS_SUCCESS) {
823 OvsClearAllSwitchVports(switchContext);
826 if (portArray != NULL) {
827 OvsFreeMemory(portArray);
829 OVS_LOG_TRACE("Exit: status: %x", status);
835 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
837 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
838 PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
840 PNDIS_SWITCH_NIC_PARAMETERS nicParam;
841 POVS_VPORT_ENTRY vport;
843 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
847 status = OvsGetNicsOnSwitch(switchContext, &nicArray);
848 if (status != NDIS_STATUS_SUCCESS) {
851 for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
853 nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
856 * XXX: Check if the port is configured with a VLAN. Disallow such a
857 * configuration, since we don't support tag-in-tag.
861 * XXX: Check if the port is connected to a VF. Disconnect the VF in
865 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
866 nicParam->NicIndex != 0) {
867 POVS_VPORT_ENTRY virtVport =
868 (POVS_VPORT_ENTRY)switchContext->externalVport;
869 vport = OvsAllocateVport();
871 OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex);
872 status = OvsInitVportCommon(switchContext, vport);
873 if (status != NDIS_STATUS_SUCCESS) {
874 OvsFreeMemory(vport);
879 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
884 OVS_LOG_ERROR("Fail to allocate vport");
887 OvsInitVportWithNicParam(switchContext, vport, nicParam);
888 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
889 OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId);
894 if (nicArray != NULL) {
895 OvsFreeMemory(nicArray);
897 OVS_LOG_TRACE("Exit: status: %x", status);
902 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
904 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash) {
905 PLIST_ENTRY head, link;
907 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
908 LIST_FORALL(head, link) {
909 POVS_VPORT_ENTRY vport;
910 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
911 OvsRemoveAndDeleteVport(switchContext, vport);
915 if (switchContext->externalVport) {
916 OvsRemoveAndDeleteVport(switchContext,
917 (POVS_VPORT_ENTRY)switchContext->externalVport);
923 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
932 ustr.Buffer = wStr->String;
933 ustr.Length = wStr->Length;
934 ustr.MaximumLength = IF_MAX_STRING_SIZE;
937 astr.MaximumLength = maxStrLen;
940 size = RtlUnicodeStringToAnsiSize(&ustr);
941 if (size > maxStrLen) {
942 return STATUS_BUFFER_OVERFLOW;
945 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
947 ASSERT(status == STATUS_SUCCESS);
948 if (status != STATUS_SUCCESS) {
951 ASSERT(astr.Length <= maxStrLen);
952 str[astr.Length] = 0;
953 return STATUS_SUCCESS;
958 * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for
959 * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1.
961 #define USE_NEW_VPORT_ADD_WORKFLOW 1
963 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
964 POVS_VPORT_EXT_INFO extInfo)
966 POVS_VPORT_ENTRY vport;
968 LOCK_STATE_EX lockState;
969 NTSTATUS status = STATUS_SUCCESS;
970 BOOLEAN doConvert = FALSE;
972 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
973 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
974 NDIS_RWL_AT_DISPATCH_LEVEL);
975 if (vportGet->portNo == 0) {
976 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
977 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
978 vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name,
981 vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name);
984 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
986 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
987 vport->ovsState != OVS_STATE_NIC_CREATED)) {
988 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
989 NdisReleaseSpinLock(gOvsCtrlLock);
990 if (vportGet->portNo) {
991 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
993 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
995 status = STATUS_DEVICE_DOES_NOT_EXIST;
998 extInfo->dpNo = vportGet->dpNo;
999 extInfo->portNo = vport->portNo;
1000 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1001 sizeof (vport->currMacAddress));
1002 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1003 sizeof (vport->permMacAddress));
1004 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1005 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1006 sizeof (vport->vmMacAddress));
1008 extInfo->nicIndex = vport->nicIndex;
1009 extInfo->portId = vport->portId;
1010 extInfo->type = vport->ovsType;
1011 extInfo->mtu = vport->mtu;
1015 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1016 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1017 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
1018 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1020 extInfo->status = OVS_EVENT_DISCONNECT;
1022 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1023 (vport->ovsState == OVS_STATE_NIC_CREATED ||
1024 vport->ovsState == OVS_STATE_CONNECTED)) {
1027 extInfo->vmUUID[0] = 0;
1028 extInfo->vifUUID[0] = 0;
1030 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1031 RtlCopyMemory(extInfo->name, vport->ovsName, vport->ovsNameLen + 1);
1033 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1034 NdisReleaseSpinLock(gOvsCtrlLock);
1036 #if USE_NEW_VPORT_ADD_WORKFLOW == 1
1037 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1039 OVS_MAX_PORT_NAME_LENGTH);
1040 if (status != STATUS_SUCCESS) {
1041 OVS_LOG_INFO("Fail to convert NIC name.");
1042 extInfo->vmUUID[0] = 0;
1046 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1048 OVS_MAX_VM_UUID_LEN);
1049 if (status != STATUS_SUCCESS) {
1050 OVS_LOG_INFO("Fail to convert VM name.");
1051 extInfo->vmUUID[0] = 0;
1054 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1056 OVS_MAX_VIF_UUID_LEN);
1057 if (status != STATUS_SUCCESS) {
1058 OVS_LOG_INFO("Fail to convert nic UUID");
1059 extInfo->vifUUID[0] = 0;
1062 * for now ignore status
1064 status = STATUS_SUCCESS;
1072 * --------------------------------------------------------------------------
1073 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1074 * --------------------------------------------------------------------------
1077 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1080 NTSTATUS status = STATUS_SUCCESS;
1081 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1082 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1083 NL_ERROR nlError = NL_ERROR_SUCCESS;
1084 OVS_VPORT_GET vportGet;
1085 OVS_VPORT_EXT_INFO info;
1086 LOCK_STATE_EX lockState;
1088 static const NL_POLICY ovsNetdevPolicy[] = {
1089 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1091 .maxLen = IFNAMSIZ },
1093 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1095 /* input buffer has been validated while validating transaction dev op. */
1096 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1097 usrParamsCtx->inputLength > sizeof *msgIn);
1099 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1100 return STATUS_INVALID_BUFFER_SIZE;
1103 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1104 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1105 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1106 ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1107 return STATUS_INVALID_PARAMETER;
1110 OvsAcquireCtrlLock();
1111 if (!gOvsSwitchContext) {
1112 OvsReleaseCtrlLock();
1113 return STATUS_INVALID_PARAMETER;
1116 vportGet.portNo = 0;
1117 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1118 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1120 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1121 status = OvsGetExtInfoIoctl(&vportGet, &info);
1122 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1123 nlError = NL_ERROR_NODEV;
1124 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1125 OvsReleaseCtrlLock();
1128 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1130 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1131 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1132 gOvsSwitchContext->dpNo);
1133 if (status == STATUS_SUCCESS) {
1134 *replyLen = msgOut->nlMsg.nlmsgLen;
1136 OvsReleaseCtrlLock();
1139 if (nlError != NL_ERROR_SUCCESS) {
1140 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1141 usrParamsCtx->outputBuffer;
1143 BuildErrorMsg(msgIn, msgError, nlError);
1144 *replyLen = msgError->nlMsg.nlmsgLen;
1147 return STATUS_SUCCESS;
1152 * --------------------------------------------------------------------------
1153 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1154 * OVS_MESSAGE contains the output of a netdev command.
1155 * --------------------------------------------------------------------------
1158 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1168 UINT32 netdevFlags = 0;
1170 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1172 BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1173 msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1175 ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1177 return STATUS_INSUFFICIENT_RESOURCES;
1180 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1183 return STATUS_INSUFFICIENT_RESOURCES;
1186 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1188 return STATUS_INSUFFICIENT_RESOURCES;
1191 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1194 return STATUS_INSUFFICIENT_RESOURCES;
1197 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1198 (PCHAR)info->macAddress, sizeof (info->macAddress));
1200 return STATUS_INSUFFICIENT_RESOURCES;
1203 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1205 return STATUS_INSUFFICIENT_RESOURCES;
1208 if (info->status != OVS_EVENT_CONNECT) {
1209 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1211 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1214 return STATUS_INSUFFICIENT_RESOURCES;
1218 * XXX: add netdev_stats when we have the definition available in the
1222 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1223 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1225 return STATUS_SUCCESS;
1228 static __inline VOID
1229 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1231 while ((!switchContext->isActivated) &&
1232 (!switchContext->isActivateFailed)) {
1233 /* Wait for the switch to be active and
1234 * the list of ports in OVS to be initialized. */
1235 NdisMSleep(sleepMicroSec);