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.
32 #define OVS_DBG_MOD OVS_DBG_VPORT
35 #define VPORT_NIC_ENTER(_nic) \
36 OVS_LOG_TRACE("Enter: PortId: %x, NicIndex: %d", _nic->PortId, \
39 #define VPORT_NIC_EXIT(_nic) \
40 OVS_LOG_TRACE("Exit: PortId: %x, NicIndex: %d", _nic->PortId, \
43 #define VPORT_PORT_ENTER(_port) \
44 OVS_LOG_TRACE("Enter: PortId: %x", _port->PortId)
46 #define VPORT_PORT_EXIT(_port) \
47 OVS_LOG_TRACE("Exit: PortId: %x", _port->PortId)
49 #define OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC 100
51 /* Context structure used to pass back and forth information to the tunnel
53 typedef struct _OVS_TUNFLT_INIT_CONTEXT
{
54 POVS_SWITCH_CONTEXT switchContext
;
58 POVS_VPORT_ENTRY vport
;
62 } OVS_TUNFLT_INIT_CONTEXT
, *POVS_TUNFLT_INIT_CONTEXT
;
65 extern POVS_SWITCH_CONTEXT gOvsSwitchContext
;
67 static VOID
OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport
,
68 PNDIS_SWITCH_PORT_PARAMETERS portParam
);
69 static VOID
OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext
,
70 POVS_VPORT_ENTRY vport
, PNDIS_SWITCH_NIC_PARAMETERS nicParam
);
71 static VOID
OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVPort
,
72 POVS_VPORT_ENTRY virtExtVport
, UINT32 nicIndex
);
73 static __inline VOID
OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext
,
75 static NTSTATUS
OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet
,
76 POVS_VPORT_EXT_INFO extInfo
);
77 static NTSTATUS
CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info
,
82 static POVS_VPORT_ENTRY
OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext
,
83 PWSTR wsName
, SIZE_T wstrSize
);
84 static NDIS_STATUS
InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext
,
85 POVS_VPORT_ENTRY vport
,
87 static NTSTATUS
OvsRemoveTunnelVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
88 POVS_SWITCH_CONTEXT switchContext
,
89 POVS_VPORT_ENTRY vport
,
92 static VOID
OvsTunnelVportPendingInit(PVOID context
,
95 static VOID
OvsTunnelVportPendingRemove(PVOID context
,
101 * Functions implemented in relaton to NDIS port manipulation.
104 HvCreatePort(POVS_SWITCH_CONTEXT switchContext
,
105 PNDIS_SWITCH_PORT_PARAMETERS portParam
)
107 POVS_VPORT_ENTRY vport
;
108 LOCK_STATE_EX lockState
;
109 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
110 BOOLEAN newPort
= FALSE
;
112 VPORT_PORT_ENTER(portParam
);
114 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
115 /* Lookup by port ID. */
116 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
117 portParam
->PortId
, 0);
119 OVS_LOG_ERROR("Port add failed due to duplicate port name, "
120 "port Id: %u", portParam
->PortId
);
121 status
= STATUS_DATA_NOT_ACCEPTED
;
122 goto create_port_done
;
126 * Lookup by port name to see if this port with this name had been added
127 * (and deleted) previously.
129 vport
= OvsFindVportByHvNameW(gOvsSwitchContext
,
130 portParam
->PortFriendlyName
.String
,
131 portParam
->PortFriendlyName
.Length
);
132 if (vport
&& vport
->isAbsentOnHv
== FALSE
) {
133 OVS_LOG_ERROR("Port add failed since a port already exists on "
134 "the specified port Id: %u, ovsName: %s",
135 portParam
->PortId
, vport
->ovsName
);
136 status
= STATUS_DATA_NOT_ACCEPTED
;
137 goto create_port_done
;
141 ASSERT(vport
->isAbsentOnHv
);
142 ASSERT(vport
->portNo
!= OVS_DPPORT_NUMBER_INVALID
);
145 * It should be possible to simply just mark this port as "not deleted"
146 * given that the port Id and the name are the same and also provided
147 * that the other properties that we cache have not changed.
149 if (vport
->portType
!= portParam
->PortType
) {
150 OVS_LOG_INFO("Port add failed due to PortType change, port Id: %u"
151 " old: %u, new: %u", portParam
->PortId
,
152 vport
->portType
, portParam
->PortType
);
153 status
= STATUS_DATA_NOT_ACCEPTED
;
154 goto create_port_done
;
156 vport
->isAbsentOnHv
= FALSE
;
158 vport
= (POVS_VPORT_ENTRY
)OvsAllocateVport();
160 status
= NDIS_STATUS_RESOURCES
;
161 goto create_port_done
;
165 OvsInitVportWithPortParam(vport
, portParam
);
166 InitHvVportCommon(switchContext
, vport
, newPort
);
169 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
170 VPORT_PORT_EXIT(portParam
);
176 * Function updating the port properties
179 HvUpdatePort(POVS_SWITCH_CONTEXT switchContext
,
180 PNDIS_SWITCH_PORT_PARAMETERS portParam
)
182 POVS_VPORT_ENTRY vport
;
183 LOCK_STATE_EX lockState
;
184 OVS_VPORT_STATE ovsState
;
185 NDIS_SWITCH_NIC_STATE nicState
;
187 VPORT_PORT_ENTER(portParam
);
189 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
190 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
191 portParam
->PortId
, 0);
193 * Update properties only for NETDEV ports for supprting PS script
194 * We don't allow changing the names of the internal or external ports
196 if (vport
== NULL
|| (( vport
->portType
!= NdisSwitchPortTypeSynthetic
) &&
197 ( vport
->portType
!= NdisSwitchPortTypeEmulated
))) {
198 goto update_port_done
;
201 /* Store the nic and the OVS states as Nic Create won't be called */
202 ovsState
= vport
->ovsState
;
203 nicState
= vport
->nicState
;
206 * Currently only the port friendly name is being updated
207 * Make sure that no other properties are changed
209 ASSERT(portParam
->PortId
== vport
->portId
);
210 ASSERT(portParam
->PortState
== vport
->portState
);
211 ASSERT(portParam
->PortType
== vport
->portType
);
214 * Call the set parameters function the handle all properties
215 * change in a single place in case future version supports change of
218 OvsInitVportWithPortParam(vport
, portParam
);
219 /* Retore the nic and OVS states */
220 vport
->nicState
= nicState
;
221 vport
->ovsState
= ovsState
;
224 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
225 VPORT_PORT_EXIT(portParam
);
227 /* Must always return success */
228 return NDIS_STATUS_SUCCESS
;
232 HvTeardownPort(POVS_SWITCH_CONTEXT switchContext
,
233 PNDIS_SWITCH_PORT_PARAMETERS portParam
)
235 POVS_VPORT_ENTRY vport
;
236 LOCK_STATE_EX lockState
;
238 VPORT_PORT_ENTER(portParam
);
240 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
241 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
242 portParam
->PortId
, 0);
244 /* add assertion here */
245 vport
->portState
= NdisSwitchPortStateTeardown
;
246 vport
->ovsState
= OVS_STATE_PORT_TEAR_DOWN
;
248 OVS_LOG_WARN("Vport not present.");
250 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
252 VPORT_PORT_EXIT(portParam
);
257 HvDeletePort(POVS_SWITCH_CONTEXT switchContext
,
258 PNDIS_SWITCH_PORT_PARAMETERS portParams
)
260 POVS_VPORT_ENTRY vport
;
261 LOCK_STATE_EX lockState
;
263 VPORT_PORT_ENTER(portParams
);
265 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
266 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
267 portParams
->PortId
, 0);
270 * XXX: we can only destroy and remove the port if its datapath port
271 * counterpart was deleted. If the datapath port counterpart is present,
272 * we only mark the vport for deletion, so that a netlink command vport
273 * delete will delete the vport.
276 OvsRemoveAndDeleteVport(NULL
, switchContext
, vport
, TRUE
, FALSE
);
278 OVS_LOG_WARN("Vport not present.");
280 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
282 VPORT_PORT_EXIT(portParams
);
287 * Functions implemented in relaton to NDIS NIC manipulation.
290 HvCreateNic(POVS_SWITCH_CONTEXT switchContext
,
291 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
293 POVS_VPORT_ENTRY vport
;
296 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
298 LOCK_STATE_EX lockState
;
300 VPORT_NIC_ENTER(nicParam
);
302 /* Wait for lists to be initialized. */
303 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
305 if (!switchContext
->isActivated
) {
306 OVS_LOG_WARN("Switch is not activated yet.");
307 /* Veto the creation of nic */
308 status
= NDIS_STATUS_NOT_SUPPORTED
;
312 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
313 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
, nicParam
->PortId
, 0);
315 OVS_LOG_ERROR("Create NIC without Switch Port,"
316 " PortId: %x, NicIndex: %d",
317 nicParam
->PortId
, nicParam
->NicIndex
);
318 status
= NDIS_STATUS_INVALID_PARAMETER
;
322 if (nicParam
->NicType
== NdisSwitchNicTypeExternal
&&
323 nicParam
->NicIndex
!= 0) {
324 POVS_VPORT_ENTRY virtExtVport
=
325 (POVS_VPORT_ENTRY
)switchContext
->virtualExternalVport
;
327 vport
= (POVS_VPORT_ENTRY
)OvsAllocateVport();
329 status
= NDIS_STATUS_RESOURCES
;
332 OvsInitPhysNicVport(vport
, virtExtVport
, nicParam
->NicIndex
);
333 status
= InitHvVportCommon(switchContext
, vport
, TRUE
);
334 if (status
!= NDIS_STATUS_SUCCESS
) {
335 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
339 OvsInitVportWithNicParam(switchContext
, vport
, nicParam
);
340 portNo
= vport
->portNo
;
341 if (vport
->ovsState
== OVS_STATE_CONNECTED
) {
342 event
= OVS_EVENT_CONNECT
| OVS_EVENT_LINK_UP
;
343 } else if (vport
->ovsState
== OVS_STATE_NIC_CREATED
) {
344 event
= OVS_EVENT_CONNECT
;
348 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
349 if (portNo
!= OVS_DPPORT_NUMBER_INVALID
&& event
) {
350 OvsPostEvent(portNo
, event
);
354 VPORT_NIC_EXIT(nicParam
);
355 OVS_LOG_TRACE("Exit: status %8x.\n", status
);
361 /* Mark already created NIC as connected. */
363 HvConnectNic(POVS_SWITCH_CONTEXT switchContext
,
364 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
366 LOCK_STATE_EX lockState
;
367 POVS_VPORT_ENTRY vport
;
370 VPORT_NIC_ENTER(nicParam
);
372 /* Wait for lists to be initialized. */
373 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
375 if (!switchContext
->isActivated
) {
376 OVS_LOG_WARN("Switch is not activated yet.");
380 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
381 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
386 OVS_LOG_WARN("Vport not present.");
387 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
392 vport
->ovsState
= OVS_STATE_CONNECTED
;
393 vport
->nicState
= NdisSwitchNicStateConnected
;
394 portNo
= vport
->portNo
;
396 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
398 /* XXX only if portNo != INVALID or always? */
399 OvsPostEvent(portNo
, OVS_EVENT_LINK_UP
);
401 if (nicParam
->NicType
== NdisSwitchNicTypeInternal
) {
402 OvsInternalAdapterUp(portNo
, &nicParam
->NetCfgInstanceId
);
406 VPORT_NIC_EXIT(nicParam
);
410 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext
,
411 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
413 POVS_VPORT_ENTRY vport
;
414 LOCK_STATE_EX lockState
;
416 UINT32 status
= 0, portNo
= 0;
418 VPORT_NIC_ENTER(nicParam
);
420 /* Wait for lists to be initialized. */
421 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
423 if (!switchContext
->isActivated
) {
424 OVS_LOG_WARN("Switch is not activated yet.");
425 goto update_nic_done
;
428 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
429 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
433 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
434 OVS_LOG_WARN("Vport search failed.");
435 goto update_nic_done
;
437 switch (nicParam
->NicType
) {
438 case NdisSwitchNicTypeExternal
:
439 case NdisSwitchNicTypeInternal
:
440 RtlCopyMemory(&vport
->netCfgInstanceId
, &nicParam
->NetCfgInstanceId
,
443 case NdisSwitchNicTypeSynthetic
:
444 case NdisSwitchNicTypeEmulated
:
445 if (!RtlEqualMemory(vport
->vmMacAddress
, nicParam
->VMMacAddress
,
446 sizeof (vport
->vmMacAddress
))) {
447 status
|= OVS_EVENT_MAC_CHANGE
;
448 RtlCopyMemory(vport
->vmMacAddress
, nicParam
->VMMacAddress
,
449 sizeof (vport
->vmMacAddress
));
455 if (!RtlEqualMemory(vport
->permMacAddress
, nicParam
->PermanentMacAddress
,
456 sizeof (vport
->permMacAddress
))) {
457 RtlCopyMemory(vport
->permMacAddress
, nicParam
->PermanentMacAddress
,
458 sizeof (vport
->permMacAddress
));
459 status
|= OVS_EVENT_MAC_CHANGE
;
461 if (!RtlEqualMemory(vport
->currMacAddress
, nicParam
->CurrentMacAddress
,
462 sizeof (vport
->currMacAddress
))) {
463 RtlCopyMemory(vport
->currMacAddress
, nicParam
->CurrentMacAddress
,
464 sizeof (vport
->currMacAddress
));
465 status
|= OVS_EVENT_MAC_CHANGE
;
468 if (vport
->mtu
!= nicParam
->MTU
) {
469 vport
->mtu
= nicParam
->MTU
;
470 status
|= OVS_EVENT_MTU_CHANGE
;
472 vport
->numaNodeId
= nicParam
->NumaNodeId
;
473 portNo
= vport
->portNo
;
475 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
476 if (status
&& portNo
) {
477 OvsPostEvent(portNo
, status
);
480 VPORT_NIC_EXIT(nicParam
);
485 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext
,
486 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
488 POVS_VPORT_ENTRY vport
;
490 LOCK_STATE_EX lockState
;
491 BOOLEAN isInternalPort
= FALSE
;
493 VPORT_NIC_ENTER(nicParam
);
495 /* Wait for lists to be initialized. */
496 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
498 if (!switchContext
->isActivated
) {
499 OVS_LOG_WARN("Switch is not activated yet.");
503 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
504 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
509 OVS_LOG_WARN("Vport not present.");
510 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
514 vport
->nicState
= NdisSwitchNicStateDisconnected
;
515 vport
->ovsState
= OVS_STATE_NIC_CREATED
;
516 portNo
= vport
->portNo
;
518 if (vport
->ovsType
== OVS_VPORT_TYPE_INTERNAL
) {
519 isInternalPort
= TRUE
;
522 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
524 /* XXX if portNo != INVALID or always? */
525 OvsPostEvent(portNo
, OVS_EVENT_LINK_DOWN
);
527 if (isInternalPort
) {
528 OvsInternalAdapterDown();
532 VPORT_NIC_EXIT(nicParam
);
537 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext
,
538 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
540 LOCK_STATE_EX lockState
;
541 POVS_VPORT_ENTRY vport
;
544 VPORT_NIC_ENTER(nicParam
);
545 /* Wait for lists to be initialized. */
546 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
548 if (!switchContext
->isActivated
) {
549 OVS_LOG_WARN("Switch is not activated yet.");
553 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
554 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
559 OVS_LOG_WARN("Vport not present.");
560 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
564 vport
->nicState
= NdisSwitchNicStateUnknown
;
565 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
567 portNo
= vport
->portNo
;
568 if (vport
->portType
== NdisSwitchPortTypeExternal
&&
569 vport
->nicIndex
!= 0) {
570 OvsRemoveAndDeleteVport(NULL
, switchContext
, vport
, TRUE
, FALSE
);
573 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
574 /* XXX if portNo != INVALID or always? */
575 OvsPostEvent(portNo
, OVS_EVENT_DISCONNECT
);
578 VPORT_NIC_EXIT(nicParam
);
583 * OVS Vport related functionality.
586 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext
,
589 POVS_VPORT_ENTRY vport
;
590 PLIST_ENTRY head
, link
;
591 UINT32 hash
= OvsJhashBytes((const VOID
*)&portNo
, sizeof(portNo
),
593 head
= &(switchContext
->portNoHashArray
[hash
& OVS_VPORT_MASK
]);
594 LIST_FORALL(head
, link
) {
595 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portNoLink
);
596 if (vport
->portNo
== portNo
) {
605 OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext
,
607 OVS_VPORT_TYPE ovsPortType
)
609 POVS_VPORT_ENTRY vport
;
610 PLIST_ENTRY head
, link
;
611 UINT32 hash
= OvsJhashBytes((const VOID
*)&dstPort
, sizeof(dstPort
),
613 head
= &(switchContext
->tunnelVportsArray
[hash
& OVS_VPORT_MASK
]);
614 LIST_FORALL(head
, link
) {
615 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, tunnelVportLink
);
616 if (GetPortFromPriv(vport
) == dstPort
&&
617 vport
->ovsType
== ovsPortType
) {
626 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext
,
629 POVS_VPORT_ENTRY vport
;
630 PLIST_ENTRY head
, link
;
632 SIZE_T length
= strlen(name
) + 1;
634 hash
= OvsJhashBytes((const VOID
*)name
, length
, OVS_HASH_BASIS
);
635 head
= &(switchContext
->ovsPortNameHashArray
[hash
& OVS_VPORT_MASK
]);
637 LIST_FORALL(head
, link
) {
638 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, ovsNameLink
);
639 if (!strcmp(name
, vport
->ovsName
)) {
647 /* OvsFindVportByHvName: "name" is assumed to be null-terminated */
649 OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext
,
650 PWSTR wsName
, SIZE_T wstrSize
)
652 POVS_VPORT_ENTRY vport
= NULL
;
653 PLIST_ENTRY head
, link
;
656 for (i
= 0; i
< OVS_MAX_VPORT_ARRAY_SIZE
; i
++) {
657 head
= &(switchContext
->portIdHashArray
[i
]);
658 LIST_FORALL(head
, link
) {
659 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portIdLink
);
662 * NOTE about portFriendlyName:
663 * If the string is NULL-terminated, the Length member does not
664 * include the terminating NULL character.
666 if (vport
->portFriendlyName
.Length
== wstrSize
&&
667 RtlEqualMemory(wsName
, vport
->portFriendlyName
.String
,
668 vport
->portFriendlyName
.Length
)) {
677 * Look in the list of ports that were added from the Hyper-V switch and
681 for (i
= 0; i
< OVS_MAX_VPORT_ARRAY_SIZE
; i
++) {
682 head
= &(switchContext
->portNoHashArray
[i
]);
683 LIST_FORALL(head
, link
) {
684 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portNoLink
);
685 if (vport
->portFriendlyName
.Length
== wstrSize
&&
686 RtlEqualMemory(wsName
, vport
->portFriendlyName
.String
,
687 vport
->portFriendlyName
.Length
)) {
701 OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext
,
704 POVS_VPORT_ENTRY vport
= NULL
;
705 /* 'portFriendlyName' is not NUL-terminated. */
706 SIZE_T length
= strlen(name
);
707 SIZE_T wstrSize
= length
* sizeof(WCHAR
);
710 PWSTR wsName
= OvsAllocateMemoryWithTag(wstrSize
, OVS_VPORT_POOL_TAG
);
714 for (i
= 0; i
< length
; i
++) {
717 vport
= OvsFindVportByHvNameW(switchContext
, wsName
, wstrSize
);
718 OvsFreeMemoryWithTag(wsName
, OVS_VPORT_POOL_TAG
);
723 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext
,
724 NDIS_SWITCH_PORT_ID portId
,
725 NDIS_SWITCH_NIC_INDEX index
)
727 if (switchContext
->virtualExternalVport
&&
728 portId
== switchContext
->virtualExternalPortId
&&
729 index
== switchContext
->virtualExternalVport
->nicIndex
) {
730 return (POVS_VPORT_ENTRY
)switchContext
->virtualExternalVport
;
731 } else if (switchContext
->internalVport
&&
732 portId
== switchContext
->internalPortId
&&
733 index
== switchContext
->internalVport
->nicIndex
) {
734 return (POVS_VPORT_ENTRY
)switchContext
->internalVport
;
736 PLIST_ENTRY head
, link
;
737 POVS_VPORT_ENTRY vport
;
739 hash
= OvsJhashWords((UINT32
*)&portId
, 1, OVS_HASH_BASIS
);
740 head
= &(switchContext
->portIdHashArray
[hash
& OVS_VPORT_MASK
]);
741 LIST_FORALL(head
, link
) {
742 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portIdLink
);
743 if (portId
== vport
->portId
&& index
== vport
->nicIndex
) {
752 OvsAllocateVport(VOID
)
754 POVS_VPORT_ENTRY vport
;
755 vport
= (POVS_VPORT_ENTRY
)OvsAllocateMemoryWithTag(
756 sizeof(OVS_VPORT_ENTRY
), OVS_VPORT_POOL_TAG
);
760 RtlZeroMemory(vport
, sizeof (OVS_VPORT_ENTRY
));
761 vport
->ovsState
= OVS_STATE_UNKNOWN
;
762 vport
->isAbsentOnHv
= FALSE
;
763 vport
->portNo
= OVS_DPPORT_NUMBER_INVALID
;
765 InitializeListHead(&vport
->ovsNameLink
);
766 InitializeListHead(&vport
->portIdLink
);
767 InitializeListHead(&vport
->portNoLink
);
773 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport
,
774 PNDIS_SWITCH_PORT_PARAMETERS portParam
)
776 vport
->portType
= portParam
->PortType
;
777 vport
->portState
= portParam
->PortState
;
778 vport
->portId
= portParam
->PortId
;
779 vport
->nicState
= NdisSwitchNicStateUnknown
;
780 vport
->isExternal
= FALSE
;
781 vport
->isBridgeInternal
= FALSE
;
783 switch (vport
->portType
) {
784 case NdisSwitchPortTypeExternal
:
785 vport
->isExternal
= TRUE
;
786 vport
->ovsType
= OVS_VPORT_TYPE_NETDEV
;
788 case NdisSwitchPortTypeInternal
:
789 vport
->ovsType
= OVS_VPORT_TYPE_INTERNAL
;
791 case NdisSwitchPortTypeSynthetic
:
792 case NdisSwitchPortTypeEmulated
:
793 vport
->ovsType
= OVS_VPORT_TYPE_NETDEV
;
796 RtlCopyMemory(&vport
->hvPortName
, &portParam
->PortName
,
797 sizeof (NDIS_SWITCH_PORT_NAME
));
798 /* For external and internal ports, 'portFriendlyName' is overwritten
800 RtlCopyMemory(&vport
->portFriendlyName
, &portParam
->PortFriendlyName
,
801 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME
));
803 switch (vport
->portState
) {
804 case NdisSwitchPortStateCreated
:
805 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
807 case NdisSwitchPortStateTeardown
:
808 vport
->ovsState
= OVS_STATE_PORT_TEAR_DOWN
;
810 case NdisSwitchPortStateDeleted
:
811 vport
->ovsState
= OVS_STATE_PORT_DELETED
;
818 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext
,
819 POVS_VPORT_ENTRY vport
,
820 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
822 ASSERT(vport
->portId
== nicParam
->PortId
);
823 ASSERT(vport
->ovsState
== OVS_STATE_PORT_CREATED
);
825 UNREFERENCED_PARAMETER(switchContext
);
827 RtlCopyMemory(vport
->permMacAddress
, nicParam
->PermanentMacAddress
,
828 sizeof (nicParam
->PermanentMacAddress
));
829 RtlCopyMemory(vport
->currMacAddress
, nicParam
->CurrentMacAddress
,
830 sizeof (nicParam
->CurrentMacAddress
));
832 if (nicParam
->NicType
== NdisSwitchNicTypeSynthetic
||
833 nicParam
->NicType
== NdisSwitchNicTypeEmulated
) {
834 RtlCopyMemory(vport
->vmMacAddress
, nicParam
->VMMacAddress
,
835 sizeof (nicParam
->VMMacAddress
));
836 RtlCopyMemory(&vport
->vmName
, &nicParam
->VmName
,
837 sizeof (nicParam
->VmName
));
839 RtlCopyMemory(&vport
->netCfgInstanceId
, &nicParam
->NetCfgInstanceId
,
840 sizeof (nicParam
->NetCfgInstanceId
));
842 RtlCopyMemory(&vport
->nicName
, &nicParam
->NicName
,
843 sizeof (nicParam
->NicName
));
844 vport
->mtu
= nicParam
->MTU
;
845 vport
->nicState
= nicParam
->NicState
;
846 vport
->nicIndex
= nicParam
->NicIndex
;
847 vport
->numaNodeId
= nicParam
->NumaNodeId
;
849 switch (vport
->nicState
) {
850 case NdisSwitchNicStateCreated
:
851 vport
->ovsState
= OVS_STATE_NIC_CREATED
;
853 case NdisSwitchNicStateConnected
:
854 vport
->ovsState
= OVS_STATE_CONNECTED
;
856 case NdisSwitchNicStateDisconnected
:
857 vport
->ovsState
= OVS_STATE_NIC_CREATED
;
859 case NdisSwitchNicStateDeleted
:
860 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
866 * --------------------------------------------------------------------------
867 * Copies the relevant NDIS port properties from a virtual (pseudo) external
868 * NIC to a physical (real) external NIC.
869 * --------------------------------------------------------------------------
872 OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVport
,
873 POVS_VPORT_ENTRY virtExtVport
,
876 physExtVport
->portType
= virtExtVport
->portType
;
877 physExtVport
->portState
= virtExtVport
->portState
;
878 physExtVport
->portId
= virtExtVport
->portId
;
879 physExtVport
->nicState
= NdisSwitchNicStateUnknown
;
880 physExtVport
->ovsType
= OVS_VPORT_TYPE_NETDEV
;
881 physExtVport
->isExternal
= TRUE
;
882 physExtVport
->isBridgeInternal
= FALSE
;
883 physExtVport
->nicIndex
= (NDIS_SWITCH_NIC_INDEX
)physNicIndex
;
885 RtlCopyMemory(&physExtVport
->hvPortName
, &virtExtVport
->hvPortName
,
886 sizeof (NDIS_SWITCH_PORT_NAME
));
888 /* 'portFriendlyName' is overwritten later. */
889 RtlCopyMemory(&physExtVport
->portFriendlyName
,
890 &virtExtVport
->portFriendlyName
,
891 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME
));
893 physExtVport
->ovsState
= OVS_STATE_PORT_CREATED
;
897 * --------------------------------------------------------------------------
898 * Initializes a tunnel vport.
899 * --------------------------------------------------------------------------
902 OvsInitTunnelVport(PVOID userContext
,
903 POVS_VPORT_ENTRY vport
,
904 OVS_VPORT_TYPE ovsType
,
907 NTSTATUS status
= STATUS_SUCCESS
;
908 POVS_USER_PARAMS_CONTEXT usrParamsCtx
=
909 (POVS_USER_PARAMS_CONTEXT
)userContext
;
911 vport
->isBridgeInternal
= FALSE
;
912 vport
->ovsType
= ovsType
;
913 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
915 case OVS_VPORT_TYPE_GRE
:
917 case OVS_VPORT_TYPE_VXLAN
:
919 POVS_TUNFLT_INIT_CONTEXT tunnelContext
= NULL
;
921 tunnelContext
= OvsAllocateMemoryWithTag(sizeof(*tunnelContext
),
923 if (tunnelContext
== NULL
) {
924 status
= STATUS_INSUFFICIENT_RESOURCES
;
927 tunnelContext
->inputBuffer
= usrParamsCtx
->inputBuffer
;
928 tunnelContext
->outputBuffer
= usrParamsCtx
->outputBuffer
;
929 tunnelContext
->outputLength
= usrParamsCtx
->outputLength
;
930 tunnelContext
->vport
= vport
;
932 status
= OvsInitVxlanTunnel(usrParamsCtx
->irp
,
935 OvsTunnelVportPendingInit
,
936 (PVOID
)tunnelContext
);
937 if (status
!= STATUS_PENDING
) {
938 OvsFreeMemoryWithTag(tunnelContext
, OVS_VPORT_POOL_TAG
);
939 tunnelContext
= NULL
;
943 case OVS_VPORT_TYPE_STT
:
944 status
= OvsInitSttTunnel(vport
, dstPort
);
953 * --------------------------------------------------------------------------
954 * Initializes a bridge internal vport ie. a port of type
955 * OVS_VPORT_TYPE_INTERNAL but not present on the Hyper-V switch.
956 * --------------------------------------------------------------------------
959 OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport
)
961 vport
->isBridgeInternal
= TRUE
;
962 vport
->ovsType
= OVS_VPORT_TYPE_INTERNAL
;
963 /* Mark the status to be connected, since there is no other initialization
965 vport
->ovsState
= OVS_STATE_CONNECTED
;
966 return STATUS_SUCCESS
;
970 * --------------------------------------------------------------------------
971 * For external vports 'portFriendlyName' provided by Hyper-V is over-written
972 * by synthetic names.
973 * --------------------------------------------------------------------------
976 AssignNicNameSpecial(POVS_VPORT_ENTRY vport
)
980 if (vport
->portType
== NdisSwitchPortTypeExternal
) {
981 if (vport
->nicIndex
== 0) {
982 ASSERT(vport
->nicIndex
== 0);
983 RtlStringCbPrintfW(vport
->portFriendlyName
.String
,
985 L
"%s.virtualAdapter", OVS_DPPORT_EXTERNAL_NAME_W
);
987 RtlStringCbPrintfW(vport
->portFriendlyName
.String
,
989 L
"%s.%lu", OVS_DPPORT_EXTERNAL_NAME_W
,
990 (UINT32
)vport
->nicIndex
);
993 RtlStringCbPrintfW(vport
->portFriendlyName
.String
,
995 L
"%s", OVS_DPPORT_INTERNAL_NAME_W
);
998 RtlStringCbLengthW(vport
->portFriendlyName
.String
, IF_MAX_STRING_SIZE
,
1000 vport
->portFriendlyName
.Length
= (USHORT
)len
;
1005 * --------------------------------------------------------------------------
1006 * Functionality common to any port on the Hyper-V switch. This function is not
1007 * to be called for a port that is not on the Hyper-V switch.
1009 * Inserts the port into 'portIdHashArray' and caches the pointer in the
1010 * 'switchContext' if needed.
1012 * For external NIC, assigns the name for the NIC.
1013 * --------------------------------------------------------------------------
1016 InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext
,
1017 POVS_VPORT_ENTRY vport
,
1022 switch (vport
->portType
) {
1023 case NdisSwitchPortTypeExternal
:
1025 * Overwrite the 'portFriendlyName' of this external vport. The reason
1026 * for having this in common code is to be able to call it from the NDIS
1027 * Port callback as well as the NDIS NIC callback.
1029 AssignNicNameSpecial(vport
);
1031 if (vport
->nicIndex
== 0) {
1032 switchContext
->virtualExternalPortId
= vport
->portId
;
1033 switchContext
->virtualExternalVport
= vport
;
1035 switchContext
->numPhysicalNics
++;
1038 case NdisSwitchPortTypeInternal
:
1039 ASSERT(vport
->isBridgeInternal
== FALSE
);
1041 /* Overwrite the 'portFriendlyName' of the internal vport. */
1042 AssignNicNameSpecial(vport
);
1043 switchContext
->internalPortId
= vport
->portId
;
1044 switchContext
->internalVport
= vport
;
1046 case NdisSwitchPortTypeSynthetic
:
1047 case NdisSwitchPortTypeEmulated
:
1052 * It is important to not insert vport corresponding to virtual external
1053 * port into the 'portIdHashArray' since the port should not be exposed to
1056 if (vport
->portType
== NdisSwitchPortTypeExternal
&&
1057 vport
->nicIndex
== 0) {
1058 return NDIS_STATUS_SUCCESS
;
1062 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
1063 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
1064 * hyper-v switch seems to use only 2 bytes out of 4.
1066 hash
= OvsJhashWords(&vport
->portId
, 1, OVS_HASH_BASIS
);
1067 InsertHeadList(&switchContext
->portIdHashArray
[hash
& OVS_VPORT_MASK
],
1068 &vport
->portIdLink
);
1070 switchContext
->numHvVports
++;
1072 return NDIS_STATUS_SUCCESS
;
1076 * --------------------------------------------------------------------------
1077 * Functionality common to any port added from OVS userspace.
1079 * Inserts the port into 'portNoHashArray', 'ovsPortNameHashArray' and in
1080 * 'tunnelVportsArray' if appropriate.
1081 * --------------------------------------------------------------------------
1084 InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext
,
1085 POVS_VPORT_ENTRY vport
)
1089 switch(vport
->ovsType
) {
1090 case OVS_VPORT_TYPE_VXLAN
:
1091 case OVS_VPORT_TYPE_STT
:
1093 UINT16 dstPort
= GetPortFromPriv(vport
);
1094 hash
= OvsJhashBytes(&dstPort
,
1098 &gOvsSwitchContext
->tunnelVportsArray
[hash
& OVS_VPORT_MASK
],
1099 &vport
->tunnelVportLink
);
1100 switchContext
->numNonHvVports
++;
1103 case OVS_VPORT_TYPE_INTERNAL
:
1104 if (vport
->isBridgeInternal
) {
1105 switchContext
->numNonHvVports
++;
1112 * Insert the port into the hash array of ports: by port number and ovs
1113 * and ovs (datapath) port name.
1114 * NOTE: OvsJhashWords has portNo as "1" word. This is ok, because the
1115 * portNo is stored in 2 bytes only (max port number = MAXUINT16).
1117 hash
= OvsJhashWords(&vport
->portNo
, 1, OVS_HASH_BASIS
);
1118 InsertHeadList(&gOvsSwitchContext
->portNoHashArray
[hash
& OVS_VPORT_MASK
],
1119 &vport
->portNoLink
);
1121 hash
= OvsJhashBytes(vport
->ovsName
, strlen(vport
->ovsName
) + 1,
1124 &gOvsSwitchContext
->ovsPortNameHashArray
[hash
& OVS_VPORT_MASK
],
1125 &vport
->ovsNameLink
);
1127 return STATUS_SUCCESS
;
1132 * --------------------------------------------------------------------------
1133 * Provides functionality that is partly complementatry to
1134 * InitOvsVportCommon()/InitHvVportCommon().
1136 * 'hvDelete' indicates if caller is removing the vport as a result of the
1137 * port being removed on the Hyper-V switch.
1138 * 'ovsDelete' indicates if caller is removing the vport as a result of the
1139 * port being removed from OVS userspace.
1140 * --------------------------------------------------------------------------
1143 OvsRemoveAndDeleteVport(PVOID usrParamsContext
,
1144 POVS_SWITCH_CONTEXT switchContext
,
1145 POVS_VPORT_ENTRY vport
,
1149 POVS_USER_PARAMS_CONTEXT usrParamsCtx
=
1150 (POVS_USER_PARAMS_CONTEXT
)usrParamsContext
;
1151 BOOLEAN hvSwitchPort
= FALSE
;
1152 BOOLEAN deletedOnOvs
= FALSE
;
1153 BOOLEAN deletedOnHv
= FALSE
;
1155 switch (vport
->ovsType
) {
1156 case OVS_VPORT_TYPE_INTERNAL
:
1157 if (!vport
->isBridgeInternal
) {
1158 if (hvDelete
&& vport
->isAbsentOnHv
== FALSE
) {
1159 switchContext
->internalPortId
= 0;
1160 switchContext
->internalVport
= NULL
;
1161 OvsInternalAdapterDown();
1163 hvSwitchPort
= TRUE
;
1166 case OVS_VPORT_TYPE_VXLAN
:
1169 status
= OvsRemoveTunnelVport(usrParamsCtx
, switchContext
, vport
,
1170 hvDelete
, ovsDelete
);
1171 if (status
!= STATUS_SUCCESS
) {
1175 case OVS_VPORT_TYPE_STT
:
1176 OvsCleanupSttTunnel(vport
);
1178 case OVS_VPORT_TYPE_GRE
:
1180 case OVS_VPORT_TYPE_NETDEV
:
1181 if (vport
->isExternal
) {
1182 if (vport
->nicIndex
== 0) {
1183 /* Such a vport is not part of any of the hash tables, since it
1184 * is not exposed to userspace. See Vport.h for explanation. */
1185 ASSERT(hvDelete
== TRUE
);
1186 ASSERT(switchContext
->numPhysicalNics
== 0);
1187 switchContext
->virtualExternalPortId
= 0;
1188 switchContext
->virtualExternalVport
= NULL
;
1189 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
1190 return STATUS_SUCCESS
;
1193 hvSwitchPort
= TRUE
;
1199 * 'hvDelete' == TRUE indicates that the port should be removed from the
1200 * 'portIdHashArray', while 'ovsDelete' == TRUE indicates that the port
1201 * should be removed from 'portNoHashArray' and the 'ovsPortNameHashArray'.
1203 * Both 'hvDelete' and 'ovsDelete' can be set to TRUE by the caller.
1205 if (vport
->isAbsentOnHv
== TRUE
) {
1208 if (vport
->portNo
== OVS_DPPORT_NUMBER_INVALID
) {
1209 deletedOnOvs
= TRUE
;
1212 if (hvDelete
&& !deletedOnHv
) {
1213 vport
->isAbsentOnHv
= TRUE
;
1215 if (vport
->isExternal
) {
1216 ASSERT(vport
->nicIndex
!= 0);
1217 ASSERT(switchContext
->numPhysicalNics
);
1218 switchContext
->numPhysicalNics
--;
1221 /* Remove the port from the relevant lists. */
1222 RemoveEntryList(&vport
->portIdLink
);
1223 InitializeListHead(&vport
->portIdLink
);
1226 if (ovsDelete
&& !deletedOnOvs
) {
1227 vport
->portNo
= OVS_DPPORT_NUMBER_INVALID
;
1228 vport
->ovsName
[0] = '\0';
1230 /* Remove the port from the relevant lists. */
1231 RemoveEntryList(&vport
->ovsNameLink
);
1232 InitializeListHead(&vport
->ovsNameLink
);
1233 RemoveEntryList(&vport
->portNoLink
);
1234 InitializeListHead(&vport
->portNoLink
);
1235 if (OVS_VPORT_TYPE_VXLAN
== vport
->ovsType
||
1236 OVS_VPORT_TYPE_STT
== vport
->ovsType
) {
1237 RemoveEntryList(&vport
->tunnelVportLink
);
1238 InitializeListHead(&vport
->tunnelVportLink
);
1241 deletedOnOvs
= TRUE
;
1245 * Deallocate the port if it has been deleted on the Hyper-V switch as well
1248 if (deletedOnHv
&& deletedOnOvs
) {
1250 switchContext
->numHvVports
--;
1252 switchContext
->numNonHvVports
--;
1254 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
1257 return STATUS_SUCCESS
;
1261 OvsRemoveTunnelVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
1262 POVS_SWITCH_CONTEXT switchContext
,
1263 POVS_VPORT_ENTRY vport
,
1267 POVS_TUNFLT_INIT_CONTEXT tunnelContext
= NULL
;
1270 tunnelContext
= OvsAllocateMemory(sizeof(*tunnelContext
));
1271 if (tunnelContext
== NULL
) {
1272 return STATUS_INSUFFICIENT_RESOURCES
;
1274 RtlZeroMemory(tunnelContext
, sizeof(*tunnelContext
));
1276 tunnelContext
->switchContext
= switchContext
;
1277 tunnelContext
->hvSwitchPort
= FALSE
;
1278 tunnelContext
->hvDelete
= hvDelete
;
1279 tunnelContext
->ovsDelete
= ovsDelete
;
1280 tunnelContext
->vport
= vport
;
1283 tunnelContext
->inputBuffer
= usrParamsCtx
->inputBuffer
;
1284 tunnelContext
->outputBuffer
= usrParamsCtx
->outputBuffer
;
1285 tunnelContext
->outputLength
= usrParamsCtx
->outputLength
;
1286 irp
= usrParamsCtx
->irp
;
1289 return OvsCleanupVxlanTunnel(irp
, vport
, OvsTunnelVportPendingRemove
,
1296 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext
)
1298 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
1300 PNDIS_SWITCH_PORT_PARAMETERS portParam
;
1301 PNDIS_SWITCH_PORT_ARRAY portArray
= NULL
;
1302 POVS_VPORT_ENTRY vport
;
1304 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext
);
1306 status
= OvsGetPortsOnSwitch(switchContext
, &portArray
);
1307 if (status
!= NDIS_STATUS_SUCCESS
) {
1311 for (arrIndex
= 0; arrIndex
< portArray
->NumElements
; arrIndex
++) {
1312 portParam
= NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray
, arrIndex
);
1314 if (portParam
->IsValidationPort
) {
1318 vport
= (POVS_VPORT_ENTRY
)OvsAllocateVport();
1319 if (vport
== NULL
) {
1320 status
= NDIS_STATUS_RESOURCES
;
1323 OvsInitVportWithPortParam(vport
, portParam
);
1324 status
= InitHvVportCommon(switchContext
, vport
, TRUE
);
1325 if (status
!= NDIS_STATUS_SUCCESS
) {
1326 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
1332 if (status
!= NDIS_STATUS_SUCCESS
) {
1333 OvsClearAllSwitchVports(switchContext
);
1336 OvsFreeSwitchPortsArray(portArray
);
1338 OVS_LOG_TRACE("Exit: status: %x", status
);
1345 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext
)
1347 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
1348 PNDIS_SWITCH_NIC_ARRAY nicArray
= NULL
;
1350 PNDIS_SWITCH_NIC_PARAMETERS nicParam
;
1351 POVS_VPORT_ENTRY vport
;
1353 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext
);
1355 * Now, get NIC list.
1357 status
= OvsGetNicsOnSwitch(switchContext
, &nicArray
);
1358 if (status
!= NDIS_STATUS_SUCCESS
) {
1361 for (arrIndex
= 0; arrIndex
< nicArray
->NumElements
; ++arrIndex
) {
1363 nicParam
= NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray
, arrIndex
);
1366 * XXX: Check if the port is configured with a VLAN. Disallow such a
1367 * configuration, since we don't support tag-in-tag.
1371 * XXX: Check if the port is connected to a VF. Disconnect the VF in
1375 if (nicParam
->NicType
== NdisSwitchNicTypeExternal
&&
1376 nicParam
->NicIndex
!= 0) {
1377 POVS_VPORT_ENTRY virtExtVport
=
1378 (POVS_VPORT_ENTRY
)switchContext
->virtualExternalVport
;
1380 vport
= OvsAllocateVport();
1382 OvsInitPhysNicVport(vport
, virtExtVport
,
1383 nicParam
->NicIndex
);
1384 status
= InitHvVportCommon(switchContext
, vport
, TRUE
);
1385 if (status
!= NDIS_STATUS_SUCCESS
) {
1386 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
1391 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
1393 nicParam
->NicIndex
);
1395 if (vport
== NULL
) {
1396 OVS_LOG_ERROR("Fail to allocate vport");
1399 OvsInitVportWithNicParam(switchContext
, vport
, nicParam
);
1400 if (nicParam
->NicType
== NdisSwitchNicTypeInternal
) {
1401 OvsInternalAdapterUp(vport
->portNo
, &nicParam
->NetCfgInstanceId
);
1406 OvsFreeSwitchNicsArray(nicArray
);
1408 OVS_LOG_TRACE("Exit: status: %x", status
);
1413 * --------------------------------------------------------------------------
1414 * Deletes ports added from the Hyper-V switch as well as OVS usersapce. The
1415 * function deletes ports in 'portIdHashArray'. This will delete most of the
1416 * ports that are in the 'portNoHashArray' as well. Any remaining ports
1417 * are deleted by walking the 'portNoHashArray'.
1418 * --------------------------------------------------------------------------
1421 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext
)
1423 for (UINT hash
= 0; hash
< OVS_MAX_VPORT_ARRAY_SIZE
; hash
++) {
1424 PLIST_ENTRY head
, link
, next
;
1426 head
= &(switchContext
->portIdHashArray
[hash
& OVS_VPORT_MASK
]);
1427 LIST_FORALL_SAFE(head
, link
, next
) {
1428 POVS_VPORT_ENTRY vport
;
1429 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portIdLink
);
1430 OvsRemoveAndDeleteVport(NULL
, switchContext
, vport
, TRUE
, TRUE
);
1435 * Remove 'virtualExternalVport' as well. This port is not part of the
1436 * 'portIdHashArray'.
1438 if (switchContext
->virtualExternalVport
) {
1439 OvsRemoveAndDeleteVport(NULL
, switchContext
,
1440 (POVS_VPORT_ENTRY
)switchContext
->virtualExternalVport
, TRUE
, TRUE
);
1444 for (UINT hash
= 0; hash
< OVS_MAX_VPORT_ARRAY_SIZE
; hash
++) {
1445 PLIST_ENTRY head
, link
, next
;
1446 head
= &(switchContext
->portNoHashArray
[hash
& OVS_VPORT_MASK
]);
1447 LIST_FORALL_SAFE(head
, link
, next
) {
1448 POVS_VPORT_ENTRY vport
;
1449 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portNoLink
);
1450 ASSERT(OvsIsTunnelVportType(vport
->ovsType
) ||
1451 (vport
->ovsType
== OVS_VPORT_TYPE_INTERNAL
&&
1452 vport
->isBridgeInternal
) || vport
->isAbsentOnHv
== TRUE
);
1453 OvsRemoveAndDeleteVport(NULL
, switchContext
, vport
, TRUE
, TRUE
);
1457 ASSERT(switchContext
->virtualExternalVport
== NULL
);
1458 ASSERT(switchContext
->internalVport
== NULL
);
1463 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr
,
1468 UNICODE_STRING ustr
;
1472 ustr
.Buffer
= wStr
->String
;
1473 ustr
.Length
= wStr
->Length
;
1474 ustr
.MaximumLength
= IF_MAX_STRING_SIZE
;
1477 astr
.MaximumLength
= maxStrLen
;
1480 size
= RtlUnicodeStringToAnsiSize(&ustr
);
1481 if (size
> maxStrLen
) {
1482 return STATUS_BUFFER_OVERFLOW
;
1485 status
= RtlUnicodeStringToAnsiString(&astr
, &ustr
, FALSE
);
1487 ASSERT(status
== STATUS_SUCCESS
);
1488 if (status
!= STATUS_SUCCESS
) {
1491 ASSERT(astr
.Length
<= maxStrLen
);
1492 str
[astr
.Length
] = 0;
1493 return STATUS_SUCCESS
;
1497 * --------------------------------------------------------------------------
1498 * Utility function that populates a 'OVS_VPORT_EXT_INFO' structure for the
1500 * --------------------------------------------------------------------------
1503 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet
,
1504 POVS_VPORT_EXT_INFO extInfo
)
1506 POVS_VPORT_ENTRY vport
;
1508 LOCK_STATE_EX lockState
;
1509 NTSTATUS status
= STATUS_SUCCESS
;
1510 BOOLEAN doConvert
= FALSE
;
1512 RtlZeroMemory(extInfo
, sizeof (POVS_VPORT_EXT_INFO
));
1513 NdisAcquireRWLockRead(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
1514 if (vportGet
->portNo
== 0) {
1515 StringCbLengthA(vportGet
->name
, OVS_MAX_PORT_NAME_LENGTH
- 1, &len
);
1516 vport
= OvsFindVportByHvNameA(gOvsSwitchContext
, vportGet
->name
);
1517 if (vport
!= NULL
) {
1518 /* If the port is not a Hyper-V port and it has been added earlier,
1519 * we'll find it in 'ovsPortNameHashArray'. */
1520 vport
= OvsFindVportByOvsName(gOvsSwitchContext
, vportGet
->name
);
1523 vport
= OvsFindVportByPortNo(gOvsSwitchContext
, vportGet
->portNo
);
1525 if (vport
== NULL
|| (vport
->ovsState
!= OVS_STATE_CONNECTED
&&
1526 vport
->ovsState
!= OVS_STATE_NIC_CREATED
)) {
1527 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1528 if (vportGet
->portNo
) {
1529 OVS_LOG_WARN("vport %u does not exist any more", vportGet
->portNo
);
1531 OVS_LOG_WARN("vport %s does not exist any more", vportGet
->name
);
1533 status
= STATUS_DEVICE_DOES_NOT_EXIST
;
1536 extInfo
->dpNo
= vportGet
->dpNo
;
1537 extInfo
->portNo
= vport
->portNo
;
1538 RtlCopyMemory(extInfo
->macAddress
, vport
->currMacAddress
,
1539 sizeof (vport
->currMacAddress
));
1540 RtlCopyMemory(extInfo
->permMACAddress
, vport
->permMacAddress
,
1541 sizeof (vport
->permMacAddress
));
1542 if (vport
->ovsType
== OVS_VPORT_TYPE_NETDEV
) {
1543 RtlCopyMemory(extInfo
->vmMACAddress
, vport
->vmMacAddress
,
1544 sizeof (vport
->vmMacAddress
));
1546 extInfo
->nicIndex
= vport
->nicIndex
;
1547 extInfo
->portId
= vport
->portId
;
1548 extInfo
->type
= vport
->ovsType
;
1549 extInfo
->mtu
= vport
->mtu
;
1553 if (vport
->ovsState
== OVS_STATE_NIC_CREATED
) {
1554 extInfo
->status
= OVS_EVENT_CONNECT
| OVS_EVENT_LINK_DOWN
;
1555 } else if (vport
->ovsState
== OVS_STATE_CONNECTED
) {
1556 extInfo
->status
= OVS_EVENT_CONNECT
| OVS_EVENT_LINK_UP
;
1558 extInfo
->status
= OVS_EVENT_DISCONNECT
;
1560 if (extInfo
->type
== OVS_VPORT_TYPE_NETDEV
&&
1561 (vport
->ovsState
== OVS_STATE_NIC_CREATED
||
1562 vport
->ovsState
== OVS_STATE_CONNECTED
)) {
1565 extInfo
->vmUUID
[0] = 0;
1566 extInfo
->vifUUID
[0] = 0;
1568 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1570 status
= OvsConvertIfCountedStrToAnsiStr(&vport
->portFriendlyName
,
1572 OVS_MAX_PORT_NAME_LENGTH
);
1573 if (status
!= STATUS_SUCCESS
) {
1574 OVS_LOG_INFO("Fail to convert NIC name.");
1575 extInfo
->vmUUID
[0] = 0;
1578 status
= OvsConvertIfCountedStrToAnsiStr(&vport
->vmName
,
1580 OVS_MAX_VM_UUID_LEN
);
1581 if (status
!= STATUS_SUCCESS
) {
1582 OVS_LOG_INFO("Fail to convert VM name.");
1583 extInfo
->vmUUID
[0] = 0;
1586 status
= OvsConvertIfCountedStrToAnsiStr(&vport
->nicName
,
1588 OVS_MAX_VIF_UUID_LEN
);
1589 if (status
!= STATUS_SUCCESS
) {
1590 OVS_LOG_INFO("Fail to convert nic UUID");
1591 extInfo
->vifUUID
[0] = 0;
1594 * for now ignore status
1596 status
= STATUS_SUCCESS
;
1604 * --------------------------------------------------------------------------
1605 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1606 * --------------------------------------------------------------------------
1609 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
1612 NTSTATUS status
= STATUS_SUCCESS
;
1613 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
1614 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
1615 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
1616 OVS_VPORT_GET vportGet
;
1617 OVS_VPORT_EXT_INFO info
;
1619 static const NL_POLICY ovsNetdevPolicy
[] = {
1620 [OVS_WIN_NETDEV_ATTR_NAME
] = { .type
= NL_A_STRING
,
1622 .maxLen
= IFNAMSIZ
},
1624 PNL_ATTR netdevAttrs
[ARRAY_SIZE(ovsNetdevPolicy
)];
1626 /* input buffer has been validated while validating transaction dev op. */
1627 ASSERT(usrParamsCtx
->inputBuffer
!= NULL
&&
1628 usrParamsCtx
->inputLength
> sizeof *msgIn
);
1630 if (msgOut
== NULL
|| usrParamsCtx
->outputLength
< sizeof *msgOut
) {
1631 return STATUS_INVALID_BUFFER_SIZE
;
1634 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
1635 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
1636 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
1637 ovsNetdevPolicy
, ARRAY_SIZE(ovsNetdevPolicy
),
1638 netdevAttrs
, ARRAY_SIZE(netdevAttrs
))) {
1639 return STATUS_INVALID_PARAMETER
;
1642 vportGet
.portNo
= 0;
1643 RtlCopyMemory(&vportGet
.name
, NlAttrGet(netdevAttrs
[OVS_VPORT_ATTR_NAME
]),
1644 NlAttrGetSize(netdevAttrs
[OVS_VPORT_ATTR_NAME
]));
1646 status
= OvsGetExtInfoIoctl(&vportGet
, &info
);
1647 if (status
== STATUS_DEVICE_DOES_NOT_EXIST
) {
1648 nlError
= NL_ERROR_NODEV
;
1652 status
= CreateNetlinkMesgForNetdev(&info
, msgIn
,
1653 usrParamsCtx
->outputBuffer
, usrParamsCtx
->outputLength
,
1654 gOvsSwitchContext
->dpNo
);
1655 if (status
== STATUS_SUCCESS
) {
1656 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
1660 if (nlError
!= NL_ERROR_SUCCESS
) {
1661 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
1662 usrParamsCtx
->outputBuffer
;
1664 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
1665 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
1668 return STATUS_SUCCESS
;
1673 * --------------------------------------------------------------------------
1674 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1675 * OVS_MESSAGE contains the output of a netdev command.
1676 * --------------------------------------------------------------------------
1679 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info
,
1688 UINT32 netdevFlags
= 0;
1690 NlBufInit(&nlBuffer
, outBuffer
, outBufLen
);
1692 ok
= NlFillOvsMsg(&nlBuffer
, msgIn
->nlMsg
.nlmsgType
, NLM_F_MULTI
,
1693 msgIn
->nlMsg
.nlmsgSeq
, msgIn
->nlMsg
.nlmsgPid
,
1694 msgIn
->genlMsg
.cmd
, msgIn
->genlMsg
.version
,
1697 return STATUS_INVALID_BUFFER_SIZE
;
1700 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_PORT_NO
,
1703 return STATUS_INVALID_BUFFER_SIZE
;
1706 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_TYPE
, info
->type
);
1708 return STATUS_INVALID_BUFFER_SIZE
;
1711 ok
= NlMsgPutTailString(&nlBuffer
, OVS_WIN_NETDEV_ATTR_NAME
,
1714 return STATUS_INVALID_BUFFER_SIZE
;
1717 ok
= NlMsgPutTailUnspec(&nlBuffer
, OVS_WIN_NETDEV_ATTR_MAC_ADDR
,
1718 (PCHAR
)info
->macAddress
, sizeof (info
->macAddress
));
1720 return STATUS_INVALID_BUFFER_SIZE
;
1723 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_MTU
, info
->mtu
);
1725 return STATUS_INVALID_BUFFER_SIZE
;
1728 if (info
->status
!= OVS_EVENT_CONNECT
) {
1729 netdevFlags
= OVS_WIN_NETDEV_IFF_UP
;
1731 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_IF_FLAGS
,
1734 return STATUS_INVALID_BUFFER_SIZE
;
1738 * XXX: add netdev_stats when we have the definition available in the
1742 nlMsg
= (PNL_MSG_HDR
)NlBufAt(&nlBuffer
, 0, 0);
1743 nlMsg
->nlmsgLen
= NlBufSize(&nlBuffer
);
1745 return STATUS_SUCCESS
;
1748 static __inline VOID
1749 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext
, ULONG sleepMicroSec
)
1751 while ((!switchContext
->isActivated
) &&
1752 (!switchContext
->isActivateFailed
)) {
1753 /* Wait for the switch to be active and
1754 * the list of ports in OVS to be initialized. */
1755 NdisMSleep(sleepMicroSec
);
1760 OvsCreateMsgFromVport(POVS_VPORT_ENTRY vport
,
1767 OVS_VPORT_FULL_STATS vportStats
;
1771 NlBufInit(&nlBuffer
, outBuffer
, outBufLen
);
1773 ok
= NlFillOvsMsg(&nlBuffer
, msgIn
->nlMsg
.nlmsgType
, NLM_F_MULTI
,
1774 msgIn
->nlMsg
.nlmsgSeq
, msgIn
->nlMsg
.nlmsgPid
,
1775 msgIn
->genlMsg
.cmd
, msgIn
->genlMsg
.version
,
1778 return STATUS_INVALID_BUFFER_SIZE
;
1781 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_VPORT_ATTR_PORT_NO
, vport
->portNo
);
1783 return STATUS_INVALID_BUFFER_SIZE
;
1786 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_VPORT_ATTR_TYPE
, vport
->ovsType
);
1788 return STATUS_INVALID_BUFFER_SIZE
;
1791 ok
= NlMsgPutTailString(&nlBuffer
, OVS_VPORT_ATTR_NAME
, vport
->ovsName
);
1793 return STATUS_INVALID_BUFFER_SIZE
;
1797 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1798 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1799 * it means we have an array of pids, instead of a single pid.
1800 * ATM we assume we have one pid only.
1803 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_VPORT_ATTR_UPCALL_PID
,
1806 return STATUS_INVALID_BUFFER_SIZE
;
1810 vportStats
.rxPackets
= vport
->stats
.rxPackets
;
1811 vportStats
.rxBytes
= vport
->stats
.rxBytes
;
1812 vportStats
.txPackets
= vport
->stats
.txPackets
;
1813 vportStats
.txBytes
= vport
->stats
.txBytes
;
1814 vportStats
.rxErrors
= vport
->errStats
.rxErrors
;
1815 vportStats
.txErrors
= vport
->errStats
.txErrors
;
1816 vportStats
.rxDropped
= vport
->errStats
.rxDropped
;
1817 vportStats
.txDropped
= vport
->errStats
.txDropped
;
1819 ok
= NlMsgPutTailUnspec(&nlBuffer
, OVS_VPORT_ATTR_STATS
,
1821 sizeof(OVS_VPORT_FULL_STATS
));
1823 return STATUS_INVALID_BUFFER_SIZE
;
1827 * XXX: when vxlan udp dest port becomes configurable, we will also need
1828 * to add vport options
1831 nlMsg
= (PNL_MSG_HDR
)NlBufAt(&nlBuffer
, 0, 0);
1832 nlMsg
->nlmsgLen
= NlBufSize(&nlBuffer
);
1834 return STATUS_SUCCESS
;
1838 OvsGetVportDumpNext(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
1842 POVS_OPEN_INSTANCE instance
=
1843 (POVS_OPEN_INSTANCE
)usrParamsCtx
->ovsInstance
;
1844 LOCK_STATE_EX lockState
;
1845 UINT32 i
= OVS_MAX_VPORT_ARRAY_SIZE
;
1848 * XXX: this function shares some code with other dump command(s).
1849 * In the future, we will need to refactor the dump functions
1852 ASSERT(usrParamsCtx
->devOp
== OVS_READ_DEV_OP
);
1854 if (instance
->dumpState
.ovsMsg
== NULL
) {
1856 return STATUS_INVALID_DEVICE_STATE
;
1859 /* Output buffer has been validated while validating read dev op. */
1860 ASSERT(usrParamsCtx
->outputBuffer
!= NULL
);
1862 msgIn
= instance
->dumpState
.ovsMsg
;
1865 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1866 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1867 * it means we have an array of pids, instead of a single pid.
1868 * ATM we assume we have one pid only.
1870 NdisAcquireRWLockRead(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
1872 if (gOvsSwitchContext
->numHvVports
> 0 ||
1873 gOvsSwitchContext
->numNonHvVports
> 0) {
1874 /* inBucket: the bucket, used for lookup */
1875 UINT32 inBucket
= instance
->dumpState
.index
[0];
1876 /* inIndex: index within the given bucket, used for lookup */
1877 UINT32 inIndex
= instance
->dumpState
.index
[1];
1878 /* the bucket to be used for the next dump operation */
1879 UINT32 outBucket
= 0;
1880 /* the index within the outBucket to be used for the next dump */
1881 UINT32 outIndex
= 0;
1883 for (i
= inBucket
; i
< OVS_MAX_VPORT_ARRAY_SIZE
; i
++) {
1884 PLIST_ENTRY head
, link
;
1885 head
= &(gOvsSwitchContext
->portNoHashArray
[i
]);
1886 POVS_VPORT_ENTRY vport
= NULL
;
1889 LIST_FORALL(head
, link
) {
1892 * if one or more dumps were previously done on this same bucket,
1893 * inIndex will be > 0, so we'll need to reply with the
1894 * inIndex + 1 vport from the bucket.
1896 if (outIndex
>= inIndex
) {
1897 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portNoLink
);
1899 ASSERT(vport
->portNo
!= OVS_DPPORT_NUMBER_INVALID
);
1900 OvsCreateMsgFromVport(vport
, msgIn
,
1901 usrParamsCtx
->outputBuffer
,
1902 usrParamsCtx
->outputLength
,
1903 gOvsSwitchContext
->dpNo
);
1916 * if no vport was found above, check the next bucket, beginning
1917 * with the first (i.e. index 0) elem from within that bucket
1924 /* XXX: what about NLMSG_DONE (as msg type)? */
1925 instance
->dumpState
.index
[0] = outBucket
;
1926 instance
->dumpState
.index
[1] = outIndex
;
1929 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1931 /* if i < OVS_MAX_VPORT_ARRAY_SIZE => vport was found */
1932 if (i
< OVS_MAX_VPORT_ARRAY_SIZE
) {
1933 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
1934 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
1937 * if i >= OVS_MAX_VPORT_ARRAY_SIZE => vport was not found =>
1941 /* Free up the dump state, since there's no more data to continue. */
1942 FreeUserDumpState(instance
);
1945 return STATUS_SUCCESS
;
1949 OvsGetVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
1952 NTSTATUS status
= STATUS_SUCCESS
;
1953 LOCK_STATE_EX lockState
;
1955 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
1956 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
1957 POVS_VPORT_ENTRY vport
= NULL
;
1958 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
1959 PCHAR portName
= NULL
;
1960 UINT32 portNameLen
= 0;
1961 UINT32 portNumber
= OVS_DPPORT_NUMBER_INVALID
;
1963 static const NL_POLICY ovsVportPolicy
[] = {
1964 [OVS_VPORT_ATTR_PORT_NO
] = { .type
= NL_A_U32
, .optional
= TRUE
},
1965 [OVS_VPORT_ATTR_NAME
] = { .type
= NL_A_STRING
,
1970 PNL_ATTR vportAttrs
[ARRAY_SIZE(ovsVportPolicy
)];
1972 /* input buffer has been validated while validating write dev op. */
1973 ASSERT(usrParamsCtx
->inputBuffer
!= NULL
);
1975 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
1976 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
1977 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
1978 ovsVportPolicy
, ARRAY_SIZE(ovsVportPolicy
),
1979 vportAttrs
, ARRAY_SIZE(vportAttrs
))) {
1980 return STATUS_INVALID_PARAMETER
;
1983 /* Output buffer has been validated while validating transact dev op. */
1984 ASSERT(msgOut
!= NULL
&& usrParamsCtx
->outputLength
>= sizeof *msgOut
);
1986 NdisAcquireRWLockRead(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
1987 if (vportAttrs
[OVS_VPORT_ATTR_NAME
] != NULL
) {
1988 portName
= NlAttrGet(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
1989 portNameLen
= NlAttrGetSize(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
1991 /* the port name is expected to be null-terminated */
1992 ASSERT(portName
[portNameLen
- 1] == '\0');
1994 vport
= OvsFindVportByOvsName(gOvsSwitchContext
, portName
);
1995 } else if (vportAttrs
[OVS_VPORT_ATTR_PORT_NO
] != NULL
) {
1996 portNumber
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_PORT_NO
]);
1998 vport
= OvsFindVportByPortNo(gOvsSwitchContext
, portNumber
);
2000 nlError
= NL_ERROR_INVAL
;
2001 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
2006 nlError
= NL_ERROR_NODEV
;
2007 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
2011 status
= OvsCreateMsgFromVport(vport
, msgIn
, usrParamsCtx
->outputBuffer
,
2012 usrParamsCtx
->outputLength
,
2013 gOvsSwitchContext
->dpNo
);
2014 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
2016 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2019 if (nlError
!= NL_ERROR_SUCCESS
) {
2020 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
2021 usrParamsCtx
->outputBuffer
;
2023 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2024 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
2027 return STATUS_SUCCESS
;
2031 * --------------------------------------------------------------------------
2032 * Command Handler for 'OVS_VPORT_CMD_GET'.
2034 * The function handles the initial call to setup the dump state, as well as
2035 * subsequent calls to continue dumping data.
2036 * --------------------------------------------------------------------------
2039 OvsGetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
2044 switch (usrParamsCtx
->devOp
) {
2045 case OVS_WRITE_DEV_OP
:
2046 return OvsSetupDumpStart(usrParamsCtx
);
2048 case OVS_READ_DEV_OP
:
2049 return OvsGetVportDumpNext(usrParamsCtx
, replyLen
);
2051 case OVS_TRANSACTION_DEV_OP
:
2052 return OvsGetVport(usrParamsCtx
, replyLen
);
2055 return STATUS_INVALID_DEVICE_REQUEST
;
2061 OvsComputeVportNo(POVS_SWITCH_CONTEXT switchContext
)
2063 /* we are not allowed to create the port OVS_DPPORT_NUMBER_LOCAL */
2064 for (ULONG i
= OVS_DPPORT_NUMBER_LOCAL
+ 1; i
< MAXUINT16
; ++i
) {
2065 POVS_VPORT_ENTRY vport
;
2067 vport
= OvsFindVportByPortNo(switchContext
, i
);
2073 return OVS_DPPORT_NUMBER_INVALID
;
2077 * --------------------------------------------------------------------------
2078 * Command Handler for 'OVS_VPORT_CMD_NEW'.
2079 * --------------------------------------------------------------------------
2082 OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
2085 NDIS_STATUS status
= STATUS_SUCCESS
;
2086 LOCK_STATE_EX lockState
;
2088 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
2089 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
2090 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
2091 POVS_VPORT_ENTRY vport
= NULL
;
2095 BOOLEAN isBridgeInternal
= FALSE
;
2096 BOOLEAN vportAllocated
= FALSE
, vportInitialized
= FALSE
;
2097 BOOLEAN addInternalPortAsNetdev
= FALSE
;
2099 static const NL_POLICY ovsVportPolicy
[] = {
2100 [OVS_VPORT_ATTR_PORT_NO
] = { .type
= NL_A_U32
, .optional
= TRUE
},
2101 [OVS_VPORT_ATTR_TYPE
] = { .type
= NL_A_U32
, .optional
= FALSE
},
2102 [OVS_VPORT_ATTR_NAME
] = { .type
= NL_A_STRING
, .maxLen
= IFNAMSIZ
,
2104 [OVS_VPORT_ATTR_UPCALL_PID
] = { .type
= NL_A_UNSPEC
,
2105 .optional
= FALSE
},
2106 [OVS_VPORT_ATTR_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= TRUE
},
2109 PNL_ATTR vportAttrs
[ARRAY_SIZE(ovsVportPolicy
)];
2111 /* input buffer has been validated while validating write dev op. */
2112 ASSERT(usrParamsCtx
->inputBuffer
!= NULL
);
2114 /* Output buffer has been validated while validating transact dev op. */
2115 ASSERT(msgOut
!= NULL
&& usrParamsCtx
->outputLength
>= sizeof *msgOut
);
2117 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
2118 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
2119 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
2120 ovsVportPolicy
, ARRAY_SIZE(ovsVportPolicy
),
2121 vportAttrs
, ARRAY_SIZE(vportAttrs
))) {
2122 return STATUS_INVALID_PARAMETER
;
2125 portName
= NlAttrGet(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2126 portNameLen
= NlAttrGetSize(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2127 portType
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_TYPE
]);
2129 /* we are expecting null terminated strings to be passed */
2130 ASSERT(portName
[portNameLen
- 1] == '\0');
2132 NdisAcquireRWLockWrite(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
2134 vport
= OvsFindVportByOvsName(gOvsSwitchContext
, portName
);
2136 nlError
= NL_ERROR_EXIST
;
2140 if (portName
&& portType
== OVS_VPORT_TYPE_NETDEV
&&
2141 !strcmp(OVS_DPPORT_INTERNAL_NAME_A
, portName
)) {
2142 addInternalPortAsNetdev
= TRUE
;
2145 if (portName
&& portType
== OVS_VPORT_TYPE_INTERNAL
&&
2146 strcmp(OVS_DPPORT_INTERNAL_NAME_A
, portName
)) {
2147 isBridgeInternal
= TRUE
;
2150 if (portType
== OVS_VPORT_TYPE_INTERNAL
&& !isBridgeInternal
) {
2151 vport
= gOvsSwitchContext
->internalVport
;
2152 } else if (portType
== OVS_VPORT_TYPE_NETDEV
) {
2153 /* External ports can also be looked up like VIF ports. */
2154 vport
= OvsFindVportByHvNameA(gOvsSwitchContext
, portName
);
2156 ASSERT(OvsIsTunnelVportType(portType
) ||
2157 (portType
== OVS_VPORT_TYPE_INTERNAL
&& isBridgeInternal
));
2159 vport
= (POVS_VPORT_ENTRY
)OvsAllocateVport();
2160 if (vport
== NULL
) {
2161 nlError
= NL_ERROR_NOMEM
;
2164 vportAllocated
= TRUE
;
2166 if (OvsIsTunnelVportType(portType
)) {
2167 UINT16 transportPortDest
= 0;
2170 case OVS_VPORT_TYPE_VXLAN
:
2171 transportPortDest
= VXLAN_UDP_PORT
;
2173 case OVS_VPORT_TYPE_STT
:
2174 transportPortDest
= STT_TCP_PORT
;
2180 if (vportAttrs
[OVS_VPORT_ATTR_OPTIONS
]) {
2181 PNL_ATTR attr
= NlAttrFindNested(vportAttrs
[OVS_VPORT_ATTR_OPTIONS
],
2182 OVS_TUNNEL_ATTR_DST_PORT
);
2184 transportPortDest
= NlAttrGetU16(attr
);
2188 status
= OvsInitTunnelVport(usrParamsCtx
,
2193 nlError
= NlMapStatusToNlErr(status
);
2195 OvsInitBridgeInternalVport(vport
);
2198 vportInitialized
= TRUE
;
2200 if (nlError
== NL_ERROR_SUCCESS
) {
2201 vport
->ovsState
= OVS_STATE_CONNECTED
;
2202 vport
->nicState
= NdisSwitchNicStateConnected
;
2205 * Allow the vport to be deleted, because there is no
2206 * corresponding hyper-v switch part.
2208 vport
->isAbsentOnHv
= TRUE
;
2215 nlError
= NL_ERROR_INVAL
;
2218 if (vport
->portNo
!= OVS_DPPORT_NUMBER_INVALID
) {
2219 nlError
= NL_ERROR_EXIST
;
2223 /* Initialize the vport with OVS specific properties. */
2224 if (addInternalPortAsNetdev
!= TRUE
) {
2225 vport
->ovsType
= portType
;
2227 if (vportAttrs
[OVS_VPORT_ATTR_PORT_NO
] != NULL
) {
2229 * XXX: when we implement the limit for ovs port number to be
2230 * MAXUINT16, we'll need to check the port number received from the
2233 vport
->portNo
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_PORT_NO
]);
2235 vport
->portNo
= OvsComputeVportNo(gOvsSwitchContext
);
2236 if (vport
->portNo
== OVS_DPPORT_NUMBER_INVALID
) {
2237 nlError
= NL_ERROR_NOMEM
;
2242 /* The ovs port name must be uninitialized. */
2243 ASSERT(vport
->ovsName
[0] == '\0');
2244 ASSERT(portNameLen
<= OVS_MAX_PORT_NAME_LENGTH
);
2246 RtlCopyMemory(vport
->ovsName
, portName
, portNameLen
);
2247 /* if we don't have options, then vport->portOptions will be NULL */
2248 vport
->portOptions
= vportAttrs
[OVS_VPORT_ATTR_OPTIONS
];
2251 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2252 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2253 * it means we have an array of pids, instead of a single pid.
2254 * ATM we assume we have one pid only.
2256 vport
->upcallPid
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_UPCALL_PID
]);
2258 status
= InitOvsVportCommon(gOvsSwitchContext
, vport
);
2259 ASSERT(status
== STATUS_SUCCESS
);
2261 status
= OvsCreateMsgFromVport(vport
, msgIn
, usrParamsCtx
->outputBuffer
,
2262 usrParamsCtx
->outputLength
,
2263 gOvsSwitchContext
->dpNo
);
2265 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2268 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
2270 if ((nlError
!= NL_ERROR_SUCCESS
) && (nlError
!= NL_ERROR_PENDING
)) {
2271 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
2272 usrParamsCtx
->outputBuffer
;
2274 if (vport
&& vportAllocated
== TRUE
) {
2275 if (vportInitialized
== TRUE
) {
2276 if (OvsIsTunnelVportType(portType
)) {
2277 switch (vport
->ovsType
) {
2278 case OVS_VPORT_TYPE_VXLAN
:
2279 OvsCleanupVxlanTunnel(NULL
, vport
, NULL
, NULL
);
2281 case OVS_VPORT_TYPE_STT
:
2282 OvsCleanupSttTunnel(vport
);
2285 ASSERT(!"Invalid tunnel port type");
2289 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
2292 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2293 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
2296 return (status
== STATUS_PENDING
) ? STATUS_PENDING
: STATUS_SUCCESS
;
2301 * --------------------------------------------------------------------------
2302 * Command Handler for 'OVS_VPORT_CMD_SET'.
2303 * --------------------------------------------------------------------------
2306 OvsSetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
2309 NDIS_STATUS status
= STATUS_SUCCESS
;
2310 LOCK_STATE_EX lockState
;
2312 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
2313 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
2314 POVS_VPORT_ENTRY vport
= NULL
;
2315 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
2317 static const NL_POLICY ovsVportPolicy
[] = {
2318 [OVS_VPORT_ATTR_PORT_NO
] = { .type
= NL_A_U32
, .optional
= TRUE
},
2319 [OVS_VPORT_ATTR_TYPE
] = { .type
= NL_A_U32
, .optional
= TRUE
},
2320 [OVS_VPORT_ATTR_NAME
] = { .type
= NL_A_STRING
, .maxLen
= IFNAMSIZ
,
2322 [OVS_VPORT_ATTR_UPCALL_PID
] = { .type
= NL_A_UNSPEC
,
2324 [OVS_VPORT_ATTR_STATS
] = { .type
= NL_A_UNSPEC
,
2325 .minLen
= sizeof(OVS_VPORT_FULL_STATS
),
2326 .maxLen
= sizeof(OVS_VPORT_FULL_STATS
),
2328 [OVS_VPORT_ATTR_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= TRUE
},
2330 PNL_ATTR vportAttrs
[ARRAY_SIZE(ovsVportPolicy
)];
2332 ASSERT(usrParamsCtx
->inputBuffer
!= NULL
);
2334 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
2335 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
2336 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
2337 ovsVportPolicy
, ARRAY_SIZE(ovsVportPolicy
),
2338 vportAttrs
, ARRAY_SIZE(vportAttrs
))) {
2339 return STATUS_INVALID_PARAMETER
;
2342 /* Output buffer has been validated while validating transact dev op. */
2343 ASSERT(msgOut
!= NULL
&& usrParamsCtx
->outputLength
>= sizeof *msgOut
);
2345 NdisAcquireRWLockWrite(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
2346 if (vportAttrs
[OVS_VPORT_ATTR_NAME
] != NULL
) {
2347 PSTR portName
= NlAttrGet(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2349 UINT32 portNameLen
= NlAttrGetSize(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2351 /* the port name is expected to be null-terminated */
2352 ASSERT(portName
[portNameLen
- 1] == '\0');
2354 vport
= OvsFindVportByOvsName(gOvsSwitchContext
, portName
);
2355 } else if (vportAttrs
[OVS_VPORT_ATTR_PORT_NO
] != NULL
) {
2356 vport
= OvsFindVportByPortNo(gOvsSwitchContext
,
2357 NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_PORT_NO
]));
2361 nlError
= NL_ERROR_NODEV
;
2366 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2367 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2368 * it means we have an array of pids, instead of a single pid.
2369 * Currently, we support only one pid.
2371 if (vportAttrs
[OVS_VPORT_ATTR_UPCALL_PID
]) {
2372 vport
->upcallPid
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_UPCALL_PID
]);
2375 if (vportAttrs
[OVS_VPORT_ATTR_TYPE
]) {
2376 OVS_VPORT_TYPE type
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_TYPE
]);
2377 if (type
!= vport
->ovsType
) {
2378 nlError
= NL_ERROR_INVAL
;
2383 if (vportAttrs
[OVS_VPORT_ATTR_OPTIONS
]) {
2384 OVS_LOG_ERROR("Vport options not supported");
2385 nlError
= NL_ERROR_NOTSUPP
;
2389 status
= OvsCreateMsgFromVport(vport
, msgIn
, usrParamsCtx
->outputBuffer
,
2390 usrParamsCtx
->outputLength
,
2391 gOvsSwitchContext
->dpNo
);
2393 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2396 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
2398 if (nlError
!= NL_ERROR_SUCCESS
) {
2399 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
2400 usrParamsCtx
->outputBuffer
;
2402 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2403 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
2406 return STATUS_SUCCESS
;
2410 * --------------------------------------------------------------------------
2411 * Command Handler for 'OVS_VPORT_CMD_DEL'.
2412 * --------------------------------------------------------------------------
2415 OvsDeleteVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
2418 NDIS_STATUS status
= STATUS_SUCCESS
;
2419 LOCK_STATE_EX lockState
;
2421 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
2422 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
2423 POVS_VPORT_ENTRY vport
= NULL
;
2424 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
2425 PSTR portName
= NULL
;
2426 UINT32 portNameLen
= 0;
2428 static const NL_POLICY ovsVportPolicy
[] = {
2429 [OVS_VPORT_ATTR_PORT_NO
] = { .type
= NL_A_U32
, .optional
= TRUE
},
2430 [OVS_VPORT_ATTR_NAME
] = { .type
= NL_A_STRING
, .maxLen
= IFNAMSIZ
,
2433 PNL_ATTR vportAttrs
[ARRAY_SIZE(ovsVportPolicy
)];
2435 ASSERT(usrParamsCtx
->inputBuffer
!= NULL
);
2437 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
2438 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
2439 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
2440 ovsVportPolicy
, ARRAY_SIZE(ovsVportPolicy
),
2441 vportAttrs
, ARRAY_SIZE(vportAttrs
))) {
2442 return STATUS_INVALID_PARAMETER
;
2445 /* Output buffer has been validated while validating transact dev op. */
2446 ASSERT(msgOut
!= NULL
&& usrParamsCtx
->outputLength
>= sizeof *msgOut
);
2448 NdisAcquireRWLockWrite(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
2449 if (vportAttrs
[OVS_VPORT_ATTR_NAME
] != NULL
) {
2450 portName
= NlAttrGet(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2451 portNameLen
= NlAttrGetSize(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2453 /* the port name is expected to be null-terminated */
2454 ASSERT(portName
[portNameLen
- 1] == '\0');
2456 vport
= OvsFindVportByOvsName(gOvsSwitchContext
, portName
);
2458 else if (vportAttrs
[OVS_VPORT_ATTR_PORT_NO
] != NULL
) {
2459 vport
= OvsFindVportByPortNo(gOvsSwitchContext
,
2460 NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_PORT_NO
]));
2464 nlError
= NL_ERROR_NODEV
;
2468 status
= OvsCreateMsgFromVport(vport
, msgIn
, usrParamsCtx
->outputBuffer
,
2469 usrParamsCtx
->outputLength
,
2470 gOvsSwitchContext
->dpNo
);
2472 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2475 * Mark the port as deleted from OVS userspace. If the port does not exist
2476 * on the Hyper-V switch, it gets deallocated. Otherwise, it stays.
2478 status
= OvsRemoveAndDeleteVport(usrParamsCtx
,
2484 nlError
= NlMapStatusToNlErr(status
);
2488 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
2490 if ((nlError
!= NL_ERROR_SUCCESS
) && (nlError
!= NL_ERROR_PENDING
)) {
2491 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
2492 usrParamsCtx
->outputBuffer
;
2494 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2495 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
2498 return (status
== STATUS_PENDING
) ? STATUS_PENDING
: STATUS_SUCCESS
;
2502 OvsTunnelVportPendingRemove(PVOID context
,
2506 POVS_TUNFLT_INIT_CONTEXT tunnelContext
=
2507 (POVS_TUNFLT_INIT_CONTEXT
) context
;
2508 POVS_SWITCH_CONTEXT switchContext
= tunnelContext
->switchContext
;
2509 POVS_VPORT_ENTRY vport
= tunnelContext
->vport
;
2510 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)tunnelContext
->inputBuffer
;
2511 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)tunnelContext
->outputBuffer
;
2512 NL_ERROR nlError
= NlMapStatusToNlErr(status
);
2513 LOCK_STATE_EX lockState
;
2515 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
2517 if (msgIn
&& msgOut
) {
2518 /* Check the received status to reply to the caller. */
2519 if (STATUS_SUCCESS
== status
) {
2520 OvsCreateMsgFromVport(vport
,
2523 tunnelContext
->outputLength
,
2524 switchContext
->dpNo
);
2526 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2528 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)msgOut
;
2530 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2531 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
2535 ASSERT(vport
->isAbsentOnHv
== TRUE
);
2536 ASSERT(vport
->portNo
!= OVS_DPPORT_NUMBER_INVALID
);
2538 /* Remove the port from the relevant lists. */
2539 switchContext
->numNonHvVports
--;
2540 RemoveEntryList(&vport
->ovsNameLink
);
2541 RemoveEntryList(&vport
->portNoLink
);
2542 RemoveEntryList(&vport
->tunnelVportLink
);
2545 OvsFreeMemoryWithTag(vport
->priv
, OVS_VXLAN_POOL_TAG
);
2549 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
2551 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
2555 OvsTunnelVportPendingInit(PVOID context
,
2559 POVS_TUNFLT_INIT_CONTEXT tunnelContext
=
2560 (POVS_TUNFLT_INIT_CONTEXT
) context
;
2561 POVS_VPORT_ENTRY vport
= tunnelContext
->vport
;
2562 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)tunnelContext
->inputBuffer
;
2563 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)tunnelContext
->outputBuffer
;
2565 ULONG portNameLen
= 0;
2566 UINT32 portType
= 0;
2567 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
2568 BOOLEAN error
= TRUE
;
2571 if (!NT_SUCCESS(status
)) {
2572 nlError
= NlMapStatusToNlErr(status
);
2576 static const NL_POLICY ovsVportPolicy
[] = {
2577 [OVS_VPORT_ATTR_PORT_NO
] = { .type
= NL_A_U32
, .optional
= TRUE
},
2578 [OVS_VPORT_ATTR_TYPE
] = { .type
= NL_A_U32
, .optional
= FALSE
},
2579 [OVS_VPORT_ATTR_NAME
] = { .type
= NL_A_STRING
, .maxLen
= IFNAMSIZ
,
2580 .optional
= FALSE
},
2581 [OVS_VPORT_ATTR_UPCALL_PID
] = { .type
= NL_A_UNSPEC
,
2582 .optional
= FALSE
},
2583 [OVS_VPORT_ATTR_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= TRUE
},
2586 PNL_ATTR vportAttrs
[ARRAY_SIZE(ovsVportPolicy
)];
2588 /* input buffer has been validated while validating write dev op. */
2589 ASSERT(msgIn
!= NULL
);
2591 /* Output buffer has been validated while validating transact dev op. */
2592 ASSERT(msgOut
!= NULL
&& tunnelContext
->outputLength
>= sizeof *msgOut
);
2594 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
2595 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
2596 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
2597 ovsVportPolicy
, ARRAY_SIZE(ovsVportPolicy
),
2598 vportAttrs
, ARRAY_SIZE(vportAttrs
))) {
2599 nlError
= NL_ERROR_INVAL
;
2603 portName
= NlAttrGet(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2604 portNameLen
= NlAttrGetSize(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2605 portType
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_TYPE
]);
2607 if (vport
->portNo
!= OVS_DPPORT_NUMBER_INVALID
) {
2608 nlError
= NL_ERROR_EXIST
;
2612 vport
->ovsState
= OVS_STATE_CONNECTED
;
2613 vport
->nicState
= NdisSwitchNicStateConnected
;
2616 * Allow the vport to be deleted, because there is no
2617 * corresponding hyper-v switch part.
2619 vport
->isAbsentOnHv
= TRUE
;
2621 if (vportAttrs
[OVS_VPORT_ATTR_PORT_NO
] != NULL
) {
2623 * XXX: when we implement the limit for OVS port number to be
2624 * MAXUINT16, we'll need to check the port number received from the
2628 NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_PORT_NO
]);
2631 OvsComputeVportNo(gOvsSwitchContext
);
2632 if (vport
->portNo
== OVS_DPPORT_NUMBER_INVALID
) {
2633 nlError
= NL_ERROR_NOMEM
;
2638 /* The ovs port name must be uninitialized. */
2639 ASSERT(vport
->ovsName
[0] == '\0');
2640 ASSERT(portNameLen
<= OVS_MAX_PORT_NAME_LENGTH
);
2642 RtlCopyMemory(vport
->ovsName
, portName
, portNameLen
);
2643 /* if we don't have options, then vport->portOptions will be NULL */
2644 vport
->portOptions
= vportAttrs
[OVS_VPORT_ATTR_OPTIONS
];
2647 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2648 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2649 * it means we have an array of pids, instead of a single pid.
2650 * ATM we assume we have one pid only.
2653 NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_UPCALL_PID
]);
2655 status
= InitOvsVportCommon(gOvsSwitchContext
, vport
);
2656 ASSERT(status
== STATUS_SUCCESS
);
2658 OvsCreateMsgFromVport(vport
,
2661 tunnelContext
->outputLength
,
2662 gOvsSwitchContext
->dpNo
);
2664 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2670 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
) msgOut
;
2672 OvsCleanupVxlanTunnel(NULL
, vport
, NULL
, NULL
);
2673 OvsFreeMemory(vport
);
2675 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2676 *replyLen
= msgError
->nlMsg
.nlmsgLen
;