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 != OVS_DPPORT_NUMBER_INVALID && 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 /* XXX only if portNo != INVALID or always? */
272 OvsPostEvent(portNo, OVS_EVENT_LINK_UP);
274 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
275 OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
279 VPORT_NIC_EXIT(nicParam);
283 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
284 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
286 POVS_VPORT_ENTRY vport;
287 LOCK_STATE_EX lockState;
289 UINT32 status = 0, portNo = 0;
291 VPORT_NIC_ENTER(nicParam);
293 /* Wait for lists to be initialized. */
294 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
296 if (!switchContext->isActivated) {
297 OVS_LOG_WARN("Switch is not activated yet.");
298 goto update_nic_done;
301 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
302 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
306 OVS_LOG_WARN("Vport search failed.");
307 goto update_nic_done;
309 switch (nicParam->NicType) {
310 case NdisSwitchNicTypeExternal:
311 case NdisSwitchNicTypeInternal:
312 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
315 case NdisSwitchNicTypeSynthetic:
316 case NdisSwitchNicTypeEmulated:
317 if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
318 sizeof (vport->vmMacAddress))) {
319 status |= OVS_EVENT_MAC_CHANGE;
320 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
321 sizeof (vport->vmMacAddress));
327 if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
328 sizeof (vport->permMacAddress))) {
329 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
330 sizeof (vport->permMacAddress));
331 status |= OVS_EVENT_MAC_CHANGE;
333 if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
334 sizeof (vport->currMacAddress))) {
335 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
336 sizeof (vport->currMacAddress));
337 status |= OVS_EVENT_MAC_CHANGE;
340 if (vport->mtu != nicParam->MTU) {
341 vport->mtu = nicParam->MTU;
342 status |= OVS_EVENT_MTU_CHANGE;
344 vport->numaNodeId = nicParam->NumaNodeId;
345 portNo = vport->portNo;
347 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
348 if (status && portNo) {
349 OvsPostEvent(portNo, status);
352 VPORT_NIC_EXIT(nicParam);
357 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
358 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
360 POVS_VPORT_ENTRY vport;
362 LOCK_STATE_EX lockState;
363 BOOLEAN isInternalPort = FALSE;
365 VPORT_NIC_ENTER(nicParam);
367 /* Wait for lists to be initialized. */
368 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
370 if (!switchContext->isActivated) {
371 OVS_LOG_WARN("Switch is not activated yet.");
375 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
376 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
381 OVS_LOG_WARN("Vport not present.");
382 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
386 vport->nicState = NdisSwitchNicStateDisconnected;
387 vport->ovsState = OVS_STATE_NIC_CREATED;
388 portNo = vport->portNo;
390 if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
391 isInternalPort = TRUE;
394 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
396 /* XXX if portNo != INVALID or always? */
397 OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
399 if (isInternalPort) {
400 OvsInternalAdapterDown();
404 VPORT_NIC_EXIT(nicParam);
409 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
410 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
412 LOCK_STATE_EX lockState;
413 POVS_VPORT_ENTRY vport;
416 VPORT_NIC_ENTER(nicParam);
417 /* Wait for lists to be initialized. */
418 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
420 if (!switchContext->isActivated) {
421 OVS_LOG_WARN("Switch is not activated yet.");
425 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
426 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
431 OVS_LOG_WARN("Vport not present.");
432 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
436 portNo = vport->portNo;
437 if (vport->portType == NdisSwitchPortTypeExternal &&
438 vport->nicIndex != 0) {
439 OvsRemoveAndDeleteVport(switchContext, vport);
441 vport->nicState = NdisSwitchNicStateUnknown;
442 vport->ovsState = OVS_STATE_PORT_CREATED;
444 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
445 /* XXX if portNo != INVALID or always? */
446 OvsPostEvent(portNo, OVS_EVENT_DISCONNECT);
449 VPORT_NIC_EXIT(nicParam);
454 * OVS Vport related functionality.
457 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
460 POVS_VPORT_ENTRY vport;
461 PLIST_ENTRY head, link;
462 UINT32 hash = OvsJhashBytes((const VOID *)&portNo, sizeof(portNo),
464 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
465 LIST_FORALL(head, link) {
466 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
467 if (vport->portNo == portNo) {
476 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
480 POVS_VPORT_ENTRY vport;
481 PLIST_ENTRY head, link;
482 UINT32 hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
483 head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
484 LIST_FORALL(head, link) {
485 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
486 if (vport->ovsNameLen == length &&
487 RtlEqualMemory(name, vport->ovsName, length)) {
495 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
496 NDIS_SWITCH_PORT_ID portId,
497 NDIS_SWITCH_NIC_INDEX index)
499 if (portId == switchContext->externalPortId) {
500 return (POVS_VPORT_ENTRY)switchContext->externalVport;
501 } else if (switchContext->internalPortId == portId) {
502 return (POVS_VPORT_ENTRY)switchContext->internalVport;
504 PLIST_ENTRY head, link;
505 POVS_VPORT_ENTRY vport;
507 hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
508 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
509 LIST_FORALL(head, link) {
510 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
511 if (portId == vport->portId && index == vport->nicIndex) {
519 static POVS_VPORT_ENTRY
520 OvsAllocateVport(VOID)
522 POVS_VPORT_ENTRY vport;
523 vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY));
527 RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
528 vport->ovsState = OVS_STATE_UNKNOWN;
529 vport->portNo = OVS_DPPORT_NUMBER_INVALID;
531 InitializeListHead(&vport->ovsNameLink);
532 InitializeListHead(&vport->portIdLink);
533 InitializeListHead(&vport->portNoLink);
539 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
540 PNDIS_SWITCH_PORT_PARAMETERS portParam)
542 vport->portType = portParam->PortType;
543 vport->portState = portParam->PortState;
544 vport->portId = portParam->PortId;
545 vport->nicState = NdisSwitchNicStateUnknown;
546 vport->isExternal = FALSE;
548 switch (vport->portType) {
549 case NdisSwitchPortTypeExternal:
550 vport->isExternal = TRUE;
551 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
553 case NdisSwitchPortTypeInternal:
554 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
556 case NdisSwitchPortTypeSynthetic:
557 case NdisSwitchPortTypeEmulated:
558 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
561 RtlCopyMemory(&vport->portName, &portParam->PortName,
562 sizeof (NDIS_SWITCH_PORT_NAME));
563 switch (vport->portState) {
564 case NdisSwitchPortStateCreated:
565 vport->ovsState = OVS_STATE_PORT_CREATED;
567 case NdisSwitchPortStateTeardown:
568 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
570 case NdisSwitchPortStateDeleted:
571 vport->ovsState = OVS_STATE_PORT_DELETED;
578 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
579 POVS_VPORT_ENTRY vport,
580 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
582 ASSERT(vport->portId == nicParam->PortId);
583 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
585 UNREFERENCED_PARAMETER(switchContext);
587 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
588 sizeof (nicParam->PermanentMacAddress));
589 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
590 sizeof (nicParam->CurrentMacAddress));
592 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
593 nicParam->NicType == NdisSwitchNicTypeEmulated) {
594 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
595 sizeof (nicParam->VMMacAddress));
596 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
597 sizeof (nicParam->VmName));
599 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
600 sizeof (nicParam->NetCfgInstanceId));
602 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
603 sizeof (nicParam->NicName));
604 vport->mtu = nicParam->MTU;
605 vport->nicState = nicParam->NicState;
606 vport->nicIndex = nicParam->NicIndex;
607 vport->numaNodeId = nicParam->NumaNodeId;
609 switch (vport->nicState) {
610 case NdisSwitchNicStateCreated:
611 vport->ovsState = OVS_STATE_NIC_CREATED;
613 case NdisSwitchNicStateConnected:
614 vport->ovsState = OVS_STATE_CONNECTED;
616 case NdisSwitchNicStateDisconnected:
617 vport->ovsState = OVS_STATE_NIC_CREATED;
619 case NdisSwitchNicStateDeleted:
620 vport->ovsState = OVS_STATE_PORT_CREATED;
626 OvsInitPhysNicVport(POVS_VPORT_ENTRY vport,
627 POVS_VPORT_ENTRY virtVport,
630 vport->portType = virtVport->portType;
631 vport->portState = virtVport->portState;
632 vport->portId = virtVport->portId;
633 vport->nicState = NdisSwitchNicStateUnknown;
634 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
635 vport->isExternal = TRUE;
636 vport->nicIndex = (NDIS_SWITCH_NIC_INDEX)nicIndex;
637 RtlCopyMemory(&vport->portName, &virtVport->portName,
638 sizeof (NDIS_SWITCH_PORT_NAME));
639 vport->ovsState = OVS_STATE_PORT_CREATED;
642 OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext,
643 POVS_VPORT_ENTRY vport)
646 ASSERT(vport->portNo == OVS_DPPORT_NUMBER_INVALID);
648 switch (vport->portType) {
649 case NdisSwitchPortTypeExternal:
650 if (vport->nicIndex == 0) {
651 switchContext->externalPortId = vport->portId;
652 switchContext->externalVport = vport;
653 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
654 "external.virtualAdapter");
656 switchContext->numPhysicalNics++;
657 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
658 "external.%lu", (UINT32)vport->nicIndex);
661 case NdisSwitchPortTypeInternal:
662 switchContext->internalPortId = vport->portId;
663 switchContext->internalVport = vport;
665 case NdisSwitchPortTypeSynthetic:
667 case NdisSwitchPortTypeEmulated:
671 if (vport->portType == NdisSwitchPortTypeExternal &&
672 vport->nicIndex == 0) {
673 return NDIS_STATUS_SUCCESS;
677 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
678 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
679 * hyper-v switch seems to use only 2 bytes out of 4.
681 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
682 InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK],
684 switchContext->numVports++;
685 return NDIS_STATUS_SUCCESS;
690 OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
691 POVS_VPORT_ENTRY vport)
693 if (vport->isExternal) {
694 if (vport->nicIndex == 0) {
695 ASSERT(switchContext->numPhysicalNics == 0);
696 switchContext->externalPortId = 0;
697 switchContext->externalVport = NULL;
698 OvsFreeMemory(vport);
701 ASSERT(switchContext->numPhysicalNics);
702 switchContext->numPhysicalNics--;
706 switch (vport->ovsType) {
707 case OVS_VPORT_TYPE_INTERNAL:
708 switchContext->internalPortId = 0;
709 switchContext->internalVport = NULL;
710 OvsInternalAdapterDown();
712 case OVS_VPORT_TYPE_VXLAN:
713 OvsCleanupVxlanTunnel(vport);
715 case OVS_VPORT_TYPE_GRE:
716 case OVS_VPORT_TYPE_GRE64:
718 case OVS_VPORT_TYPE_NETDEV:
723 RemoveEntryList(&vport->ovsNameLink);
724 RemoveEntryList(&vport->portIdLink);
725 RemoveEntryList(&vport->portNoLink);
726 switchContext->numVports--;
727 OvsFreeMemory(vport);
732 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
734 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
736 PNDIS_SWITCH_PORT_PARAMETERS portParam;
737 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
738 POVS_VPORT_ENTRY vport;
740 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
742 status = OvsGetPortsOnSwitch(switchContext, &portArray);
743 if (status != NDIS_STATUS_SUCCESS) {
747 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
748 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
750 if (portParam->IsValidationPort) {
754 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
756 status = NDIS_STATUS_RESOURCES;
759 OvsInitVportWithPortParam(vport, portParam);
760 status = OvsInitVportCommon(switchContext, vport);
761 if (status != NDIS_STATUS_SUCCESS) {
762 OvsFreeMemory(vport);
767 if (status != NDIS_STATUS_SUCCESS) {
768 OvsClearAllSwitchVports(switchContext);
771 if (portArray != NULL) {
772 OvsFreeMemory(portArray);
774 OVS_LOG_TRACE("Exit: status: %x", status);
780 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
782 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
783 PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
785 PNDIS_SWITCH_NIC_PARAMETERS nicParam;
786 POVS_VPORT_ENTRY vport;
788 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
792 status = OvsGetNicsOnSwitch(switchContext, &nicArray);
793 if (status != NDIS_STATUS_SUCCESS) {
796 for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
798 nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
801 * XXX: Check if the port is configured with a VLAN. Disallow such a
802 * configuration, since we don't support tag-in-tag.
806 * XXX: Check if the port is connected to a VF. Disconnect the VF in
810 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
811 nicParam->NicIndex != 0) {
812 POVS_VPORT_ENTRY virtVport =
813 (POVS_VPORT_ENTRY)switchContext->externalVport;
814 vport = OvsAllocateVport();
816 OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex);
817 status = OvsInitVportCommon(switchContext, vport);
818 if (status != NDIS_STATUS_SUCCESS) {
819 OvsFreeMemory(vport);
824 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
829 OVS_LOG_ERROR("Fail to allocate vport");
832 OvsInitVportWithNicParam(switchContext, vport, nicParam);
833 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
834 OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId);
839 if (nicArray != NULL) {
840 OvsFreeMemory(nicArray);
842 OVS_LOG_TRACE("Exit: status: %x", status);
847 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
849 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash) {
850 PLIST_ENTRY head, link;
852 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
853 LIST_FORALL(head, link) {
854 POVS_VPORT_ENTRY vport;
855 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
856 OvsRemoveAndDeleteVport(switchContext, vport);
860 if (switchContext->externalVport) {
861 OvsRemoveAndDeleteVport(switchContext,
862 (POVS_VPORT_ENTRY)switchContext->externalVport);
867 OvsInitTunnelVport(POVS_VPORT_ENTRY vport,
868 POVS_VPORT_ADD_REQUEST addReq)
871 NTSTATUS status = STATUS_SUCCESS;
873 vport->ovsType = addReq->type;
874 vport->ovsState = OVS_STATE_PORT_CREATED;
875 RtlCopyMemory(vport->ovsName, addReq->name, OVS_MAX_PORT_NAME_LENGTH);
876 vport->ovsName[OVS_MAX_PORT_NAME_LENGTH - 1] = 0;
877 StringCbLengthA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
878 vport->ovsNameLen = (UINT32)len;
879 switch (addReq->type) {
880 case OVS_VPORT_TYPE_GRE:
882 case OVS_VPORT_TYPE_GRE64:
884 case OVS_VPORT_TYPE_VXLAN:
885 status = OvsInitVxlanTunnel(vport, addReq);
894 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
903 ustr.Buffer = wStr->String;
904 ustr.Length = wStr->Length;
905 ustr.MaximumLength = IF_MAX_STRING_SIZE;
908 astr.MaximumLength = maxStrLen;
911 size = RtlUnicodeStringToAnsiSize(&ustr);
912 if (size > maxStrLen) {
913 return STATUS_BUFFER_OVERFLOW;
916 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
918 ASSERT(status == STATUS_SUCCESS);
919 if (status != STATUS_SUCCESS) {
922 ASSERT(astr.Length <= maxStrLen);
923 str[astr.Length] = 0;
924 return STATUS_SUCCESS;
929 * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for
930 * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1.
932 #define USE_NEW_VPORT_ADD_WORKFLOW 0
934 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
935 POVS_VPORT_EXT_INFO extInfo)
937 POVS_VPORT_ENTRY vport;
939 LOCK_STATE_EX lockState;
940 NTSTATUS status = STATUS_SUCCESS;
941 BOOLEAN doConvert = FALSE;
943 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
944 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
945 NDIS_RWL_AT_DISPATCH_LEVEL);
946 if (vportGet->portNo == 0) {
947 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
948 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
949 vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name,
952 vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name);
955 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
957 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
958 vport->ovsState != OVS_STATE_NIC_CREATED)) {
959 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
960 NdisReleaseSpinLock(gOvsCtrlLock);
961 if (vportGet->portNo) {
962 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
964 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
966 status = STATUS_DEVICE_DOES_NOT_EXIST;
969 extInfo->dpNo = vportGet->dpNo;
970 extInfo->portNo = vport->portNo;
971 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
972 sizeof (vport->currMacAddress));
973 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
974 sizeof (vport->permMacAddress));
975 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
976 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
977 sizeof (vport->vmMacAddress));
979 extInfo->nicIndex = vport->nicIndex;
980 extInfo->portId = vport->portId;
981 extInfo->type = vport->ovsType;
982 extInfo->mtu = vport->mtu;
986 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
987 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
988 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
989 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
991 extInfo->status = OVS_EVENT_DISCONNECT;
993 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
994 (vport->ovsState == OVS_STATE_NIC_CREATED ||
995 vport->ovsState == OVS_STATE_CONNECTED)) {
998 extInfo->vmUUID[0] = 0;
999 extInfo->vifUUID[0] = 0;
1001 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1002 RtlCopyMemory(extInfo->name, vport->ovsName, vport->ovsNameLen + 1);
1004 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1005 NdisReleaseSpinLock(gOvsCtrlLock);
1007 #if USE_NEW_VPORT_ADD_WORKFLOW == 1
1008 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1010 OVS_MAX_PORT_NAME_LENGTH);
1011 if (status != STATUS_SUCCESS) {
1012 OVS_LOG_INFO("Fail to convert NIC name.");
1013 extInfo->vmUUID[0] = 0;
1017 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1019 OVS_MAX_VM_UUID_LEN);
1020 if (status != STATUS_SUCCESS) {
1021 OVS_LOG_INFO("Fail to convert VM name.");
1022 extInfo->vmUUID[0] = 0;
1025 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1027 OVS_MAX_VIF_UUID_LEN);
1028 if (status != STATUS_SUCCESS) {
1029 OVS_LOG_INFO("Fail to convert nic UUID");
1030 extInfo->vifUUID[0] = 0;
1033 * for now ignore status
1035 status = STATUS_SUCCESS;
1043 * --------------------------------------------------------------------------
1044 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1045 * --------------------------------------------------------------------------
1048 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1051 NTSTATUS status = STATUS_SUCCESS;
1052 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1053 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1054 NL_ERROR nlError = NL_ERROR_SUCCESS;
1055 OVS_VPORT_GET vportGet;
1056 OVS_VPORT_EXT_INFO info;
1057 LOCK_STATE_EX lockState;
1059 static const NL_POLICY ovsNetdevPolicy[] = {
1060 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1062 .maxLen = IFNAMSIZ },
1064 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1066 /* input buffer has been validated while validating transaction dev op. */
1067 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1068 usrParamsCtx->inputLength > sizeof *msgIn);
1070 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1071 return STATUS_INVALID_BUFFER_SIZE;
1074 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1075 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1076 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1077 ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1078 return STATUS_INVALID_PARAMETER;
1081 OvsAcquireCtrlLock();
1082 if (!gOvsSwitchContext) {
1083 OvsReleaseCtrlLock();
1084 return STATUS_INVALID_PARAMETER;
1087 vportGet.portNo = 0;
1088 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1089 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1091 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1092 status = OvsGetExtInfoIoctl(&vportGet, &info);
1093 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1094 nlError = NL_ERROR_NODEV;
1095 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1096 OvsReleaseCtrlLock();
1099 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1101 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1102 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1103 gOvsSwitchContext->dpNo);
1104 if (status == STATUS_SUCCESS) {
1105 *replyLen = msgOut->nlMsg.nlmsgLen;
1107 OvsReleaseCtrlLock();
1110 if (nlError != NL_ERROR_SUCCESS) {
1111 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1112 usrParamsCtx->outputBuffer;
1114 BuildErrorMsg(msgIn, msgError, nlError);
1115 *replyLen = msgError->nlMsg.nlmsgLen;
1118 return STATUS_SUCCESS;
1123 * --------------------------------------------------------------------------
1124 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1125 * OVS_MESSAGE contains the output of a netdev command.
1126 * --------------------------------------------------------------------------
1129 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1139 UINT32 netdevFlags = 0;
1141 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1143 BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1144 msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1146 ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1148 return STATUS_INSUFFICIENT_RESOURCES;
1151 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1154 return STATUS_INSUFFICIENT_RESOURCES;
1157 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1159 return STATUS_INSUFFICIENT_RESOURCES;
1162 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1165 return STATUS_INSUFFICIENT_RESOURCES;
1168 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1169 (PCHAR)info->macAddress, sizeof (info->macAddress));
1171 return STATUS_INSUFFICIENT_RESOURCES;
1174 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1176 return STATUS_INSUFFICIENT_RESOURCES;
1179 if (info->status != OVS_EVENT_CONNECT) {
1180 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1182 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1185 return STATUS_INSUFFICIENT_RESOURCES;
1189 * XXX: add netdev_stats when we have the definition available in the
1193 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1194 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1196 return STATUS_SUCCESS;
1199 static __inline VOID
1200 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1202 while ((!switchContext->isActivated) &&
1203 (!switchContext->isActivateFailed)) {
1204 /* Wait for the switch to be active and
1205 * the list of ports in OVS to be initialized. */
1206 NdisMSleep(sleepMicroSec);