2 * Copyright (c) 2014 VMware, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
31 #define OVS_DBG_MOD OVS_DBG_VPORT
34 #define VPORT_NIC_ENTER(_nic) \
35 OVS_LOG_TRACE("Enter: PortId: %x, NicIndex: %d", _nic->PortId, \
38 #define VPORT_NIC_EXIT(_nic) \
39 OVS_LOG_TRACE("Exit: PortId: %x, NicIndex: %d", _nic->PortId, \
42 #define VPORT_PORT_ENTER(_port) \
43 OVS_LOG_TRACE("Enter: PortId: %x", _port->PortId)
45 #define VPORT_PORT_EXIT(_port) \
46 OVS_LOG_TRACE("Exit: PortId: %x", _port->PortId)
48 #define OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC 100
50 extern POVS_SWITCH_CONTEXT gOvsSwitchContext
;
51 extern PNDIS_SPIN_LOCK gOvsCtrlLock
;
53 static VOID
OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport
,
54 PNDIS_SWITCH_PORT_PARAMETERS portParam
);
55 static VOID
OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext
,
56 POVS_VPORT_ENTRY vport
, PNDIS_SWITCH_NIC_PARAMETERS nicParam
);
57 static VOID
OvsInitPhysNicVport(POVS_VPORT_ENTRY vport
, POVS_VPORT_ENTRY
58 virtVport
, UINT32 nicIndex
);
59 static VOID
OvsInitPhysNicVport(POVS_VPORT_ENTRY vport
, POVS_VPORT_ENTRY
60 virtVport
, UINT32 nicIndex
);
61 static __inline VOID
OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext
,
63 static NTSTATUS
OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet
,
64 POVS_VPORT_EXT_INFO extInfo
);
65 static NTSTATUS
CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info
,
72 * Functions implemented in relaton to NDIS port manipulation.
75 HvCreatePort(POVS_SWITCH_CONTEXT switchContext
,
76 PNDIS_SWITCH_PORT_PARAMETERS portParam
)
78 POVS_VPORT_ENTRY vport
;
79 LOCK_STATE_EX lockState
;
80 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
82 VPORT_PORT_ENTER(portParam
);
84 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
85 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
86 portParam
->PortId
, 0);
87 if (vport
!= NULL
&& !vport
->hvDeleted
) {
88 status
= STATUS_DATA_NOT_ACCEPTED
;
89 goto create_port_done
;
91 vport
= (POVS_VPORT_ENTRY
)OvsAllocateVport();
93 status
= NDIS_STATUS_RESOURCES
;
94 goto create_port_done
;
98 OvsInitVportWithPortParam(vport
, portParam
);
99 OvsInitVportCommon(switchContext
, vport
);
102 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
103 VPORT_PORT_EXIT(portParam
);
108 HvTeardownPort(POVS_SWITCH_CONTEXT switchContext
,
109 PNDIS_SWITCH_PORT_PARAMETERS portParam
)
111 POVS_VPORT_ENTRY vport
;
112 LOCK_STATE_EX lockState
;
114 VPORT_PORT_ENTER(portParam
);
116 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
117 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
118 portParam
->PortId
, 0);
120 /* add assertion here
122 vport
->portState
= NdisSwitchPortStateTeardown
;
123 vport
->ovsState
= OVS_STATE_PORT_TEAR_DOWN
;
125 OVS_LOG_WARN("Vport not present.");
127 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
129 VPORT_PORT_EXIT(portParam
);
135 HvDeletePort(POVS_SWITCH_CONTEXT switchContext
,
136 PNDIS_SWITCH_PORT_PARAMETERS portParams
)
138 POVS_VPORT_ENTRY vport
;
139 LOCK_STATE_EX lockState
;
141 VPORT_PORT_ENTER(portParams
);
143 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
144 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
145 portParams
->PortId
, 0);
148 * XXX: we can only destroy and remove the port if its datapath port
149 * counterpart was deleted. If the datapath port counterpart is present,
150 * we only mark the vport for deletion, so that a netlink command vport
151 * delete will delete the vport.
154 if (vport
->portNo
== OVS_DPPORT_NUMBER_INVALID
) {
155 OvsRemoveAndDeleteVport(switchContext
, vport
);
157 vport
->hvDeleted
= TRUE
;
160 OVS_LOG_WARN("Vport not present.");
162 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
164 VPORT_PORT_EXIT(portParams
);
169 * Functions implemented in relaton to NDIS NIC manipulation.
172 HvCreateNic(POVS_SWITCH_CONTEXT switchContext
,
173 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
175 POVS_VPORT_ENTRY vport
;
178 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
180 LOCK_STATE_EX lockState
;
182 VPORT_NIC_ENTER(nicParam
);
184 /* Wait for lists to be initialized. */
185 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
187 if (!switchContext
->isActivated
) {
188 OVS_LOG_WARN("Switch is not activated yet.");
189 /* Veto the creation of nic */
190 status
= NDIS_STATUS_NOT_SUPPORTED
;
194 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
195 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
, nicParam
->PortId
, 0);
197 OVS_LOG_ERROR("Create NIC without Switch Port,"
198 " PortId: %x, NicIndex: %d",
199 nicParam
->PortId
, nicParam
->NicIndex
);
200 status
= NDIS_STATUS_INVALID_PARAMETER
;
204 if (nicParam
->NicType
== NdisSwitchNicTypeExternal
&&
205 nicParam
->NicIndex
!= 0) {
206 POVS_VPORT_ENTRY virtVport
=
207 (POVS_VPORT_ENTRY
)switchContext
->externalVport
;
208 vport
= (POVS_VPORT_ENTRY
)OvsAllocateVport();
210 status
= NDIS_STATUS_RESOURCES
;
213 OvsInitPhysNicVport(vport
, virtVport
, nicParam
->NicIndex
);
214 status
= OvsInitVportCommon(switchContext
, vport
);
215 if (status
!= NDIS_STATUS_SUCCESS
) {
216 OvsFreeMemory(vport
);
220 OvsInitVportWithNicParam(switchContext
, vport
, nicParam
);
221 portNo
= vport
->portNo
;
222 if (vport
->ovsState
== OVS_STATE_CONNECTED
) {
223 event
= OVS_EVENT_CONNECT
| OVS_EVENT_LINK_UP
;
224 } else if (vport
->ovsState
== OVS_STATE_NIC_CREATED
) {
225 event
= OVS_EVENT_CONNECT
;
229 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
230 if (portNo
!= OVS_DPPORT_NUMBER_INVALID
&& event
) {
231 OvsPostEvent(portNo
, event
);
235 VPORT_NIC_EXIT(nicParam
);
236 OVS_LOG_TRACE("Exit: status %8x.\n", status
);
242 /* Mark already created NIC as connected. */
244 HvConnectNic(POVS_SWITCH_CONTEXT switchContext
,
245 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
247 LOCK_STATE_EX lockState
;
248 POVS_VPORT_ENTRY vport
;
251 VPORT_NIC_ENTER(nicParam
);
253 /* Wait for lists to be initialized. */
254 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
256 if (!switchContext
->isActivated
) {
257 OVS_LOG_WARN("Switch is not activated yet.");
261 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
262 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
267 OVS_LOG_WARN("Vport not present.");
268 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
273 vport
->ovsState
= OVS_STATE_CONNECTED
;
274 vport
->nicState
= NdisSwitchNicStateConnected
;
275 portNo
= vport
->portNo
;
277 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
279 /* XXX only if portNo != INVALID or always? */
280 OvsPostEvent(portNo
, OVS_EVENT_LINK_UP
);
282 if (nicParam
->NicType
== NdisSwitchNicTypeInternal
) {
283 OvsInternalAdapterUp(portNo
, &nicParam
->NetCfgInstanceId
);
287 VPORT_NIC_EXIT(nicParam
);
291 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext
,
292 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
294 POVS_VPORT_ENTRY vport
;
295 LOCK_STATE_EX lockState
;
297 UINT32 status
= 0, portNo
= 0;
299 VPORT_NIC_ENTER(nicParam
);
301 /* Wait for lists to be initialized. */
302 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
304 if (!switchContext
->isActivated
) {
305 OVS_LOG_WARN("Switch is not activated yet.");
306 goto update_nic_done
;
309 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
310 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
314 OVS_LOG_WARN("Vport search failed.");
315 goto update_nic_done
;
317 switch (nicParam
->NicType
) {
318 case NdisSwitchNicTypeExternal
:
319 case NdisSwitchNicTypeInternal
:
320 RtlCopyMemory(&vport
->netCfgInstanceId
, &nicParam
->NetCfgInstanceId
,
323 case NdisSwitchNicTypeSynthetic
:
324 case NdisSwitchNicTypeEmulated
:
325 if (!RtlEqualMemory(vport
->vmMacAddress
, nicParam
->VMMacAddress
,
326 sizeof (vport
->vmMacAddress
))) {
327 status
|= OVS_EVENT_MAC_CHANGE
;
328 RtlCopyMemory(vport
->vmMacAddress
, nicParam
->VMMacAddress
,
329 sizeof (vport
->vmMacAddress
));
335 if (!RtlEqualMemory(vport
->permMacAddress
, nicParam
->PermanentMacAddress
,
336 sizeof (vport
->permMacAddress
))) {
337 RtlCopyMemory(vport
->permMacAddress
, nicParam
->PermanentMacAddress
,
338 sizeof (vport
->permMacAddress
));
339 status
|= OVS_EVENT_MAC_CHANGE
;
341 if (!RtlEqualMemory(vport
->currMacAddress
, nicParam
->CurrentMacAddress
,
342 sizeof (vport
->currMacAddress
))) {
343 RtlCopyMemory(vport
->currMacAddress
, nicParam
->CurrentMacAddress
,
344 sizeof (vport
->currMacAddress
));
345 status
|= OVS_EVENT_MAC_CHANGE
;
348 if (vport
->mtu
!= nicParam
->MTU
) {
349 vport
->mtu
= nicParam
->MTU
;
350 status
|= OVS_EVENT_MTU_CHANGE
;
352 vport
->numaNodeId
= nicParam
->NumaNodeId
;
353 portNo
= vport
->portNo
;
355 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
356 if (status
&& portNo
) {
357 OvsPostEvent(portNo
, status
);
360 VPORT_NIC_EXIT(nicParam
);
365 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext
,
366 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
368 POVS_VPORT_ENTRY vport
;
370 LOCK_STATE_EX lockState
;
371 BOOLEAN isInternalPort
= FALSE
;
373 VPORT_NIC_ENTER(nicParam
);
375 /* Wait for lists to be initialized. */
376 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
378 if (!switchContext
->isActivated
) {
379 OVS_LOG_WARN("Switch is not activated yet.");
383 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
384 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
389 OVS_LOG_WARN("Vport not present.");
390 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
394 vport
->nicState
= NdisSwitchNicStateDisconnected
;
395 vport
->ovsState
= OVS_STATE_NIC_CREATED
;
396 portNo
= vport
->portNo
;
398 if (vport
->ovsType
== OVS_VPORT_TYPE_INTERNAL
) {
399 isInternalPort
= TRUE
;
402 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
404 /* XXX if portNo != INVALID or always? */
405 OvsPostEvent(portNo
, OVS_EVENT_LINK_DOWN
);
407 if (isInternalPort
) {
408 OvsInternalAdapterDown();
412 VPORT_NIC_EXIT(nicParam
);
417 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext
,
418 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
420 LOCK_STATE_EX lockState
;
421 POVS_VPORT_ENTRY vport
;
424 VPORT_NIC_ENTER(nicParam
);
425 /* Wait for lists to be initialized. */
426 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
428 if (!switchContext
->isActivated
) {
429 OVS_LOG_WARN("Switch is not activated yet.");
433 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
434 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
439 OVS_LOG_WARN("Vport not present.");
440 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
444 portNo
= vport
->portNo
;
445 if (vport
->portType
== NdisSwitchPortTypeExternal
&&
446 vport
->nicIndex
!= 0) {
447 OvsRemoveAndDeleteVport(switchContext
, vport
);
449 vport
->nicState
= NdisSwitchNicStateUnknown
;
450 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
452 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
453 /* XXX if portNo != INVALID or always? */
454 OvsPostEvent(portNo
, OVS_EVENT_DISCONNECT
);
457 VPORT_NIC_EXIT(nicParam
);
462 * OVS Vport related functionality.
465 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext
,
468 POVS_VPORT_ENTRY vport
;
469 PLIST_ENTRY head
, link
;
470 UINT32 hash
= OvsJhashBytes((const VOID
*)&portNo
, sizeof(portNo
),
472 head
= &(switchContext
->portNoHashArray
[hash
& OVS_VPORT_MASK
]);
473 LIST_FORALL(head
, link
) {
474 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portNoLink
);
475 if (vport
->portNo
== portNo
) {
484 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext
,
487 POVS_VPORT_ENTRY vport
;
488 PLIST_ENTRY head
, link
;
490 SIZE_T length
= strlen(name
) + 1;
492 hash
= OvsJhashBytes((const VOID
*)name
, length
, OVS_HASH_BASIS
);
493 head
= &(switchContext
->ovsPortNameHashArray
[hash
& OVS_VPORT_MASK
]);
495 LIST_FORALL(head
, link
) {
496 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, ovsNameLink
);
497 if (!strcmp(name
, vport
->ovsName
)) {
505 /* OvsFindVportByHvName: "name" is assumed to be null-terminated */
507 OvsFindVportByHvName(POVS_SWITCH_CONTEXT switchContext
,
510 POVS_VPORT_ENTRY vport
= NULL
;
511 PLIST_ENTRY head
, link
;
512 /* 'portFriendlyName' is not NUL-terminated. */
513 SIZE_T length
= strlen(name
);
514 SIZE_T wstrSize
= length
* sizeof(WCHAR
);
517 PWSTR wsName
= OvsAllocateMemory(wstrSize
);
521 for (i
= 0; i
< length
; i
++) {
525 for (i
= 0; i
< OVS_MAX_VPORT_ARRAY_SIZE
; i
++) {
526 head
= &(switchContext
->portIdHashArray
[i
]);
527 LIST_FORALL(head
, link
) {
528 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portIdLink
);
531 * NOTE about portFriendlyName:
532 * If the string is NULL-terminated, the Length member does not
533 * include the terminating NULL character.
535 if (vport
->portFriendlyName
.Length
== wstrSize
&&
536 RtlEqualMemory(wsName
, vport
->portFriendlyName
.String
,
537 vport
->portFriendlyName
.Length
)) {
546 OvsFreeMemory(wsName
);
552 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext
,
553 NDIS_SWITCH_PORT_ID portId
,
554 NDIS_SWITCH_NIC_INDEX index
)
556 if (portId
== switchContext
->externalPortId
) {
557 return (POVS_VPORT_ENTRY
)switchContext
->externalVport
;
558 } else if (switchContext
->internalPortId
== portId
) {
559 return (POVS_VPORT_ENTRY
)switchContext
->internalVport
;
561 PLIST_ENTRY head
, link
;
562 POVS_VPORT_ENTRY vport
;
564 hash
= OvsJhashWords((UINT32
*)&portId
, 1, OVS_HASH_BASIS
);
565 head
= &(switchContext
->portIdHashArray
[hash
& OVS_VPORT_MASK
]);
566 LIST_FORALL(head
, link
) {
567 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portIdLink
);
568 if (portId
== vport
->portId
&& index
== vport
->nicIndex
) {
577 OvsAllocateVport(VOID
)
579 POVS_VPORT_ENTRY vport
;
580 vport
= (POVS_VPORT_ENTRY
)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY
));
584 RtlZeroMemory(vport
, sizeof (OVS_VPORT_ENTRY
));
585 vport
->ovsState
= OVS_STATE_UNKNOWN
;
586 vport
->hvDeleted
= FALSE
;
587 vport
->portNo
= OVS_DPPORT_NUMBER_INVALID
;
589 InitializeListHead(&vport
->ovsNameLink
);
590 InitializeListHead(&vport
->portIdLink
);
591 InitializeListHead(&vport
->portNoLink
);
597 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport
,
598 PNDIS_SWITCH_PORT_PARAMETERS portParam
)
600 vport
->portType
= portParam
->PortType
;
601 vport
->portState
= portParam
->PortState
;
602 vport
->portId
= portParam
->PortId
;
603 vport
->nicState
= NdisSwitchNicStateUnknown
;
604 vport
->isExternal
= FALSE
;
606 switch (vport
->portType
) {
607 case NdisSwitchPortTypeExternal
:
608 vport
->isExternal
= TRUE
;
609 vport
->ovsType
= OVS_VPORT_TYPE_NETDEV
;
611 case NdisSwitchPortTypeInternal
:
612 vport
->ovsType
= OVS_VPORT_TYPE_INTERNAL
;
614 case NdisSwitchPortTypeSynthetic
:
615 case NdisSwitchPortTypeEmulated
:
616 vport
->ovsType
= OVS_VPORT_TYPE_NETDEV
;
619 RtlCopyMemory(&vport
->hvPortName
, &portParam
->PortName
,
620 sizeof (NDIS_SWITCH_PORT_NAME
));
622 RtlCopyMemory(&vport
->portFriendlyName
, &portParam
->PortFriendlyName
,
623 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME
));
625 switch (vport
->portState
) {
626 case NdisSwitchPortStateCreated
:
627 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
629 case NdisSwitchPortStateTeardown
:
630 vport
->ovsState
= OVS_STATE_PORT_TEAR_DOWN
;
632 case NdisSwitchPortStateDeleted
:
633 vport
->ovsState
= OVS_STATE_PORT_DELETED
;
640 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext
,
641 POVS_VPORT_ENTRY vport
,
642 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
644 ASSERT(vport
->portId
== nicParam
->PortId
);
645 ASSERT(vport
->ovsState
== OVS_STATE_PORT_CREATED
);
647 UNREFERENCED_PARAMETER(switchContext
);
649 RtlCopyMemory(vport
->permMacAddress
, nicParam
->PermanentMacAddress
,
650 sizeof (nicParam
->PermanentMacAddress
));
651 RtlCopyMemory(vport
->currMacAddress
, nicParam
->CurrentMacAddress
,
652 sizeof (nicParam
->CurrentMacAddress
));
654 if (nicParam
->NicType
== NdisSwitchNicTypeSynthetic
||
655 nicParam
->NicType
== NdisSwitchNicTypeEmulated
) {
656 RtlCopyMemory(vport
->vmMacAddress
, nicParam
->VMMacAddress
,
657 sizeof (nicParam
->VMMacAddress
));
658 RtlCopyMemory(&vport
->vmName
, &nicParam
->VmName
,
659 sizeof (nicParam
->VmName
));
661 RtlCopyMemory(&vport
->netCfgInstanceId
, &nicParam
->NetCfgInstanceId
,
662 sizeof (nicParam
->NetCfgInstanceId
));
664 RtlCopyMemory(&vport
->nicName
, &nicParam
->NicName
,
665 sizeof (nicParam
->NicName
));
666 vport
->mtu
= nicParam
->MTU
;
667 vport
->nicState
= nicParam
->NicState
;
668 vport
->nicIndex
= nicParam
->NicIndex
;
669 vport
->numaNodeId
= nicParam
->NumaNodeId
;
671 switch (vport
->nicState
) {
672 case NdisSwitchNicStateCreated
:
673 vport
->ovsState
= OVS_STATE_NIC_CREATED
;
675 case NdisSwitchNicStateConnected
:
676 vport
->ovsState
= OVS_STATE_CONNECTED
;
678 case NdisSwitchNicStateDisconnected
:
679 vport
->ovsState
= OVS_STATE_NIC_CREATED
;
681 case NdisSwitchNicStateDeleted
:
682 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
688 OvsInitPhysNicVport(POVS_VPORT_ENTRY vport
,
689 POVS_VPORT_ENTRY virtVport
,
692 vport
->portType
= virtVport
->portType
;
693 vport
->portState
= virtVport
->portState
;
694 vport
->portId
= virtVport
->portId
;
695 vport
->nicState
= NdisSwitchNicStateUnknown
;
696 vport
->ovsType
= OVS_VPORT_TYPE_NETDEV
;
697 vport
->isExternal
= TRUE
;
698 vport
->nicIndex
= (NDIS_SWITCH_NIC_INDEX
)nicIndex
;
700 RtlCopyMemory(&vport
->hvPortName
, &virtVport
->hvPortName
,
701 sizeof (NDIS_SWITCH_PORT_NAME
));
703 RtlCopyMemory(&vport
->portFriendlyName
, &virtVport
->portFriendlyName
,
704 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME
));
706 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
710 OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext
,
711 POVS_VPORT_ENTRY vport
)
714 ASSERT(vport
->portNo
== OVS_DPPORT_NUMBER_INVALID
);
716 switch (vport
->portType
) {
717 case NdisSwitchPortTypeExternal
:
718 if (vport
->nicIndex
== 0) {
719 switchContext
->externalPortId
= vport
->portId
;
720 switchContext
->externalVport
= vport
;
721 RtlStringCbPrintfA(vport
->ovsName
, OVS_MAX_PORT_NAME_LENGTH
- 1,
722 "external.virtualAdapter");
724 switchContext
->numPhysicalNics
++;
725 RtlStringCbPrintfA(vport
->ovsName
, OVS_MAX_PORT_NAME_LENGTH
- 1,
726 "external.%lu", (UINT32
)vport
->nicIndex
);
729 case NdisSwitchPortTypeInternal
:
730 switchContext
->internalPortId
= vport
->portId
;
731 switchContext
->internalVport
= vport
;
733 case NdisSwitchPortTypeSynthetic
:
735 case NdisSwitchPortTypeEmulated
:
739 if (vport
->portType
== NdisSwitchPortTypeExternal
&&
740 vport
->nicIndex
== 0) {
741 return NDIS_STATUS_SUCCESS
;
745 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
746 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
747 * hyper-v switch seems to use only 2 bytes out of 4.
749 hash
= OvsJhashWords(&vport
->portId
, 1, OVS_HASH_BASIS
);
750 InsertHeadList(&switchContext
->portIdHashArray
[hash
& OVS_VPORT_MASK
],
752 switchContext
->numVports
++;
753 return NDIS_STATUS_SUCCESS
;
757 OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext
,
758 POVS_VPORT_ENTRY vport
)
760 if (vport
->isExternal
) {
761 if (vport
->nicIndex
== 0) {
762 ASSERT(switchContext
->numPhysicalNics
== 0);
763 switchContext
->externalPortId
= 0;
764 switchContext
->externalVport
= NULL
;
765 OvsFreeMemory(vport
);
768 ASSERT(switchContext
->numPhysicalNics
);
769 switchContext
->numPhysicalNics
--;
773 switch (vport
->ovsType
) {
774 case OVS_VPORT_TYPE_INTERNAL
:
775 switchContext
->internalPortId
= 0;
776 switchContext
->internalVport
= NULL
;
777 OvsInternalAdapterDown();
779 case OVS_VPORT_TYPE_VXLAN
:
780 OvsCleanupVxlanTunnel(vport
);
782 case OVS_VPORT_TYPE_GRE
:
783 case OVS_VPORT_TYPE_GRE64
:
785 case OVS_VPORT_TYPE_NETDEV
:
790 RemoveEntryList(&vport
->ovsNameLink
);
791 RemoveEntryList(&vport
->portIdLink
);
792 RemoveEntryList(&vport
->portNoLink
);
793 switchContext
->numVports
--;
794 OvsFreeMemory(vport
);
799 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext
)
801 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
803 PNDIS_SWITCH_PORT_PARAMETERS portParam
;
804 PNDIS_SWITCH_PORT_ARRAY portArray
= NULL
;
805 POVS_VPORT_ENTRY vport
;
807 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext
);
809 status
= OvsGetPortsOnSwitch(switchContext
, &portArray
);
810 if (status
!= NDIS_STATUS_SUCCESS
) {
814 for (arrIndex
= 0; arrIndex
< portArray
->NumElements
; arrIndex
++) {
815 portParam
= NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray
, arrIndex
);
817 if (portParam
->IsValidationPort
) {
821 vport
= (POVS_VPORT_ENTRY
)OvsAllocateVport();
823 status
= NDIS_STATUS_RESOURCES
;
826 OvsInitVportWithPortParam(vport
, portParam
);
827 status
= OvsInitVportCommon(switchContext
, vport
);
828 if (status
!= NDIS_STATUS_SUCCESS
) {
829 OvsFreeMemory(vport
);
834 if (status
!= NDIS_STATUS_SUCCESS
) {
835 OvsClearAllSwitchVports(switchContext
);
838 if (portArray
!= NULL
) {
839 OvsFreeMemory(portArray
);
841 OVS_LOG_TRACE("Exit: status: %x", status
);
847 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext
)
849 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
850 PNDIS_SWITCH_NIC_ARRAY nicArray
= NULL
;
852 PNDIS_SWITCH_NIC_PARAMETERS nicParam
;
853 POVS_VPORT_ENTRY vport
;
855 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext
);
859 status
= OvsGetNicsOnSwitch(switchContext
, &nicArray
);
860 if (status
!= NDIS_STATUS_SUCCESS
) {
863 for (arrIndex
= 0; arrIndex
< nicArray
->NumElements
; ++arrIndex
) {
865 nicParam
= NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray
, arrIndex
);
868 * XXX: Check if the port is configured with a VLAN. Disallow such a
869 * configuration, since we don't support tag-in-tag.
873 * XXX: Check if the port is connected to a VF. Disconnect the VF in
877 if (nicParam
->NicType
== NdisSwitchNicTypeExternal
&&
878 nicParam
->NicIndex
!= 0) {
879 POVS_VPORT_ENTRY virtVport
=
880 (POVS_VPORT_ENTRY
)switchContext
->externalVport
;
881 vport
= OvsAllocateVport();
883 OvsInitPhysNicVport(vport
, virtVport
, nicParam
->NicIndex
);
884 status
= OvsInitVportCommon(switchContext
, vport
);
885 if (status
!= NDIS_STATUS_SUCCESS
) {
886 OvsFreeMemory(vport
);
891 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
896 OVS_LOG_ERROR("Fail to allocate vport");
899 OvsInitVportWithNicParam(switchContext
, vport
, nicParam
);
900 if (nicParam
->NicType
== NdisSwitchNicTypeInternal
) {
901 OvsInternalAdapterUp(vport
->portNo
, &nicParam
->NetCfgInstanceId
);
906 if (nicArray
!= NULL
) {
907 OvsFreeMemory(nicArray
);
909 OVS_LOG_TRACE("Exit: status: %x", status
);
914 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext
)
916 for (UINT hash
= 0; hash
< OVS_MAX_VPORT_ARRAY_SIZE
; hash
++) {
917 PLIST_ENTRY head
, link
, next
;
919 head
= &(switchContext
->portIdHashArray
[hash
& OVS_VPORT_MASK
]);
920 LIST_FORALL_SAFE(head
, link
, next
) {
921 POVS_VPORT_ENTRY vport
;
922 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portIdLink
);
923 OvsRemoveAndDeleteVport(switchContext
, vport
);
927 if (switchContext
->externalVport
) {
928 OvsRemoveAndDeleteVport(switchContext
,
929 (POVS_VPORT_ENTRY
)switchContext
->externalVport
);
935 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr
,
944 ustr
.Buffer
= wStr
->String
;
945 ustr
.Length
= wStr
->Length
;
946 ustr
.MaximumLength
= IF_MAX_STRING_SIZE
;
949 astr
.MaximumLength
= maxStrLen
;
952 size
= RtlUnicodeStringToAnsiSize(&ustr
);
953 if (size
> maxStrLen
) {
954 return STATUS_BUFFER_OVERFLOW
;
957 status
= RtlUnicodeStringToAnsiString(&astr
, &ustr
, FALSE
);
959 ASSERT(status
== STATUS_SUCCESS
);
960 if (status
!= STATUS_SUCCESS
) {
963 ASSERT(astr
.Length
<= maxStrLen
);
964 str
[astr
.Length
] = 0;
965 return STATUS_SUCCESS
;
970 * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for
971 * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1.
973 #define USE_NEW_VPORT_ADD_WORKFLOW 1
975 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet
,
976 POVS_VPORT_EXT_INFO extInfo
)
978 POVS_VPORT_ENTRY vport
;
980 LOCK_STATE_EX lockState
;
981 NTSTATUS status
= STATUS_SUCCESS
;
982 BOOLEAN doConvert
= FALSE
;
984 RtlZeroMemory(extInfo
, sizeof (POVS_VPORT_EXT_INFO
));
985 NdisAcquireRWLockRead(gOvsSwitchContext
->dispatchLock
, &lockState
,
986 NDIS_RWL_AT_DISPATCH_LEVEL
);
987 if (vportGet
->portNo
== 0) {
988 StringCbLengthA(vportGet
->name
, OVS_MAX_PORT_NAME_LENGTH
- 1, &len
);
989 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
990 vport
= OvsFindVportByOvsName(gOvsSwitchContext
, vportGet
->name
,
993 vport
= OvsFindVportByHvName(gOvsSwitchContext
, vportGet
->name
);
996 vport
= OvsFindVportByPortNo(gOvsSwitchContext
, vportGet
->portNo
);
998 if (vport
== NULL
|| (vport
->ovsState
!= OVS_STATE_CONNECTED
&&
999 vport
->ovsState
!= OVS_STATE_NIC_CREATED
)) {
1000 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1001 NdisReleaseSpinLock(gOvsCtrlLock
);
1002 if (vportGet
->portNo
) {
1003 OVS_LOG_WARN("vport %u does not exist any more", vportGet
->portNo
);
1005 OVS_LOG_WARN("vport %s does not exist any more", vportGet
->name
);
1007 status
= STATUS_DEVICE_DOES_NOT_EXIST
;
1010 extInfo
->dpNo
= vportGet
->dpNo
;
1011 extInfo
->portNo
= vport
->portNo
;
1012 RtlCopyMemory(extInfo
->macAddress
, vport
->currMacAddress
,
1013 sizeof (vport
->currMacAddress
));
1014 RtlCopyMemory(extInfo
->permMACAddress
, vport
->permMacAddress
,
1015 sizeof (vport
->permMacAddress
));
1016 if (vport
->ovsType
== OVS_VPORT_TYPE_NETDEV
) {
1017 RtlCopyMemory(extInfo
->vmMACAddress
, vport
->vmMacAddress
,
1018 sizeof (vport
->vmMacAddress
));
1020 extInfo
->nicIndex
= vport
->nicIndex
;
1021 extInfo
->portId
= vport
->portId
;
1022 extInfo
->type
= vport
->ovsType
;
1023 extInfo
->mtu
= vport
->mtu
;
1027 if (vport
->ovsState
== OVS_STATE_NIC_CREATED
) {
1028 extInfo
->status
= OVS_EVENT_CONNECT
| OVS_EVENT_LINK_DOWN
;
1029 } else if (vport
->ovsState
== OVS_STATE_CONNECTED
) {
1030 extInfo
->status
= OVS_EVENT_CONNECT
| OVS_EVENT_LINK_UP
;
1032 extInfo
->status
= OVS_EVENT_DISCONNECT
;
1034 if (extInfo
->type
== OVS_VPORT_TYPE_NETDEV
&&
1035 (vport
->ovsState
== OVS_STATE_NIC_CREATED
||
1036 vport
->ovsState
== OVS_STATE_CONNECTED
)) {
1039 extInfo
->vmUUID
[0] = 0;
1040 extInfo
->vifUUID
[0] = 0;
1042 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1043 RtlCopyMemory(extInfo
->name
, vport
->ovsName
, vport
->ovsNameLen
+ 1);
1045 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1046 NdisReleaseSpinLock(gOvsCtrlLock
);
1048 #if USE_NEW_VPORT_ADD_WORKFLOW == 1
1049 status
= OvsConvertIfCountedStrToAnsiStr(&vport
->portFriendlyName
,
1051 OVS_MAX_PORT_NAME_LENGTH
);
1052 if (status
!= STATUS_SUCCESS
) {
1053 OVS_LOG_INFO("Fail to convert NIC name.");
1054 extInfo
->vmUUID
[0] = 0;
1058 status
= OvsConvertIfCountedStrToAnsiStr(&vport
->vmName
,
1060 OVS_MAX_VM_UUID_LEN
);
1061 if (status
!= STATUS_SUCCESS
) {
1062 OVS_LOG_INFO("Fail to convert VM name.");
1063 extInfo
->vmUUID
[0] = 0;
1066 status
= OvsConvertIfCountedStrToAnsiStr(&vport
->nicName
,
1068 OVS_MAX_VIF_UUID_LEN
);
1069 if (status
!= STATUS_SUCCESS
) {
1070 OVS_LOG_INFO("Fail to convert nic UUID");
1071 extInfo
->vifUUID
[0] = 0;
1074 * for now ignore status
1076 status
= STATUS_SUCCESS
;
1084 * --------------------------------------------------------------------------
1085 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1086 * --------------------------------------------------------------------------
1089 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
1092 NTSTATUS status
= STATUS_SUCCESS
;
1093 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
1094 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
1095 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
1096 OVS_VPORT_GET vportGet
;
1097 OVS_VPORT_EXT_INFO info
;
1098 LOCK_STATE_EX lockState
;
1100 static const NL_POLICY ovsNetdevPolicy
[] = {
1101 [OVS_WIN_NETDEV_ATTR_NAME
] = { .type
= NL_A_STRING
,
1103 .maxLen
= IFNAMSIZ
},
1105 PNL_ATTR netdevAttrs
[ARRAY_SIZE(ovsNetdevPolicy
)];
1107 /* input buffer has been validated while validating transaction dev op. */
1108 ASSERT(usrParamsCtx
->inputBuffer
!= NULL
&&
1109 usrParamsCtx
->inputLength
> sizeof *msgIn
);
1111 if (msgOut
== NULL
|| usrParamsCtx
->outputLength
< sizeof *msgOut
) {
1112 return STATUS_INVALID_BUFFER_SIZE
;
1115 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
1116 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
1117 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
1118 ovsNetdevPolicy
, netdevAttrs
, ARRAY_SIZE(netdevAttrs
))) {
1119 return STATUS_INVALID_PARAMETER
;
1122 OvsAcquireCtrlLock();
1123 if (!gOvsSwitchContext
) {
1124 OvsReleaseCtrlLock();
1125 return STATUS_INVALID_PARAMETER
;
1128 vportGet
.portNo
= 0;
1129 RtlCopyMemory(&vportGet
.name
, NlAttrGet(netdevAttrs
[OVS_VPORT_ATTR_NAME
]),
1130 NlAttrGetSize(netdevAttrs
[OVS_VPORT_ATTR_NAME
]));
1132 NdisAcquireRWLockRead(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
1133 status
= OvsGetExtInfoIoctl(&vportGet
, &info
);
1134 if (status
== STATUS_DEVICE_DOES_NOT_EXIST
) {
1135 nlError
= NL_ERROR_NODEV
;
1136 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1137 OvsReleaseCtrlLock();
1140 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1142 status
= CreateNetlinkMesgForNetdev(&info
, msgIn
,
1143 usrParamsCtx
->outputBuffer
, usrParamsCtx
->outputLength
,
1144 gOvsSwitchContext
->dpNo
);
1145 if (status
== STATUS_SUCCESS
) {
1146 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
1148 OvsReleaseCtrlLock();
1151 if (nlError
!= NL_ERROR_SUCCESS
) {
1152 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
1153 usrParamsCtx
->outputBuffer
;
1155 BuildErrorMsg(msgIn
, msgError
, nlError
);
1156 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
1159 return STATUS_SUCCESS
;
1164 * --------------------------------------------------------------------------
1165 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1166 * OVS_MESSAGE contains the output of a netdev command.
1167 * --------------------------------------------------------------------------
1170 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info
,
1180 UINT32 netdevFlags
= 0;
1182 NlBufInit(&nlBuffer
, outBuffer
, outBufLen
);
1184 BuildReplyMsgFromMsgIn(msgIn
, &msgOut
, 0);
1185 msgOut
.ovsHdr
.dp_ifindex
= dpIfIndex
;
1187 ok
= NlMsgPutHead(&nlBuffer
, (PCHAR
)&msgOut
, sizeof msgOut
);
1189 return STATUS_INSUFFICIENT_RESOURCES
;
1192 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_PORT_NO
,
1195 return STATUS_INSUFFICIENT_RESOURCES
;
1198 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_TYPE
, info
->type
);
1200 return STATUS_INSUFFICIENT_RESOURCES
;
1203 ok
= NlMsgPutTailString(&nlBuffer
, OVS_WIN_NETDEV_ATTR_NAME
,
1206 return STATUS_INSUFFICIENT_RESOURCES
;
1209 ok
= NlMsgPutTailUnspec(&nlBuffer
, OVS_WIN_NETDEV_ATTR_MAC_ADDR
,
1210 (PCHAR
)info
->macAddress
, sizeof (info
->macAddress
));
1212 return STATUS_INSUFFICIENT_RESOURCES
;
1215 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_MTU
, info
->mtu
);
1217 return STATUS_INSUFFICIENT_RESOURCES
;
1220 if (info
->status
!= OVS_EVENT_CONNECT
) {
1221 netdevFlags
= OVS_WIN_NETDEV_IFF_UP
;
1223 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_IF_FLAGS
,
1226 return STATUS_INSUFFICIENT_RESOURCES
;
1230 * XXX: add netdev_stats when we have the definition available in the
1234 nlMsg
= (PNL_MSG_HDR
)NlBufAt(&nlBuffer
, 0, 0);
1235 nlMsg
->nlmsgLen
= NlBufSize(&nlBuffer
);
1237 return STATUS_SUCCESS
;
1240 static __inline VOID
1241 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext
, ULONG sleepMicroSec
)
1243 while ((!switchContext
->isActivated
) &&
1244 (!switchContext
->isActivateFailed
)) {
1245 /* Wait for the switch to be active and
1246 * the list of ports in OVS to be initialized. */
1247 NdisMSleep(sleepMicroSec
);