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 POVS_VPORT_ENTRY OvsAllocateVport(VOID);
54 static VOID OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
55 PNDIS_SWITCH_PORT_PARAMETERS portParam);
56 static VOID OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
57 POVS_VPORT_ENTRY vport, PNDIS_SWITCH_NIC_PARAMETERS nicParam);
58 static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, POVS_VPORT_ENTRY
59 virtVport, UINT32 nicIndex);
60 static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, POVS_VPORT_ENTRY
61 virtVport, UINT32 nicIndex);
62 static NDIS_STATUS OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext,
63 POVS_VPORT_ENTRY vport);
64 static VOID OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
65 POVS_VPORT_ENTRY vport);
66 static __inline VOID OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext,
68 static NTSTATUS OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
69 POVS_VPORT_EXT_INFO extInfo);
70 static NTSTATUS CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
77 * Functions implemented in relaton to NDIS port manipulation.
80 HvCreatePort(POVS_SWITCH_CONTEXT switchContext,
81 PNDIS_SWITCH_PORT_PARAMETERS portParam)
83 POVS_VPORT_ENTRY vport;
84 LOCK_STATE_EX lockState;
85 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
87 VPORT_PORT_ENTER(portParam);
89 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
90 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
91 portParam->PortId, 0);
93 status = STATUS_DATA_NOT_ACCEPTED;
94 goto create_port_done;
96 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
98 status = NDIS_STATUS_RESOURCES;
99 goto create_port_done;
101 OvsInitVportWithPortParam(vport, portParam);
102 OvsInitVportCommon(switchContext, vport);
105 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
106 VPORT_PORT_EXIT(portParam);
111 HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
112 PNDIS_SWITCH_PORT_PARAMETERS portParam)
114 POVS_VPORT_ENTRY vport;
115 LOCK_STATE_EX lockState;
117 VPORT_PORT_ENTER(portParam);
119 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
120 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
121 portParam->PortId, 0);
123 /* add assertion here
125 vport->portState = NdisSwitchPortStateTeardown;
126 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
128 OVS_LOG_WARN("Vport not present.");
130 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
132 VPORT_PORT_EXIT(portParam);
138 HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
139 PNDIS_SWITCH_PORT_PARAMETERS portParam)
141 POVS_VPORT_ENTRY vport;
142 LOCK_STATE_EX lockState;
144 VPORT_PORT_ENTER(portParam);
146 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
147 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
148 portParam->PortId, 0);
150 OvsRemoveAndDeleteVport(switchContext, vport);
152 OVS_LOG_WARN("Vport not present.");
154 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
156 VPORT_PORT_EXIT(portParam);
161 * Functions implemented in relaton to NDIS NIC manipulation.
164 HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
165 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
167 POVS_VPORT_ENTRY vport;
170 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
172 LOCK_STATE_EX lockState;
174 VPORT_NIC_ENTER(nicParam);
176 /* Wait for lists to be initialized. */
177 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
179 if (!switchContext->isActivated) {
180 OVS_LOG_WARN("Switch is not activated yet.");
181 /* Veto the creation of nic */
182 status = NDIS_STATUS_NOT_SUPPORTED;
186 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
187 vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId, 0);
189 OVS_LOG_ERROR("Create NIC without Switch Port,"
190 " PortId: %x, NicIndex: %d",
191 nicParam->PortId, nicParam->NicIndex);
192 status = NDIS_STATUS_INVALID_PARAMETER;
196 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
197 nicParam->NicIndex != 0) {
198 POVS_VPORT_ENTRY virtVport =
199 (POVS_VPORT_ENTRY)switchContext->externalVport;
200 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
202 status = NDIS_STATUS_RESOURCES;
205 OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex);
206 status = OvsInitVportCommon(switchContext, vport);
207 if (status != NDIS_STATUS_SUCCESS) {
208 OvsFreeMemory(vport);
212 OvsInitVportWithNicParam(switchContext, vport, nicParam);
213 portNo = vport->portNo;
214 if (vport->ovsState == OVS_STATE_CONNECTED) {
215 event = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
216 } else if (vport->ovsState == OVS_STATE_NIC_CREATED) {
217 event = OVS_EVENT_CONNECT;
221 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
222 if (portNo && event) {
223 OvsPostEvent(portNo, event);
227 VPORT_NIC_EXIT(nicParam);
228 OVS_LOG_TRACE("Exit: status %8x.\n", status);
234 /* Mark already created NIC as connected. */
236 HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
237 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
239 LOCK_STATE_EX lockState;
240 POVS_VPORT_ENTRY vport;
243 VPORT_NIC_ENTER(nicParam);
245 /* Wait for lists to be initialized. */
246 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
248 if (!switchContext->isActivated) {
249 OVS_LOG_WARN("Switch is not activated yet.");
253 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
254 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
259 OVS_LOG_WARN("Vport not present.");
260 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
265 vport->ovsState = OVS_STATE_CONNECTED;
266 vport->nicState = NdisSwitchNicStateConnected;
267 portNo = vport->portNo;
269 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
271 OvsPostEvent(portNo, OVS_EVENT_LINK_UP);
273 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
274 OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
278 VPORT_NIC_EXIT(nicParam);
282 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
283 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
285 POVS_VPORT_ENTRY vport;
286 LOCK_STATE_EX lockState;
288 UINT32 status = 0, portNo = 0;
290 VPORT_NIC_ENTER(nicParam);
292 /* Wait for lists to be initialized. */
293 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
295 if (!switchContext->isActivated) {
296 OVS_LOG_WARN("Switch is not activated yet.");
297 goto update_nic_done;
300 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
301 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
305 OVS_LOG_WARN("Vport search failed.");
306 goto update_nic_done;
308 switch (nicParam->NicType) {
309 case NdisSwitchNicTypeExternal:
310 case NdisSwitchNicTypeInternal:
311 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
314 case NdisSwitchNicTypeSynthetic:
315 case NdisSwitchNicTypeEmulated:
316 if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
317 sizeof (vport->vmMacAddress))) {
318 status |= OVS_EVENT_MAC_CHANGE;
319 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
320 sizeof (vport->vmMacAddress));
326 if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
327 sizeof (vport->permMacAddress))) {
328 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
329 sizeof (vport->permMacAddress));
330 status |= OVS_EVENT_MAC_CHANGE;
332 if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
333 sizeof (vport->currMacAddress))) {
334 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
335 sizeof (vport->currMacAddress));
336 status |= OVS_EVENT_MAC_CHANGE;
339 if (vport->mtu != nicParam->MTU) {
340 vport->mtu = nicParam->MTU;
341 status |= OVS_EVENT_MTU_CHANGE;
343 vport->numaNodeId = nicParam->NumaNodeId;
344 portNo = vport->portNo;
346 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
347 if (status && portNo) {
348 OvsPostEvent(portNo, status);
351 VPORT_NIC_EXIT(nicParam);
356 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
357 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
359 POVS_VPORT_ENTRY vport;
361 LOCK_STATE_EX lockState;
362 BOOLEAN isInternalPort = FALSE;
364 VPORT_NIC_ENTER(nicParam);
366 /* Wait for lists to be initialized. */
367 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
369 if (!switchContext->isActivated) {
370 OVS_LOG_WARN("Switch is not activated yet.");
374 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
375 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
380 OVS_LOG_WARN("Vport not present.");
381 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
385 vport->nicState = NdisSwitchNicStateDisconnected;
386 vport->ovsState = OVS_STATE_NIC_CREATED;
387 portNo = vport->portNo;
389 if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
390 isInternalPort = TRUE;
393 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
395 OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
397 if (isInternalPort) {
398 OvsInternalAdapterDown();
402 VPORT_NIC_EXIT(nicParam);
407 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
408 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
410 LOCK_STATE_EX lockState;
411 POVS_VPORT_ENTRY vport;
414 VPORT_NIC_ENTER(nicParam);
415 /* Wait for lists to be initialized. */
416 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
418 if (!switchContext->isActivated) {
419 OVS_LOG_WARN("Switch is not activated yet.");
423 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
424 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
429 OVS_LOG_WARN("Vport not present.");
430 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
434 portNo = vport->portNo;
435 if (vport->portType == NdisSwitchPortTypeExternal &&
436 vport->nicIndex != 0) {
437 OvsRemoveAndDeleteVport(switchContext, vport);
439 vport->nicState = NdisSwitchNicStateUnknown;
440 vport->ovsState = OVS_STATE_PORT_CREATED;
442 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
443 OvsPostEvent(portNo, OVS_EVENT_DISCONNECT);
446 VPORT_NIC_EXIT(nicParam);
451 * OVS Vport related functionality.
454 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
457 if (OVS_VPORT_INDEX(portNo) < OVS_MAX_VPORT_ARRAY_SIZE) {
458 if (OVS_IS_VPORT_ENTRY_NULL(switchContext, OVS_VPORT_INDEX(portNo))) {
461 POVS_VPORT_ENTRY vport;
462 vport = (POVS_VPORT_ENTRY)
463 switchContext->vportArray[OVS_VPORT_INDEX(portNo)];
464 return vport->portNo == portNo ? vport : NULL;
472 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
476 POVS_VPORT_ENTRY vport;
477 PLIST_ENTRY head, link;
478 UINT32 hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
479 head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
480 LIST_FORALL(head, link) {
481 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
482 if (vport->ovsNameLen == length &&
483 RtlEqualMemory(name, vport->ovsName, length)) {
491 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
492 NDIS_SWITCH_PORT_ID portId,
493 NDIS_SWITCH_NIC_INDEX index)
495 if (portId == switchContext->externalPortId) {
497 return (POVS_VPORT_ENTRY)switchContext->externalVport;
498 } else if (index > OVS_MAX_PHYS_ADAPTERS) {
501 if (OVS_IS_VPORT_ENTRY_NULL(switchContext,
502 index + OVS_EXTERNAL_VPORT_START)) {
505 return (POVS_VPORT_ENTRY)switchContext->vportArray[
506 index + OVS_EXTERNAL_VPORT_START];
508 } else if (switchContext->internalPortId == portId) {
509 return (POVS_VPORT_ENTRY)switchContext->internalVport;
511 PLIST_ENTRY head, link;
512 POVS_VPORT_ENTRY vport;
514 hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
515 head = &(switchContext->portHashArray[hash & OVS_VPORT_MASK]);
516 LIST_FORALL(head, link) {
517 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portLink);
518 if (portId == vport->portId && index == vport->nicIndex) {
527 OvsComputeVportNo(POVS_SWITCH_CONTEXT switchContext,
529 OVS_VPORT_TYPE ovsType,
532 UINT32 index = 0xffffff, i = 0;
537 return 0; // not a valid portNo
538 } else if (nicIndex > OVS_MAX_PHYS_ADAPTERS) {
541 index = nicIndex + OVS_EXTERNAL_VPORT_START;
546 case OVS_VPORT_TYPE_INTERNAL:
547 index = OVS_INTERNAL_VPORT_DEFAULT_INDEX;
549 case OVS_VPORT_TYPE_NETDEV:
550 index = switchContext->lastPortIndex + 1;
551 if (index == OVS_MAX_VPORT_ARRAY_SIZE) {
552 index = OVS_VM_VPORT_START;
554 while (!OVS_IS_VPORT_ENTRY_NULL(switchContext, index) &&
555 i < (OVS_MAX_VPORT_ARRAY_SIZE - OVS_VM_VPORT_START)) {
558 if (index == OVS_MAX_VPORT_ARRAY_SIZE) {
559 index = OVS_VM_VPORT_START;
562 if (i == (OVS_MAX_VPORT_ARRAY_SIZE - OVS_VM_VPORT_START)) {
563 return 0; // not available
565 switchContext->lastPortIndex = index;
567 case OVS_VPORT_TYPE_GRE:
568 index = OVS_GRE_VPORT_INDEX;
570 case OVS_VPORT_TYPE_GRE64:
571 index = OVS_GRE64_VPORT_INDEX;
573 case OVS_VPORT_TYPE_VXLAN:
574 index = OVS_VXLAN_VPORT_INDEX;
579 if (index > OVS_MAX_VPORT_ARRAY_SIZE) {
582 gen = (UINT64)switchContext->vportArray[index];
585 } else if (gen == 0) {
588 return OVS_VPORT_PORT_NO(index, (UINT32)gen);
592 static POVS_VPORT_ENTRY
593 OvsAllocateVport(VOID)
595 POVS_VPORT_ENTRY vport;
596 vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY));
600 RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
601 vport->ovsState = OVS_STATE_UNKNOWN;
606 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
607 PNDIS_SWITCH_PORT_PARAMETERS portParam)
609 vport->portType = portParam->PortType;
610 vport->portState = portParam->PortState;
611 vport->portId = portParam->PortId;
612 vport->nicState = NdisSwitchNicStateUnknown;
613 vport->isExternal = FALSE;
615 switch (vport->portType) {
616 case NdisSwitchPortTypeExternal:
617 vport->isExternal = TRUE;
618 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
620 case NdisSwitchPortTypeInternal:
621 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
623 case NdisSwitchPortTypeSynthetic:
624 case NdisSwitchPortTypeEmulated:
625 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
628 RtlCopyMemory(&vport->portName, &portParam->PortName,
629 sizeof (NDIS_SWITCH_PORT_NAME));
630 switch (vport->portState) {
631 case NdisSwitchPortStateCreated:
632 vport->ovsState = OVS_STATE_PORT_CREATED;
634 case NdisSwitchPortStateTeardown:
635 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
637 case NdisSwitchPortStateDeleted:
638 vport->ovsState = OVS_STATE_PORT_DELETED;
645 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
646 POVS_VPORT_ENTRY vport,
647 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
649 ASSERT(vport->portId == nicParam->PortId);
650 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
652 UNREFERENCED_PARAMETER(switchContext);
654 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
655 sizeof (nicParam->PermanentMacAddress));
656 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
657 sizeof (nicParam->CurrentMacAddress));
659 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
660 nicParam->NicType == NdisSwitchNicTypeEmulated) {
661 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
662 sizeof (nicParam->VMMacAddress));
663 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
664 sizeof (nicParam->VmName));
666 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
667 sizeof (nicParam->NetCfgInstanceId));
669 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
670 sizeof (nicParam->NicName));
671 vport->mtu = nicParam->MTU;
672 vport->nicState = nicParam->NicState;
673 vport->nicIndex = nicParam->NicIndex;
674 vport->numaNodeId = nicParam->NumaNodeId;
676 switch (vport->nicState) {
677 case NdisSwitchNicStateCreated:
678 vport->ovsState = OVS_STATE_NIC_CREATED;
680 case NdisSwitchNicStateConnected:
681 vport->ovsState = OVS_STATE_CONNECTED;
683 case NdisSwitchNicStateDisconnected:
684 vport->ovsState = OVS_STATE_NIC_CREATED;
686 case NdisSwitchNicStateDeleted:
687 vport->ovsState = OVS_STATE_PORT_CREATED;
693 OvsInitPhysNicVport(POVS_VPORT_ENTRY vport,
694 POVS_VPORT_ENTRY virtVport,
697 vport->portType = virtVport->portType;
698 vport->portState = virtVport->portState;
699 vport->portId = virtVport->portId;
700 vport->nicState = NdisSwitchNicStateUnknown;
701 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
702 vport->isExternal = TRUE;
703 vport->nicIndex = (NDIS_SWITCH_NIC_INDEX)nicIndex;
704 RtlCopyMemory(&vport->portName, &virtVport->portName,
705 sizeof (NDIS_SWITCH_PORT_NAME));
706 vport->ovsState = OVS_STATE_PORT_CREATED;
709 OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext,
710 POVS_VPORT_ENTRY vport)
714 if (vport->portType != NdisSwitchPortTypeExternal ||
715 vport->nicIndex != 0) {
716 vport->portNo = OvsComputeVportNo(switchContext, vport->nicIndex,
717 vport->ovsType, vport->portType == NdisSwitchPortTypeExternal);
718 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
719 return NDIS_STATUS_RESOURCES;
721 ASSERT(OVS_IS_VPORT_ENTRY_NULL(switchContext,
722 OVS_VPORT_INDEX(vport->portNo)));
724 switchContext->vportArray[OVS_VPORT_INDEX(vport->portNo)] = vport;
726 switch (vport->portType) {
727 case NdisSwitchPortTypeExternal:
728 if (vport->nicIndex == 0) {
729 switchContext->externalPortId = vport->portId;
730 switchContext->externalVport = vport;
731 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
732 "external.virtualAdapter");
735 switchContext->numPhysicalNics++;
736 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
737 "external.%lu", (UINT32)vport->nicIndex);
740 case NdisSwitchPortTypeInternal:
741 switchContext->internalPortId = vport->portId;
742 switchContext->internalVport = vport;
743 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
746 case NdisSwitchPortTypeSynthetic:
747 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
748 "vmNICSyn.%lx", vport->portNo);
750 case NdisSwitchPortTypeEmulated:
751 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
752 "vmNICEmu.%lx", vport->portNo);
755 StringCbLengthA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
756 vport->ovsNameLen = (UINT32)len;
757 if (vport->portType == NdisSwitchPortTypeExternal &&
758 vport->nicIndex == 0) {
759 return NDIS_STATUS_SUCCESS;
761 hash = OvsJhashBytes(vport->ovsName, vport->ovsNameLen, OVS_HASH_BASIS);
762 InsertHeadList(&switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK],
763 &vport->ovsNameLink);
764 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
765 InsertHeadList(&switchContext->portHashArray[hash & OVS_VPORT_MASK],
767 switchContext->numVports++;
768 return NDIS_STATUS_SUCCESS;
773 OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
774 POVS_VPORT_ENTRY vport)
776 UINT64 gen = vport->portNo >> 24;
778 if (vport->isExternal) {
779 if (vport->nicIndex == 0) {
780 ASSERT(switchContext->numPhysicalNics == 0);
781 switchContext->externalPortId = 0;
782 switchContext->externalVport = NULL;
783 OvsFreeMemory(vport);
786 ASSERT(switchContext->numPhysicalNics);
787 switchContext->numPhysicalNics--;
791 switch (vport->ovsType) {
792 case OVS_VPORT_TYPE_INTERNAL:
793 switchContext->internalPortId = 0;
794 switchContext->internalVport = NULL;
795 OvsInternalAdapterDown();
797 case OVS_VPORT_TYPE_VXLAN:
798 OvsCleanupVxlanTunnel(vport);
800 case OVS_VPORT_TYPE_GRE:
801 case OVS_VPORT_TYPE_GRE64:
803 case OVS_VPORT_TYPE_NETDEV:
808 RemoveEntryList(&vport->ovsNameLink);
809 RemoveEntryList(&vport->portLink);
810 gen = (gen + 1) & 0xff;
811 switchContext->vportArray[OVS_VPORT_INDEX(vport->portNo)] =
813 switchContext->numVports--;
814 OvsFreeMemory(vport);
819 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
821 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
823 PNDIS_SWITCH_PORT_PARAMETERS portParam;
824 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
825 POVS_VPORT_ENTRY vport;
827 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
829 status = OvsGetPortsOnSwitch(switchContext, &portArray);
830 if (status != NDIS_STATUS_SUCCESS) {
834 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
835 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
837 if (portParam->IsValidationPort) {
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->ovsType = addReq->type;
958 vport->ovsState = OVS_STATE_PORT_CREATED;
959 RtlCopyMemory(vport->ovsName, addReq->name, OVS_MAX_PORT_NAME_LENGTH);
960 vport->ovsName[OVS_MAX_PORT_NAME_LENGTH - 1] = 0;
961 StringCbLengthA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
962 vport->ovsNameLen = (UINT32)len;
963 switch (addReq->type) {
964 case OVS_VPORT_TYPE_GRE:
966 case OVS_VPORT_TYPE_GRE64:
968 case OVS_VPORT_TYPE_VXLAN:
969 status = OvsInitVxlanTunnel(vport, addReq);
978 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
987 ustr.Buffer = wStr->String;
988 ustr.Length = wStr->Length;
989 ustr.MaximumLength = IF_MAX_STRING_SIZE;
992 astr.MaximumLength = maxStrLen;
995 size = RtlUnicodeStringToAnsiSize(&ustr);
996 if (size > maxStrLen) {
997 return STATUS_BUFFER_OVERFLOW;
1000 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
1002 ASSERT(status == STATUS_SUCCESS);
1003 if (status != STATUS_SUCCESS) {
1006 ASSERT(astr.Length <= maxStrLen);
1007 str[astr.Length] = 0;
1008 return STATUS_SUCCESS;
1013 * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for
1014 * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1.
1016 #define USE_NEW_VPORT_ADD_WORKFLOW 0
1018 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
1019 POVS_VPORT_EXT_INFO extInfo)
1021 POVS_VPORT_ENTRY vport;
1023 LOCK_STATE_EX lockState;
1024 NTSTATUS status = STATUS_SUCCESS;
1025 BOOLEAN doConvert = FALSE;
1027 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
1028 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1029 NDIS_RWL_AT_DISPATCH_LEVEL);
1030 if (vportGet->portNo == 0) {
1031 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1032 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1033 vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name,
1036 vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name);
1039 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
1041 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1042 vport->ovsState != OVS_STATE_NIC_CREATED)) {
1043 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1044 NdisReleaseSpinLock(gOvsCtrlLock);
1045 if (vportGet->portNo) {
1046 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
1048 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
1050 status = STATUS_DEVICE_DOES_NOT_EXIST;
1053 extInfo->dpNo = vportGet->dpNo;
1054 extInfo->portNo = vport->portNo;
1055 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1056 sizeof (vport->currMacAddress));
1057 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1058 sizeof (vport->permMacAddress));
1059 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1060 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1061 sizeof (vport->vmMacAddress));
1063 extInfo->nicIndex = vport->nicIndex;
1064 extInfo->portId = vport->portId;
1065 extInfo->type = vport->ovsType;
1066 extInfo->mtu = vport->mtu;
1070 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1071 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1072 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
1073 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1075 extInfo->status = OVS_EVENT_DISCONNECT;
1077 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1078 (vport->ovsState == OVS_STATE_NIC_CREATED ||
1079 vport->ovsState == OVS_STATE_CONNECTED)) {
1082 extInfo->vmUUID[0] = 0;
1083 extInfo->vifUUID[0] = 0;
1085 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1086 RtlCopyMemory(extInfo->name, vport->ovsName, vport->ovsNameLen + 1);
1088 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1089 NdisReleaseSpinLock(gOvsCtrlLock);
1091 #if USE_NEW_VPORT_ADD_WORKFLOW == 1
1092 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1094 OVS_MAX_PORT_NAME_LENGTH);
1095 if (status != STATUS_SUCCESS) {
1096 OVS_LOG_INFO("Fail to convert NIC name.");
1097 extInfo->vmUUID[0] = 0;
1101 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1103 OVS_MAX_VM_UUID_LEN);
1104 if (status != STATUS_SUCCESS) {
1105 OVS_LOG_INFO("Fail to convert VM name.");
1106 extInfo->vmUUID[0] = 0;
1109 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1111 OVS_MAX_VIF_UUID_LEN);
1112 if (status != STATUS_SUCCESS) {
1113 OVS_LOG_INFO("Fail to convert nic UUID");
1114 extInfo->vifUUID[0] = 0;
1117 * for now ignore status
1119 status = STATUS_SUCCESS;
1127 * --------------------------------------------------------------------------
1128 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1129 * --------------------------------------------------------------------------
1132 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1135 NTSTATUS status = STATUS_SUCCESS;
1136 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1137 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1138 NL_ERROR nlError = NL_ERROR_SUCCESS;
1139 OVS_VPORT_GET vportGet;
1140 OVS_VPORT_EXT_INFO info;
1141 LOCK_STATE_EX lockState;
1143 static const NL_POLICY ovsNetdevPolicy[] = {
1144 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1146 .maxLen = IFNAMSIZ },
1148 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1150 /* input buffer has been validated while validating transaction dev op. */
1151 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1152 usrParamsCtx->inputLength > sizeof *msgIn);
1154 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1155 return STATUS_INVALID_BUFFER_SIZE;
1158 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1159 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1160 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1161 ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1162 return STATUS_INVALID_PARAMETER;
1165 OvsAcquireCtrlLock();
1166 if (!gOvsSwitchContext) {
1167 OvsReleaseCtrlLock();
1168 return STATUS_INVALID_PARAMETER;
1171 vportGet.portNo = 0;
1172 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1173 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1175 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1176 status = OvsGetExtInfoIoctl(&vportGet, &info);
1177 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1178 nlError = NL_ERROR_NODEV;
1179 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1180 OvsReleaseCtrlLock();
1183 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1185 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1186 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1187 gOvsSwitchContext->dpNo);
1188 if (status == STATUS_SUCCESS) {
1189 *replyLen = msgOut->nlMsg.nlmsgLen;
1191 OvsReleaseCtrlLock();
1194 if (nlError != NL_ERROR_SUCCESS) {
1195 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1196 usrParamsCtx->outputBuffer;
1198 BuildErrorMsg(msgIn, msgError, nlError);
1199 *replyLen = msgError->nlMsg.nlmsgLen;
1202 return STATUS_SUCCESS;
1207 * --------------------------------------------------------------------------
1208 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1209 * OVS_MESSAGE contains the output of a netdev command.
1210 * --------------------------------------------------------------------------
1213 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1223 UINT32 netdevFlags = 0;
1225 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1227 BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1228 msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1230 ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1232 return STATUS_INSUFFICIENT_RESOURCES;
1235 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1238 return STATUS_INSUFFICIENT_RESOURCES;
1241 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1243 return STATUS_INSUFFICIENT_RESOURCES;
1246 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1249 return STATUS_INSUFFICIENT_RESOURCES;
1252 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1253 (PCHAR)info->macAddress, sizeof (info->macAddress));
1255 return STATUS_INSUFFICIENT_RESOURCES;
1258 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1260 return STATUS_INSUFFICIENT_RESOURCES;
1263 if (info->status != OVS_EVENT_CONNECT) {
1264 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1266 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1269 return STATUS_INSUFFICIENT_RESOURCES;
1273 * XXX: add netdev_stats when we have the definition available in the
1277 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1278 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1280 return STATUS_SUCCESS;
1283 static __inline VOID
1284 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1286 while ((!switchContext->isActivated) &&
1287 (!switchContext->isActivateFailed)) {
1288 /* Wait for the switch to be active and
1289 * the list of ports in OVS to be initialized. */
1290 NdisMSleep(sleepMicroSec);