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 UINT32 OvsGetVportNo(POVS_SWITCH_CONTEXT switchContext, UINT32 nicIndex,
54 OVS_VPORT_TYPE ovsType,
56 static POVS_VPORT_ENTRY OvsAllocateVport(VOID);
57 static VOID OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
58 PNDIS_SWITCH_PORT_PARAMETERS portParam);
59 static VOID OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
60 POVS_VPORT_ENTRY vport, PNDIS_SWITCH_NIC_PARAMETERS nicParam);
61 static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, POVS_VPORT_ENTRY
62 virtVport, UINT32 nicIndex);
63 static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, POVS_VPORT_ENTRY
64 virtVport, UINT32 nicIndex);
65 static NDIS_STATUS OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext,
66 POVS_VPORT_ENTRY vport);
67 static VOID OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
68 POVS_VPORT_ENTRY vport);
69 static __inline VOID OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext,
71 static NTSTATUS OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
72 POVS_VPORT_EXT_INFO extInfo);
73 static NTSTATUS CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
80 * Functions implemented in relaton to NDIS port manipulation.
83 HvCreatePort(POVS_SWITCH_CONTEXT switchContext,
84 PNDIS_SWITCH_PORT_PARAMETERS portParam)
86 POVS_VPORT_ENTRY vport;
87 LOCK_STATE_EX lockState;
88 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
90 VPORT_PORT_ENTER(portParam);
92 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
93 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
94 portParam->PortId, 0);
96 status = STATUS_DATA_NOT_ACCEPTED;
97 goto create_port_done;
99 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
101 status = NDIS_STATUS_RESOURCES;
102 goto create_port_done;
104 OvsInitVportWithPortParam(vport, portParam);
105 OvsInitVportCommon(switchContext, vport);
108 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
109 VPORT_PORT_EXIT(portParam);
114 HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
115 PNDIS_SWITCH_PORT_PARAMETERS portParam)
117 POVS_VPORT_ENTRY vport;
118 LOCK_STATE_EX lockState;
120 VPORT_PORT_ENTER(portParam);
122 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
123 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
124 portParam->PortId, 0);
126 /* add assertion here
128 vport->portState = NdisSwitchPortStateTeardown;
129 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
131 OVS_LOG_WARN("Vport not present.");
133 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
135 VPORT_PORT_EXIT(portParam);
141 HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
142 PNDIS_SWITCH_PORT_PARAMETERS portParam)
144 POVS_VPORT_ENTRY vport;
145 LOCK_STATE_EX lockState;
147 VPORT_PORT_ENTER(portParam);
149 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
150 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
151 portParam->PortId, 0);
153 OvsRemoveAndDeleteVport(switchContext, vport);
155 OVS_LOG_WARN("Vport not present.");
157 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
159 VPORT_PORT_EXIT(portParam);
164 * Functions implemented in relaton to NDIS NIC manipulation.
167 HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
168 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
170 POVS_VPORT_ENTRY vport;
173 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
175 LOCK_STATE_EX lockState;
177 VPORT_NIC_ENTER(nicParam);
179 /* Wait for lists to be initialized. */
180 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
182 if (!switchContext->isActivated) {
183 OVS_LOG_WARN("Switch is not activated yet.");
184 /* Veto the creation of nic */
185 status = NDIS_STATUS_NOT_SUPPORTED;
189 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
190 vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId, 0);
192 OVS_LOG_ERROR("Create NIC without Switch Port,"
193 " PortId: %x, NicIndex: %d",
194 nicParam->PortId, nicParam->NicIndex);
195 status = NDIS_STATUS_INVALID_PARAMETER;
199 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
200 nicParam->NicIndex != 0) {
201 POVS_VPORT_ENTRY virtVport =
202 (POVS_VPORT_ENTRY)switchContext->externalVport;
203 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
205 status = NDIS_STATUS_RESOURCES;
208 OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex);
209 status = OvsInitVportCommon(switchContext, vport);
210 if (status != NDIS_STATUS_SUCCESS) {
211 OvsFreeMemory(vport);
215 OvsInitVportWithNicParam(switchContext, vport, nicParam);
216 portNo = vport->portNo;
217 if (vport->ovsState == OVS_STATE_CONNECTED) {
218 event = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
219 } else if (vport->ovsState == OVS_STATE_NIC_CREATED) {
220 event = OVS_EVENT_CONNECT;
224 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
225 if (portNo && event) {
226 OvsPostEvent(portNo, event);
230 VPORT_NIC_EXIT(nicParam);
231 OVS_LOG_TRACE("Exit: status %8x.\n", status);
237 /* Mark already created NIC as connected. */
239 HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
240 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
242 LOCK_STATE_EX lockState;
243 POVS_VPORT_ENTRY vport;
246 VPORT_NIC_ENTER(nicParam);
248 /* Wait for lists to be initialized. */
249 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
251 if (!switchContext->isActivated) {
252 OVS_LOG_WARN("Switch is not activated yet.");
256 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
257 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
262 OVS_LOG_WARN("Vport not present.");
263 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
268 vport->ovsState = OVS_STATE_CONNECTED;
269 vport->nicState = NdisSwitchNicStateConnected;
270 portNo = vport->portNo;
272 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
274 OvsPostEvent(portNo, OVS_EVENT_LINK_UP);
276 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
277 OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
281 VPORT_NIC_EXIT(nicParam);
285 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
286 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
288 POVS_VPORT_ENTRY vport;
289 LOCK_STATE_EX lockState;
291 UINT32 status = 0, portNo = 0;
293 VPORT_NIC_ENTER(nicParam);
295 /* Wait for lists to be initialized. */
296 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
298 if (!switchContext->isActivated) {
299 OVS_LOG_WARN("Switch is not activated yet.");
300 goto update_nic_done;
303 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
304 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
308 OVS_LOG_WARN("Vport search failed.");
309 goto update_nic_done;
311 switch (nicParam->NicType) {
312 case NdisSwitchNicTypeExternal:
313 case NdisSwitchNicTypeInternal:
314 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
317 case NdisSwitchNicTypeSynthetic:
318 case NdisSwitchNicTypeEmulated:
319 if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
320 sizeof (vport->vmMacAddress))) {
321 status |= OVS_EVENT_MAC_CHANGE;
322 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
323 sizeof (vport->vmMacAddress));
329 if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
330 sizeof (vport->permMacAddress))) {
331 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
332 sizeof (vport->permMacAddress));
333 status |= OVS_EVENT_MAC_CHANGE;
335 if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
336 sizeof (vport->currMacAddress))) {
337 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
338 sizeof (vport->currMacAddress));
339 status |= OVS_EVENT_MAC_CHANGE;
342 if (vport->mtu != nicParam->MTU) {
343 vport->mtu = nicParam->MTU;
344 status |= OVS_EVENT_MTU_CHANGE;
346 vport->numaNodeId = nicParam->NumaNodeId;
347 portNo = vport->portNo;
349 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
350 if (status && portNo) {
351 OvsPostEvent(portNo, status);
354 VPORT_NIC_EXIT(nicParam);
359 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
360 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
362 POVS_VPORT_ENTRY vport;
364 LOCK_STATE_EX lockState;
365 BOOLEAN isInternalPort = FALSE;
367 VPORT_NIC_ENTER(nicParam);
369 /* Wait for lists to be initialized. */
370 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
372 if (!switchContext->isActivated) {
373 OVS_LOG_WARN("Switch is not activated yet.");
377 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
378 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
383 OVS_LOG_WARN("Vport not present.");
384 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
388 vport->nicState = NdisSwitchNicStateDisconnected;
389 vport->ovsState = OVS_STATE_NIC_CREATED;
390 portNo = vport->portNo;
392 if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
393 isInternalPort = TRUE;
396 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
398 OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
400 if (isInternalPort) {
401 OvsInternalAdapterDown();
405 VPORT_NIC_EXIT(nicParam);
410 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
411 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
413 LOCK_STATE_EX lockState;
414 POVS_VPORT_ENTRY vport;
417 VPORT_NIC_ENTER(nicParam);
418 /* Wait for lists to be initialized. */
419 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
421 if (!switchContext->isActivated) {
422 OVS_LOG_WARN("Switch is not activated yet.");
426 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
427 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
432 OVS_LOG_WARN("Vport not present.");
433 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
437 portNo = vport->portNo;
438 if (vport->portType == NdisSwitchPortTypeExternal &&
439 vport->nicIndex != 0) {
440 OvsRemoveAndDeleteVport(switchContext, vport);
442 vport->nicState = NdisSwitchNicStateUnknown;
443 vport->ovsState = OVS_STATE_PORT_CREATED;
445 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
446 OvsPostEvent(portNo, OVS_EVENT_DISCONNECT);
449 VPORT_NIC_EXIT(nicParam);
454 * OVS Vport related functionality.
457 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
460 if (OVS_VPORT_INDEX(portNo) < OVS_MAX_VPORT_ARRAY_SIZE) {
461 if (OVS_IS_VPORT_ENTRY_NULL(switchContext, OVS_VPORT_INDEX(portNo))) {
464 POVS_VPORT_ENTRY vport;
465 vport = (POVS_VPORT_ENTRY)
466 switchContext->vportArray[OVS_VPORT_INDEX(portNo)];
467 return vport->portNo == portNo ? vport : NULL;
475 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
479 POVS_VPORT_ENTRY vport;
480 PLIST_ENTRY head, link;
481 UINT32 hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
482 head = &(switchContext->nameHashArray[hash & OVS_VPORT_MASK]);
483 LIST_FORALL(head, link) {
484 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, nameLink);
485 if (vport->ovsNameLen == length &&
486 RtlEqualMemory(name, vport->ovsName, length)) {
494 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
495 NDIS_SWITCH_PORT_ID portId,
496 NDIS_SWITCH_NIC_INDEX index)
498 if (portId == switchContext->externalPortId) {
500 return (POVS_VPORT_ENTRY)switchContext->externalVport;
501 } else if (index > OVS_MAX_PHYS_ADAPTERS) {
504 if (OVS_IS_VPORT_ENTRY_NULL(switchContext,
505 index + OVS_EXTERNAL_VPORT_START)) {
508 return (POVS_VPORT_ENTRY)switchContext->vportArray[
509 index + OVS_EXTERNAL_VPORT_START];
511 } else if (switchContext->internalPortId == portId) {
512 return (POVS_VPORT_ENTRY)switchContext->internalVport;
514 PLIST_ENTRY head, link;
515 POVS_VPORT_ENTRY vport;
517 hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
518 head = &(switchContext->portHashArray[hash & OVS_VPORT_MASK]);
519 LIST_FORALL(head, link) {
520 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portLink);
521 if (portId == vport->portId && index == vport->nicIndex) {
530 OvsGetVportNo(POVS_SWITCH_CONTEXT switchContext,
532 OVS_VPORT_TYPE ovsType,
535 UINT32 index = 0xffffff, i = 0;
540 return 0; // not a valid portNo
541 } else if (nicIndex > OVS_MAX_PHYS_ADAPTERS) {
544 index = nicIndex + OVS_EXTERNAL_VPORT_START;
549 case OVS_VPORT_TYPE_INTERNAL:
550 index = OVS_INTERNAL_VPORT_DEFAULT_INDEX;
552 case OVS_VPORT_TYPE_NETDEV:
553 index = switchContext->lastPortIndex + 1;
554 if (index == OVS_MAX_VPORT_ARRAY_SIZE) {
555 index = OVS_VM_VPORT_START;
557 while (!OVS_IS_VPORT_ENTRY_NULL(switchContext, index) &&
558 i < (OVS_MAX_VPORT_ARRAY_SIZE - OVS_VM_VPORT_START)) {
561 if (index == OVS_MAX_VPORT_ARRAY_SIZE) {
562 index = OVS_VM_VPORT_START;
565 if (i == (OVS_MAX_VPORT_ARRAY_SIZE - OVS_VM_VPORT_START)) {
566 return 0; // not available
568 switchContext->lastPortIndex = index;
570 case OVS_VPORT_TYPE_GRE:
571 index = OVS_GRE_VPORT_INDEX;
573 case OVS_VPORT_TYPE_GRE64:
574 index = OVS_GRE64_VPORT_INDEX;
576 case OVS_VPORT_TYPE_VXLAN:
577 index = OVS_VXLAN_VPORT_INDEX;
582 if (index > OVS_MAX_VPORT_ARRAY_SIZE) {
585 gen = (UINT64)switchContext->vportArray[index];
588 } else if (gen == 0) {
591 return OVS_VPORT_PORT_NO(index, (UINT32)gen);
595 static POVS_VPORT_ENTRY
596 OvsAllocateVport(VOID)
598 POVS_VPORT_ENTRY vport;
599 vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY));
603 RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
604 vport->ovsState = OVS_STATE_UNKNOWN;
609 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
610 PNDIS_SWITCH_PORT_PARAMETERS portParam)
612 vport->isValidationPort = portParam->IsValidationPort;
613 vport->portType = portParam->PortType;
614 vport->portState = portParam->PortState;
615 vport->portId = portParam->PortId;
616 vport->nicState = NdisSwitchNicStateUnknown;
617 vport->isExternal = FALSE;
619 switch (vport->portType) {
620 case NdisSwitchPortTypeExternal:
621 vport->isExternal = TRUE;
622 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
624 case NdisSwitchPortTypeInternal:
625 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
627 case NdisSwitchPortTypeSynthetic:
628 case NdisSwitchPortTypeEmulated:
629 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
632 RtlCopyMemory(&vport->portName, &portParam->PortName,
633 sizeof (NDIS_SWITCH_PORT_NAME));
634 switch (vport->portState) {
635 case NdisSwitchPortStateCreated:
636 vport->ovsState = OVS_STATE_PORT_CREATED;
638 case NdisSwitchPortStateTeardown:
639 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
641 case NdisSwitchPortStateDeleted:
642 vport->ovsState = OVS_STATE_PORT_DELETED;
649 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
650 POVS_VPORT_ENTRY vport,
651 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
653 ASSERT(vport->portId == nicParam->PortId);
654 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
656 UNREFERENCED_PARAMETER(switchContext);
658 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
659 sizeof (nicParam->PermanentMacAddress));
660 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
661 sizeof (nicParam->CurrentMacAddress));
663 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
664 nicParam->NicType == NdisSwitchNicTypeEmulated) {
665 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
666 sizeof (nicParam->VMMacAddress));
667 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
668 sizeof (nicParam->VmName));
670 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
671 sizeof (nicParam->NetCfgInstanceId));
673 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
674 sizeof (nicParam->NicName));
675 vport->mtu = nicParam->MTU;
676 vport->nicState = nicParam->NicState;
677 vport->nicIndex = nicParam->NicIndex;
678 vport->numaNodeId = nicParam->NumaNodeId;
680 switch (vport->nicState) {
681 case NdisSwitchNicStateCreated:
682 vport->ovsState = OVS_STATE_NIC_CREATED;
684 case NdisSwitchNicStateConnected:
685 vport->ovsState = OVS_STATE_CONNECTED;
687 case NdisSwitchNicStateDisconnected:
688 vport->ovsState = OVS_STATE_NIC_CREATED;
690 case NdisSwitchNicStateDeleted:
691 vport->ovsState = OVS_STATE_PORT_CREATED;
697 OvsInitPhysNicVport(POVS_VPORT_ENTRY vport,
698 POVS_VPORT_ENTRY virtVport,
701 vport->isValidationPort = virtVport->isValidationPort;
702 vport->portType = virtVport->portType;
703 vport->portState = virtVport->portState;
704 vport->portId = virtVport->portId;
705 vport->nicState = NdisSwitchNicStateUnknown;
706 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
707 vport->isExternal = TRUE;
708 vport->nicIndex = (NDIS_SWITCH_NIC_INDEX)nicIndex;
709 RtlCopyMemory(&vport->portName, &virtVport->portName,
710 sizeof (NDIS_SWITCH_PORT_NAME));
711 vport->ovsState = OVS_STATE_PORT_CREATED;
714 OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext,
715 POVS_VPORT_ENTRY vport)
719 if (vport->portType != NdisSwitchPortTypeExternal ||
720 vport->nicIndex != 0) {
721 vport->portNo = OvsGetVportNo(switchContext, vport->nicIndex,
722 vport->ovsType, vport->portType == NdisSwitchPortTypeExternal);
723 if (vport->portNo == 0) {
724 return NDIS_STATUS_RESOURCES;
726 ASSERT(OVS_IS_VPORT_ENTRY_NULL(switchContext,
727 OVS_VPORT_INDEX(vport->portNo)));
729 switchContext->vportArray[OVS_VPORT_INDEX(vport->portNo)] = vport;
731 switch (vport->portType) {
732 case NdisSwitchPortTypeExternal:
733 if (vport->nicIndex == 0) {
734 switchContext->externalPortId = vport->portId;
735 switchContext->externalVport = vport;
736 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
737 "external.virtualAdapter");
740 switchContext->numPhysicalNics++;
741 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
742 "external.%lu", (UINT32)vport->nicIndex);
745 case NdisSwitchPortTypeInternal:
746 switchContext->internalPortId = vport->portId;
747 switchContext->internalVport = vport;
748 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
751 case NdisSwitchPortTypeSynthetic:
752 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
753 "vmNICSyn.%lx", vport->portNo);
755 case NdisSwitchPortTypeEmulated:
756 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
757 "vmNICEmu.%lx", vport->portNo);
760 StringCbLengthA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
761 vport->ovsNameLen = (UINT32)len;
762 if (vport->portType == NdisSwitchPortTypeExternal &&
763 vport->nicIndex == 0) {
764 return NDIS_STATUS_SUCCESS;
766 hash = OvsJhashBytes(vport->ovsName, vport->ovsNameLen, OVS_HASH_BASIS);
767 InsertHeadList(&switchContext->nameHashArray[hash & OVS_VPORT_MASK],
769 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
770 InsertHeadList(&switchContext->portHashArray[hash & OVS_VPORT_MASK],
772 switchContext->numVports++;
773 return NDIS_STATUS_SUCCESS;
778 OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
779 POVS_VPORT_ENTRY vport)
781 UINT64 gen = vport->portNo >> 24;
783 if (vport->isExternal) {
784 if (vport->nicIndex == 0) {
785 ASSERT(switchContext->numPhysicalNics == 0);
786 switchContext->externalPortId = 0;
787 switchContext->externalVport = NULL;
788 OvsFreeMemory(vport);
791 ASSERT(switchContext->numPhysicalNics);
792 switchContext->numPhysicalNics--;
796 switch (vport->ovsType) {
797 case OVS_VPORT_TYPE_INTERNAL:
798 switchContext->internalPortId = 0;
799 switchContext->internalVport = NULL;
800 OvsInternalAdapterDown();
802 case OVS_VPORT_TYPE_VXLAN:
803 OvsCleanupVxlanTunnel(vport);
805 case OVS_VPORT_TYPE_GRE:
806 case OVS_VPORT_TYPE_GRE64:
808 case OVS_VPORT_TYPE_NETDEV:
813 RemoveEntryList(&vport->nameLink);
814 RemoveEntryList(&vport->portLink);
815 gen = (gen + 1) & 0xff;
816 switchContext->vportArray[OVS_VPORT_INDEX(vport->portNo)] =
818 switchContext->numVports--;
819 OvsFreeMemory(vport);
824 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
826 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
828 PNDIS_SWITCH_PORT_PARAMETERS portParam;
829 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
830 POVS_VPORT_ENTRY vport;
832 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
834 status = OvsGetPortsOnSwitch(switchContext, &portArray);
835 if (status != NDIS_STATUS_SUCCESS) {
839 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
840 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
841 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
843 status = NDIS_STATUS_RESOURCES;
846 OvsInitVportWithPortParam(vport, portParam);
847 status = OvsInitVportCommon(switchContext, vport);
848 if (status != NDIS_STATUS_SUCCESS) {
849 OvsFreeMemory(vport);
854 if (status != NDIS_STATUS_SUCCESS) {
855 OvsClearAllSwitchVports(switchContext);
858 if (portArray != NULL) {
859 OvsFreeMemory(portArray);
861 OVS_LOG_TRACE("Exit: status: %x", status);
867 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
869 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
870 PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
872 PNDIS_SWITCH_NIC_PARAMETERS nicParam;
873 POVS_VPORT_ENTRY vport;
875 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
879 status = OvsGetNicsOnSwitch(switchContext, &nicArray);
880 if (status != NDIS_STATUS_SUCCESS) {
883 for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
885 nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
888 * XXX: Check if the port is configured with a VLAN. Disallow such a
889 * configuration, since we don't support tag-in-tag.
893 * XXX: Check if the port is connected to a VF. Disconnect the VF in
897 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
898 nicParam->NicIndex != 0) {
899 POVS_VPORT_ENTRY virtVport =
900 (POVS_VPORT_ENTRY)switchContext->externalVport;
901 vport = OvsAllocateVport();
903 OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex);
904 status = OvsInitVportCommon(switchContext, vport);
905 if (status != NDIS_STATUS_SUCCESS) {
906 OvsFreeMemory(vport);
911 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
916 OVS_LOG_ERROR("Fail to allocate vport");
919 OvsInitVportWithNicParam(switchContext, vport, nicParam);
920 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
921 OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId);
926 if (nicArray != NULL) {
927 OvsFreeMemory(nicArray);
929 OVS_LOG_TRACE("Exit: status: %x", status);
934 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
938 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
939 if (!OVS_IS_VPORT_ENTRY_NULL(switchContext, i)) {
940 OvsRemoveAndDeleteVport(switchContext,
941 (POVS_VPORT_ENTRY)switchContext->vportArray[i]);
944 if (switchContext->externalVport) {
945 OvsRemoveAndDeleteVport(switchContext,
946 (POVS_VPORT_ENTRY)switchContext->externalVport);
951 OvsInitTunnelVport(POVS_VPORT_ENTRY vport,
952 POVS_VPORT_ADD_REQUEST addReq)
955 NTSTATUS status = STATUS_SUCCESS;
957 vport->isValidationPort = FALSE;
958 vport->ovsType = addReq->type;
959 vport->ovsState = OVS_STATE_PORT_CREATED;
960 RtlCopyMemory(vport->ovsName, addReq->name, OVS_MAX_PORT_NAME_LENGTH);
961 vport->ovsName[OVS_MAX_PORT_NAME_LENGTH - 1] = 0;
962 StringCbLengthA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
963 vport->ovsNameLen = (UINT32)len;
964 switch (addReq->type) {
965 case OVS_VPORT_TYPE_GRE:
967 case OVS_VPORT_TYPE_GRE64:
969 case OVS_VPORT_TYPE_VXLAN:
970 status = OvsInitVxlanTunnel(vport, addReq);
979 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
988 ustr.Buffer = wStr->String;
989 ustr.Length = wStr->Length;
990 ustr.MaximumLength = IF_MAX_STRING_SIZE;
993 astr.MaximumLength = maxStrLen;
996 size = RtlUnicodeStringToAnsiSize(&ustr);
997 if (size > maxStrLen) {
998 return STATUS_BUFFER_OVERFLOW;
1001 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
1003 ASSERT(status == STATUS_SUCCESS);
1004 if (status != STATUS_SUCCESS) {
1007 ASSERT(astr.Length <= maxStrLen);
1008 str[astr.Length] = 0;
1009 return STATUS_SUCCESS;
1014 * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for
1015 * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1.
1017 #define USE_NEW_VPORT_ADD_WORKFLOW 0
1019 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
1020 POVS_VPORT_EXT_INFO extInfo)
1022 POVS_VPORT_ENTRY vport;
1024 LOCK_STATE_EX lockState;
1025 NTSTATUS status = STATUS_SUCCESS;
1026 BOOLEAN doConvert = FALSE;
1028 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
1029 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1030 NDIS_RWL_AT_DISPATCH_LEVEL);
1031 if (vportGet->portNo == 0) {
1032 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1033 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1034 vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name,
1037 vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name);
1040 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
1042 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1043 vport->ovsState != OVS_STATE_NIC_CREATED)) {
1044 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1045 NdisReleaseSpinLock(gOvsCtrlLock);
1046 if (vportGet->portNo) {
1047 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
1049 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
1051 status = STATUS_DEVICE_DOES_NOT_EXIST;
1054 extInfo->dpNo = vportGet->dpNo;
1055 extInfo->portNo = vport->portNo;
1056 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1057 sizeof (vport->currMacAddress));
1058 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1059 sizeof (vport->permMacAddress));
1060 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1061 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1062 sizeof (vport->vmMacAddress));
1064 extInfo->nicIndex = vport->nicIndex;
1065 extInfo->portId = vport->portId;
1066 extInfo->type = vport->ovsType;
1067 extInfo->mtu = vport->mtu;
1071 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1072 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1073 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
1074 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1076 extInfo->status = OVS_EVENT_DISCONNECT;
1078 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1079 (vport->ovsState == OVS_STATE_NIC_CREATED ||
1080 vport->ovsState == OVS_STATE_CONNECTED)) {
1083 extInfo->vmUUID[0] = 0;
1084 extInfo->vifUUID[0] = 0;
1086 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1087 RtlCopyMemory(extInfo->name, vport->ovsName, vport->ovsNameLen + 1);
1089 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1090 NdisReleaseSpinLock(gOvsCtrlLock);
1092 #if USE_NEW_VPORT_ADD_WORKFLOW == 1
1093 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1095 OVS_MAX_PORT_NAME_LENGTH);
1096 if (status != STATUS_SUCCESS) {
1097 OVS_LOG_INFO("Fail to convert NIC name.");
1098 extInfo->vmUUID[0] = 0;
1102 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1104 OVS_MAX_VM_UUID_LEN);
1105 if (status != STATUS_SUCCESS) {
1106 OVS_LOG_INFO("Fail to convert VM name.");
1107 extInfo->vmUUID[0] = 0;
1110 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1112 OVS_MAX_VIF_UUID_LEN);
1113 if (status != STATUS_SUCCESS) {
1114 OVS_LOG_INFO("Fail to convert nic UUID");
1115 extInfo->vifUUID[0] = 0;
1118 * for now ignore status
1120 status = STATUS_SUCCESS;
1128 * --------------------------------------------------------------------------
1129 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1130 * --------------------------------------------------------------------------
1133 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1136 NTSTATUS status = STATUS_SUCCESS;
1137 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1138 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1139 NL_ERROR nlError = NL_ERROR_SUCCESS;
1140 OVS_VPORT_GET vportGet;
1141 OVS_VPORT_EXT_INFO info;
1142 LOCK_STATE_EX lockState;
1144 static const NL_POLICY ovsNetdevPolicy[] = {
1145 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1147 .maxLen = IFNAMSIZ },
1149 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1151 /* input buffer has been validated while validating transaction dev op. */
1152 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1153 usrParamsCtx->inputLength > sizeof *msgIn);
1155 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1156 return STATUS_INVALID_BUFFER_SIZE;
1159 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1160 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1161 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1162 ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1163 return STATUS_INVALID_PARAMETER;
1166 OvsAcquireCtrlLock();
1167 if (!gOvsSwitchContext) {
1168 OvsReleaseCtrlLock();
1169 return STATUS_INVALID_PARAMETER;
1172 vportGet.portNo = 0;
1173 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1174 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1176 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1177 status = OvsGetExtInfoIoctl(&vportGet, &info);
1178 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1179 nlError = NL_ERROR_NODEV;
1180 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1181 OvsReleaseCtrlLock();
1184 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1186 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1187 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1188 gOvsSwitchContext->dpNo);
1189 if (status == STATUS_SUCCESS) {
1190 *replyLen = msgOut->nlMsg.nlmsgLen;
1192 OvsReleaseCtrlLock();
1195 if (nlError != NL_ERROR_SUCCESS) {
1196 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1197 usrParamsCtx->outputBuffer;
1199 BuildErrorMsg(msgIn, msgError, nlError);
1200 *replyLen = msgError->nlMsg.nlmsgLen;
1203 return STATUS_SUCCESS;
1208 * --------------------------------------------------------------------------
1209 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1210 * OVS_MESSAGE contains the output of a netdev command.
1211 * --------------------------------------------------------------------------
1214 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1224 UINT32 netdevFlags = 0;
1226 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1228 BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1229 msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1231 ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1233 return STATUS_INSUFFICIENT_RESOURCES;
1236 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1239 return STATUS_INSUFFICIENT_RESOURCES;
1242 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1244 return STATUS_INSUFFICIENT_RESOURCES;
1247 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1250 return STATUS_INSUFFICIENT_RESOURCES;
1253 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1254 (PCHAR)info->macAddress, sizeof (info->macAddress));
1256 return STATUS_INSUFFICIENT_RESOURCES;
1259 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1261 return STATUS_INSUFFICIENT_RESOURCES;
1264 if (info->status != OVS_EVENT_CONNECT) {
1265 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1267 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1270 return STATUS_INSUFFICIENT_RESOURCES;
1274 * XXX: add netdev_stats when we have the definition available in the
1278 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1279 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1281 return STATUS_SUCCESS;
1284 static __inline VOID
1285 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1287 while ((!switchContext->isActivated) &&
1288 (!switchContext->isActivateFailed)) {
1289 /* Wait for the switch to be active and
1290 * the list of ports in OVS to be initialized. */
1291 NdisMSleep(sleepMicroSec);