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->portType = portParam->PortType;
613 vport->portState = portParam->PortState;
614 vport->portId = portParam->PortId;
615 vport->nicState = NdisSwitchNicStateUnknown;
616 vport->isExternal = FALSE;
618 switch (vport->portType) {
619 case NdisSwitchPortTypeExternal:
620 vport->isExternal = TRUE;
621 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
623 case NdisSwitchPortTypeInternal:
624 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
626 case NdisSwitchPortTypeSynthetic:
627 case NdisSwitchPortTypeEmulated:
628 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
631 RtlCopyMemory(&vport->portName, &portParam->PortName,
632 sizeof (NDIS_SWITCH_PORT_NAME));
633 switch (vport->portState) {
634 case NdisSwitchPortStateCreated:
635 vport->ovsState = OVS_STATE_PORT_CREATED;
637 case NdisSwitchPortStateTeardown:
638 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
640 case NdisSwitchPortStateDeleted:
641 vport->ovsState = OVS_STATE_PORT_DELETED;
648 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
649 POVS_VPORT_ENTRY vport,
650 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
652 ASSERT(vport->portId == nicParam->PortId);
653 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
655 UNREFERENCED_PARAMETER(switchContext);
657 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
658 sizeof (nicParam->PermanentMacAddress));
659 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
660 sizeof (nicParam->CurrentMacAddress));
662 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
663 nicParam->NicType == NdisSwitchNicTypeEmulated) {
664 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
665 sizeof (nicParam->VMMacAddress));
666 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
667 sizeof (nicParam->VmName));
669 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
670 sizeof (nicParam->NetCfgInstanceId));
672 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
673 sizeof (nicParam->NicName));
674 vport->mtu = nicParam->MTU;
675 vport->nicState = nicParam->NicState;
676 vport->nicIndex = nicParam->NicIndex;
677 vport->numaNodeId = nicParam->NumaNodeId;
679 switch (vport->nicState) {
680 case NdisSwitchNicStateCreated:
681 vport->ovsState = OVS_STATE_NIC_CREATED;
683 case NdisSwitchNicStateConnected:
684 vport->ovsState = OVS_STATE_CONNECTED;
686 case NdisSwitchNicStateDisconnected:
687 vport->ovsState = OVS_STATE_NIC_CREATED;
689 case NdisSwitchNicStateDeleted:
690 vport->ovsState = OVS_STATE_PORT_CREATED;
696 OvsInitPhysNicVport(POVS_VPORT_ENTRY vport,
697 POVS_VPORT_ENTRY virtVport,
700 vport->portType = virtVport->portType;
701 vport->portState = virtVport->portState;
702 vport->portId = virtVport->portId;
703 vport->nicState = NdisSwitchNicStateUnknown;
704 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
705 vport->isExternal = TRUE;
706 vport->nicIndex = (NDIS_SWITCH_NIC_INDEX)nicIndex;
707 RtlCopyMemory(&vport->portName, &virtVport->portName,
708 sizeof (NDIS_SWITCH_PORT_NAME));
709 vport->ovsState = OVS_STATE_PORT_CREATED;
712 OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext,
713 POVS_VPORT_ENTRY vport)
717 if (vport->portType != NdisSwitchPortTypeExternal ||
718 vport->nicIndex != 0) {
719 vport->portNo = OvsGetVportNo(switchContext, vport->nicIndex,
720 vport->ovsType, vport->portType == NdisSwitchPortTypeExternal);
721 if (vport->portNo == 0) {
722 return NDIS_STATUS_RESOURCES;
724 ASSERT(OVS_IS_VPORT_ENTRY_NULL(switchContext,
725 OVS_VPORT_INDEX(vport->portNo)));
727 switchContext->vportArray[OVS_VPORT_INDEX(vport->portNo)] = vport;
729 switch (vport->portType) {
730 case NdisSwitchPortTypeExternal:
731 if (vport->nicIndex == 0) {
732 switchContext->externalPortId = vport->portId;
733 switchContext->externalVport = vport;
734 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
735 "external.virtualAdapter");
738 switchContext->numPhysicalNics++;
739 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
740 "external.%lu", (UINT32)vport->nicIndex);
743 case NdisSwitchPortTypeInternal:
744 switchContext->internalPortId = vport->portId;
745 switchContext->internalVport = vport;
746 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
749 case NdisSwitchPortTypeSynthetic:
750 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
751 "vmNICSyn.%lx", vport->portNo);
753 case NdisSwitchPortTypeEmulated:
754 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
755 "vmNICEmu.%lx", vport->portNo);
758 StringCbLengthA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
759 vport->ovsNameLen = (UINT32)len;
760 if (vport->portType == NdisSwitchPortTypeExternal &&
761 vport->nicIndex == 0) {
762 return NDIS_STATUS_SUCCESS;
764 hash = OvsJhashBytes(vport->ovsName, vport->ovsNameLen, OVS_HASH_BASIS);
765 InsertHeadList(&switchContext->nameHashArray[hash & OVS_VPORT_MASK],
767 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
768 InsertHeadList(&switchContext->portHashArray[hash & OVS_VPORT_MASK],
770 switchContext->numVports++;
771 return NDIS_STATUS_SUCCESS;
776 OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
777 POVS_VPORT_ENTRY vport)
779 UINT64 gen = vport->portNo >> 24;
781 if (vport->isExternal) {
782 if (vport->nicIndex == 0) {
783 ASSERT(switchContext->numPhysicalNics == 0);
784 switchContext->externalPortId = 0;
785 switchContext->externalVport = NULL;
786 OvsFreeMemory(vport);
789 ASSERT(switchContext->numPhysicalNics);
790 switchContext->numPhysicalNics--;
794 switch (vport->ovsType) {
795 case OVS_VPORT_TYPE_INTERNAL:
796 switchContext->internalPortId = 0;
797 switchContext->internalVport = NULL;
798 OvsInternalAdapterDown();
800 case OVS_VPORT_TYPE_VXLAN:
801 OvsCleanupVxlanTunnel(vport);
803 case OVS_VPORT_TYPE_GRE:
804 case OVS_VPORT_TYPE_GRE64:
806 case OVS_VPORT_TYPE_NETDEV:
811 RemoveEntryList(&vport->nameLink);
812 RemoveEntryList(&vport->portLink);
813 gen = (gen + 1) & 0xff;
814 switchContext->vportArray[OVS_VPORT_INDEX(vport->portNo)] =
816 switchContext->numVports--;
817 OvsFreeMemory(vport);
822 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
824 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
826 PNDIS_SWITCH_PORT_PARAMETERS portParam;
827 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
828 POVS_VPORT_ENTRY vport;
830 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
832 status = OvsGetPortsOnSwitch(switchContext, &portArray);
833 if (status != NDIS_STATUS_SUCCESS) {
837 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
838 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
840 if (portParam->IsValidationPort) {
844 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
846 status = NDIS_STATUS_RESOURCES;
849 OvsInitVportWithPortParam(vport, portParam);
850 status = OvsInitVportCommon(switchContext, vport);
851 if (status != NDIS_STATUS_SUCCESS) {
852 OvsFreeMemory(vport);
857 if (status != NDIS_STATUS_SUCCESS) {
858 OvsClearAllSwitchVports(switchContext);
861 if (portArray != NULL) {
862 OvsFreeMemory(portArray);
864 OVS_LOG_TRACE("Exit: status: %x", status);
870 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
872 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
873 PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
875 PNDIS_SWITCH_NIC_PARAMETERS nicParam;
876 POVS_VPORT_ENTRY vport;
878 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
882 status = OvsGetNicsOnSwitch(switchContext, &nicArray);
883 if (status != NDIS_STATUS_SUCCESS) {
886 for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
888 nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
891 * XXX: Check if the port is configured with a VLAN. Disallow such a
892 * configuration, since we don't support tag-in-tag.
896 * XXX: Check if the port is connected to a VF. Disconnect the VF in
900 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
901 nicParam->NicIndex != 0) {
902 POVS_VPORT_ENTRY virtVport =
903 (POVS_VPORT_ENTRY)switchContext->externalVport;
904 vport = OvsAllocateVport();
906 OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex);
907 status = OvsInitVportCommon(switchContext, vport);
908 if (status != NDIS_STATUS_SUCCESS) {
909 OvsFreeMemory(vport);
914 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
919 OVS_LOG_ERROR("Fail to allocate vport");
922 OvsInitVportWithNicParam(switchContext, vport, nicParam);
923 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
924 OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId);
929 if (nicArray != NULL) {
930 OvsFreeMemory(nicArray);
932 OVS_LOG_TRACE("Exit: status: %x", status);
937 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
941 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
942 if (!OVS_IS_VPORT_ENTRY_NULL(switchContext, i)) {
943 OvsRemoveAndDeleteVport(switchContext,
944 (POVS_VPORT_ENTRY)switchContext->vportArray[i]);
947 if (switchContext->externalVport) {
948 OvsRemoveAndDeleteVport(switchContext,
949 (POVS_VPORT_ENTRY)switchContext->externalVport);
954 OvsInitTunnelVport(POVS_VPORT_ENTRY vport,
955 POVS_VPORT_ADD_REQUEST addReq)
958 NTSTATUS status = STATUS_SUCCESS;
960 vport->ovsType = addReq->type;
961 vport->ovsState = OVS_STATE_PORT_CREATED;
962 RtlCopyMemory(vport->ovsName, addReq->name, OVS_MAX_PORT_NAME_LENGTH);
963 vport->ovsName[OVS_MAX_PORT_NAME_LENGTH - 1] = 0;
964 StringCbLengthA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
965 vport->ovsNameLen = (UINT32)len;
966 switch (addReq->type) {
967 case OVS_VPORT_TYPE_GRE:
969 case OVS_VPORT_TYPE_GRE64:
971 case OVS_VPORT_TYPE_VXLAN:
972 status = OvsInitVxlanTunnel(vport, addReq);
981 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
990 ustr.Buffer = wStr->String;
991 ustr.Length = wStr->Length;
992 ustr.MaximumLength = IF_MAX_STRING_SIZE;
995 astr.MaximumLength = maxStrLen;
998 size = RtlUnicodeStringToAnsiSize(&ustr);
999 if (size > maxStrLen) {
1000 return STATUS_BUFFER_OVERFLOW;
1003 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
1005 ASSERT(status == STATUS_SUCCESS);
1006 if (status != STATUS_SUCCESS) {
1009 ASSERT(astr.Length <= maxStrLen);
1010 str[astr.Length] = 0;
1011 return STATUS_SUCCESS;
1016 * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for
1017 * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1.
1019 #define USE_NEW_VPORT_ADD_WORKFLOW 0
1021 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
1022 POVS_VPORT_EXT_INFO extInfo)
1024 POVS_VPORT_ENTRY vport;
1026 LOCK_STATE_EX lockState;
1027 NTSTATUS status = STATUS_SUCCESS;
1028 BOOLEAN doConvert = FALSE;
1030 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
1031 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1032 NDIS_RWL_AT_DISPATCH_LEVEL);
1033 if (vportGet->portNo == 0) {
1034 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1035 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1036 vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name,
1039 vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name);
1042 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
1044 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1045 vport->ovsState != OVS_STATE_NIC_CREATED)) {
1046 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1047 NdisReleaseSpinLock(gOvsCtrlLock);
1048 if (vportGet->portNo) {
1049 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
1051 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
1053 status = STATUS_DEVICE_DOES_NOT_EXIST;
1056 extInfo->dpNo = vportGet->dpNo;
1057 extInfo->portNo = vport->portNo;
1058 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1059 sizeof (vport->currMacAddress));
1060 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1061 sizeof (vport->permMacAddress));
1062 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1063 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1064 sizeof (vport->vmMacAddress));
1066 extInfo->nicIndex = vport->nicIndex;
1067 extInfo->portId = vport->portId;
1068 extInfo->type = vport->ovsType;
1069 extInfo->mtu = vport->mtu;
1073 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1074 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1075 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
1076 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1078 extInfo->status = OVS_EVENT_DISCONNECT;
1080 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1081 (vport->ovsState == OVS_STATE_NIC_CREATED ||
1082 vport->ovsState == OVS_STATE_CONNECTED)) {
1085 extInfo->vmUUID[0] = 0;
1086 extInfo->vifUUID[0] = 0;
1088 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1089 RtlCopyMemory(extInfo->name, vport->ovsName, vport->ovsNameLen + 1);
1091 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1092 NdisReleaseSpinLock(gOvsCtrlLock);
1094 #if USE_NEW_VPORT_ADD_WORKFLOW == 1
1095 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1097 OVS_MAX_PORT_NAME_LENGTH);
1098 if (status != STATUS_SUCCESS) {
1099 OVS_LOG_INFO("Fail to convert NIC name.");
1100 extInfo->vmUUID[0] = 0;
1104 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1106 OVS_MAX_VM_UUID_LEN);
1107 if (status != STATUS_SUCCESS) {
1108 OVS_LOG_INFO("Fail to convert VM name.");
1109 extInfo->vmUUID[0] = 0;
1112 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1114 OVS_MAX_VIF_UUID_LEN);
1115 if (status != STATUS_SUCCESS) {
1116 OVS_LOG_INFO("Fail to convert nic UUID");
1117 extInfo->vifUUID[0] = 0;
1120 * for now ignore status
1122 status = STATUS_SUCCESS;
1130 * --------------------------------------------------------------------------
1131 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1132 * --------------------------------------------------------------------------
1135 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1138 NTSTATUS status = STATUS_SUCCESS;
1139 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1140 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1141 NL_ERROR nlError = NL_ERROR_SUCCESS;
1142 OVS_VPORT_GET vportGet;
1143 OVS_VPORT_EXT_INFO info;
1144 LOCK_STATE_EX lockState;
1146 static const NL_POLICY ovsNetdevPolicy[] = {
1147 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1149 .maxLen = IFNAMSIZ },
1151 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1153 /* input buffer has been validated while validating transaction dev op. */
1154 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1155 usrParamsCtx->inputLength > sizeof *msgIn);
1157 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1158 return STATUS_INVALID_BUFFER_SIZE;
1161 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1162 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1163 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1164 ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1165 return STATUS_INVALID_PARAMETER;
1168 OvsAcquireCtrlLock();
1169 if (!gOvsSwitchContext) {
1170 OvsReleaseCtrlLock();
1171 return STATUS_INVALID_PARAMETER;
1174 vportGet.portNo = 0;
1175 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1176 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1178 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1179 status = OvsGetExtInfoIoctl(&vportGet, &info);
1180 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1181 nlError = NL_ERROR_NODEV;
1182 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1183 OvsReleaseCtrlLock();
1186 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1188 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1189 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1190 gOvsSwitchContext->dpNo);
1191 if (status == STATUS_SUCCESS) {
1192 *replyLen = msgOut->nlMsg.nlmsgLen;
1194 OvsReleaseCtrlLock();
1197 if (nlError != NL_ERROR_SUCCESS) {
1198 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1199 usrParamsCtx->outputBuffer;
1201 BuildErrorMsg(msgIn, msgError, nlError);
1202 *replyLen = msgError->nlMsg.nlmsgLen;
1205 return STATUS_SUCCESS;
1210 * --------------------------------------------------------------------------
1211 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1212 * OVS_MESSAGE contains the output of a netdev command.
1213 * --------------------------------------------------------------------------
1216 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1226 UINT32 netdevFlags = 0;
1228 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1230 BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1231 msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1233 ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1235 return STATUS_INSUFFICIENT_RESOURCES;
1238 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1241 return STATUS_INSUFFICIENT_RESOURCES;
1244 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1246 return STATUS_INSUFFICIENT_RESOURCES;
1249 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1252 return STATUS_INSUFFICIENT_RESOURCES;
1255 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1256 (PCHAR)info->macAddress, sizeof (info->macAddress));
1258 return STATUS_INSUFFICIENT_RESOURCES;
1261 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1263 return STATUS_INSUFFICIENT_RESOURCES;
1266 if (info->status != OVS_EVENT_CONNECT) {
1267 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1269 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1272 return STATUS_INSUFFICIENT_RESOURCES;
1276 * XXX: add netdev_stats when we have the definition available in the
1280 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1281 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1283 return STATUS_SUCCESS;
1286 static __inline VOID
1287 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1289 while ((!switchContext->isActivated) &&
1290 (!switchContext->isActivateFailed)) {
1291 /* Wait for the switch to be active and
1292 * the list of ports in OVS to be initialized. */
1293 NdisMSleep(sleepMicroSec);