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 /* Context structure used to pass back and forth information to the tunnel
52 typedef struct _OVS_TUNFLT_INIT_CONTEXT
{
53 POVS_SWITCH_CONTEXT switchContext
;
57 POVS_VPORT_ENTRY vport
;
61 } OVS_TUNFLT_INIT_CONTEXT
, *POVS_TUNFLT_INIT_CONTEXT
;
64 extern POVS_SWITCH_CONTEXT gOvsSwitchContext
;
66 static VOID
OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport
,
67 PNDIS_SWITCH_PORT_PARAMETERS portParam
);
68 static VOID
OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext
,
69 POVS_VPORT_ENTRY vport
, PNDIS_SWITCH_NIC_PARAMETERS nicParam
);
70 static VOID
OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVPort
,
71 POVS_VPORT_ENTRY virtExtVport
, UINT32 nicIndex
);
72 static __inline VOID
OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext
,
74 static NTSTATUS
OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet
,
75 POVS_VPORT_EXT_INFO extInfo
);
76 static NTSTATUS
CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info
,
81 static POVS_VPORT_ENTRY
OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext
,
82 PWSTR wsName
, SIZE_T wstrSize
);
83 static NDIS_STATUS
InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext
,
84 POVS_VPORT_ENTRY vport
,
86 static VOID
OvsCleanupVportCommon(POVS_SWITCH_CONTEXT switchContext
,
87 POVS_VPORT_ENTRY vport
,
91 static VOID
OvsTunnelVportPendingInit(PVOID context
,
94 static VOID
OvsTunnelVportPendingUninit(PVOID context
,
100 * Functions implemented in relaton to NDIS port manipulation.
103 HvCreatePort(POVS_SWITCH_CONTEXT switchContext
,
104 PNDIS_SWITCH_PORT_PARAMETERS portParam
)
106 POVS_VPORT_ENTRY vport
;
107 LOCK_STATE_EX lockState
;
108 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
109 BOOLEAN newPort
= FALSE
;
111 VPORT_PORT_ENTER(portParam
);
113 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
114 /* Lookup by port ID. */
115 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
116 portParam
->PortId
, 0);
118 OVS_LOG_ERROR("Port add failed due to duplicate port name, "
119 "port Id: %u", portParam
->PortId
);
120 status
= STATUS_DATA_NOT_ACCEPTED
;
121 goto create_port_done
;
125 * Lookup by port name to see if this port with this name had been added
126 * (and deleted) previously.
128 vport
= OvsFindVportByHvNameW(gOvsSwitchContext
,
129 portParam
->PortFriendlyName
.String
,
130 portParam
->PortFriendlyName
.Length
);
131 if (vport
&& vport
->isPresentOnHv
== FALSE
) {
132 OVS_LOG_ERROR("Port add failed since a port already exists on "
133 "the specified port Id: %u, ovsName: %s",
134 portParam
->PortId
, vport
->ovsName
);
135 status
= STATUS_DATA_NOT_ACCEPTED
;
136 goto create_port_done
;
140 ASSERT(vport
->isPresentOnHv
);
141 ASSERT(vport
->portNo
!= OVS_DPPORT_NUMBER_INVALID
);
144 * It should be possible to simply just mark this port as "not deleted"
145 * given that the port Id and the name are the same and also provided
146 * that the other properties that we cache have not changed.
148 if (vport
->portType
!= portParam
->PortType
) {
149 OVS_LOG_INFO("Port add failed due to PortType change, port Id: %u"
150 " old: %u, new: %u", portParam
->PortId
,
151 vport
->portType
, portParam
->PortType
);
152 status
= STATUS_DATA_NOT_ACCEPTED
;
153 goto create_port_done
;
155 vport
->isPresentOnHv
= FALSE
;
157 vport
= (POVS_VPORT_ENTRY
)OvsAllocateVport();
159 status
= NDIS_STATUS_RESOURCES
;
160 goto create_port_done
;
164 OvsInitVportWithPortParam(vport
, portParam
);
165 InitHvVportCommon(switchContext
, vport
, newPort
);
168 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
169 VPORT_PORT_EXIT(portParam
);
175 * Function updating the port properties
178 HvUpdatePort(POVS_SWITCH_CONTEXT switchContext
,
179 PNDIS_SWITCH_PORT_PARAMETERS portParam
)
181 POVS_VPORT_ENTRY vport
;
182 LOCK_STATE_EX lockState
;
183 OVS_VPORT_STATE ovsState
;
184 NDIS_SWITCH_NIC_STATE nicState
;
186 VPORT_PORT_ENTER(portParam
);
188 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
189 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
190 portParam
->PortId
, 0);
192 * Update properties only for NETDEV ports for supprting PS script
193 * We don't allow changing the names of the internal or external ports
195 if (vport
== NULL
|| (( vport
->portType
!= NdisSwitchPortTypeSynthetic
) &&
196 ( vport
->portType
!= NdisSwitchPortTypeEmulated
))) {
197 goto update_port_done
;
200 /* Store the nic and the OVS states as Nic Create won't be called */
201 ovsState
= vport
->ovsState
;
202 nicState
= vport
->nicState
;
205 * Currently only the port friendly name is being updated
206 * Make sure that no other properties are changed
208 ASSERT(portParam
->PortId
== vport
->portId
);
209 ASSERT(portParam
->PortState
== vport
->portState
);
210 ASSERT(portParam
->PortType
== vport
->portType
);
213 * Call the set parameters function the handle all properties
214 * change in a single place in case future version supports change of
217 OvsInitVportWithPortParam(vport
, portParam
);
218 /* Retore the nic and OVS states */
219 vport
->nicState
= nicState
;
220 vport
->ovsState
= ovsState
;
223 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
224 VPORT_PORT_EXIT(portParam
);
226 /* Must always return success */
227 return NDIS_STATUS_SUCCESS
;
231 HvTeardownPort(POVS_SWITCH_CONTEXT switchContext
,
232 PNDIS_SWITCH_PORT_PARAMETERS portParam
)
234 POVS_VPORT_ENTRY vport
;
235 LOCK_STATE_EX lockState
;
237 VPORT_PORT_ENTER(portParam
);
239 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
240 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
241 portParam
->PortId
, 0);
243 /* add assertion here */
244 vport
->portState
= NdisSwitchPortStateTeardown
;
245 vport
->ovsState
= OVS_STATE_PORT_TEAR_DOWN
;
247 OVS_LOG_WARN("Vport not present.");
249 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
251 VPORT_PORT_EXIT(portParam
);
256 HvDeletePort(POVS_SWITCH_CONTEXT switchContext
,
257 PNDIS_SWITCH_PORT_PARAMETERS portParams
)
259 POVS_VPORT_ENTRY vport
;
260 LOCK_STATE_EX lockState
;
262 VPORT_PORT_ENTER(portParams
);
264 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
265 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
266 portParams
->PortId
, 0);
269 * XXX: we can only destroy and remove the port if its datapath port
270 * counterpart was deleted. If the datapath port counterpart is present,
271 * we only mark the vport for deletion, so that a netlink command vport
272 * delete will delete the vport.
275 OvsRemoveAndDeleteVport(NULL
, switchContext
, vport
, TRUE
, FALSE
);
277 OVS_LOG_WARN("Vport not present.");
279 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
281 VPORT_PORT_EXIT(portParams
);
286 * Functions implemented in relaton to NDIS NIC manipulation.
289 HvCreateNic(POVS_SWITCH_CONTEXT switchContext
,
290 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
292 POVS_VPORT_ENTRY vport
;
295 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
297 LOCK_STATE_EX lockState
;
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 /* Veto the creation of nic */
307 status
= NDIS_STATUS_NOT_SUPPORTED
;
311 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
312 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
, nicParam
->PortId
, 0);
314 OVS_LOG_ERROR("Create NIC without Switch Port,"
315 " PortId: %x, NicIndex: %d",
316 nicParam
->PortId
, nicParam
->NicIndex
);
317 status
= NDIS_STATUS_INVALID_PARAMETER
;
321 if (nicParam
->NicType
== NdisSwitchNicTypeExternal
&&
322 nicParam
->NicIndex
!= 0) {
323 POVS_VPORT_ENTRY virtExtVport
=
324 (POVS_VPORT_ENTRY
)switchContext
->virtualExternalVport
;
326 vport
= (POVS_VPORT_ENTRY
)OvsAllocateVport();
328 status
= NDIS_STATUS_RESOURCES
;
331 OvsInitPhysNicVport(vport
, virtExtVport
, nicParam
->NicIndex
);
332 status
= InitHvVportCommon(switchContext
, vport
, TRUE
);
333 if (status
!= NDIS_STATUS_SUCCESS
) {
334 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
338 OvsInitVportWithNicParam(switchContext
, vport
, nicParam
);
339 portNo
= vport
->portNo
;
340 if (vport
->ovsState
== OVS_STATE_CONNECTED
) {
341 event
= OVS_EVENT_CONNECT
| OVS_EVENT_LINK_UP
;
342 } else if (vport
->ovsState
== OVS_STATE_NIC_CREATED
) {
343 event
= OVS_EVENT_CONNECT
;
347 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
348 if (portNo
!= OVS_DPPORT_NUMBER_INVALID
&& event
) {
349 OvsPostEvent(portNo
, event
);
353 VPORT_NIC_EXIT(nicParam
);
354 OVS_LOG_TRACE("Exit: status %8x.\n", status
);
360 /* Mark already created NIC as connected. */
362 HvConnectNic(POVS_SWITCH_CONTEXT switchContext
,
363 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
365 LOCK_STATE_EX lockState
;
366 POVS_VPORT_ENTRY vport
;
369 VPORT_NIC_ENTER(nicParam
);
371 /* Wait for lists to be initialized. */
372 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
374 if (!switchContext
->isActivated
) {
375 OVS_LOG_WARN("Switch is not activated yet.");
379 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
380 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
385 OVS_LOG_WARN("Vport not present.");
386 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
391 vport
->ovsState
= OVS_STATE_CONNECTED
;
392 vport
->nicState
= NdisSwitchNicStateConnected
;
393 portNo
= vport
->portNo
;
395 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
397 /* XXX only if portNo != INVALID or always? */
398 OvsPostEvent(portNo
, OVS_EVENT_LINK_UP
);
400 if (nicParam
->NicType
== NdisSwitchNicTypeInternal
) {
401 OvsInternalAdapterUp(portNo
, &nicParam
->NetCfgInstanceId
);
405 VPORT_NIC_EXIT(nicParam
);
409 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext
,
410 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
412 POVS_VPORT_ENTRY vport
;
413 LOCK_STATE_EX lockState
;
415 UINT32 status
= 0, portNo
= 0;
417 VPORT_NIC_ENTER(nicParam
);
419 /* Wait for lists to be initialized. */
420 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
422 if (!switchContext
->isActivated
) {
423 OVS_LOG_WARN("Switch is not activated yet.");
424 goto update_nic_done
;
427 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
428 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
432 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
433 OVS_LOG_WARN("Vport search failed.");
434 goto update_nic_done
;
436 switch (nicParam
->NicType
) {
437 case NdisSwitchNicTypeExternal
:
438 case NdisSwitchNicTypeInternal
:
439 RtlCopyMemory(&vport
->netCfgInstanceId
, &nicParam
->NetCfgInstanceId
,
442 case NdisSwitchNicTypeSynthetic
:
443 case NdisSwitchNicTypeEmulated
:
444 if (!RtlEqualMemory(vport
->vmMacAddress
, nicParam
->VMMacAddress
,
445 sizeof (vport
->vmMacAddress
))) {
446 status
|= OVS_EVENT_MAC_CHANGE
;
447 RtlCopyMemory(vport
->vmMacAddress
, nicParam
->VMMacAddress
,
448 sizeof (vport
->vmMacAddress
));
454 if (!RtlEqualMemory(vport
->permMacAddress
, nicParam
->PermanentMacAddress
,
455 sizeof (vport
->permMacAddress
))) {
456 RtlCopyMemory(vport
->permMacAddress
, nicParam
->PermanentMacAddress
,
457 sizeof (vport
->permMacAddress
));
458 status
|= OVS_EVENT_MAC_CHANGE
;
460 if (!RtlEqualMemory(vport
->currMacAddress
, nicParam
->CurrentMacAddress
,
461 sizeof (vport
->currMacAddress
))) {
462 RtlCopyMemory(vport
->currMacAddress
, nicParam
->CurrentMacAddress
,
463 sizeof (vport
->currMacAddress
));
464 status
|= OVS_EVENT_MAC_CHANGE
;
467 if (vport
->mtu
!= nicParam
->MTU
) {
468 vport
->mtu
= nicParam
->MTU
;
469 status
|= OVS_EVENT_MTU_CHANGE
;
471 vport
->numaNodeId
= nicParam
->NumaNodeId
;
472 portNo
= vport
->portNo
;
474 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
475 if (status
&& portNo
) {
476 OvsPostEvent(portNo
, status
);
479 VPORT_NIC_EXIT(nicParam
);
484 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext
,
485 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
487 POVS_VPORT_ENTRY vport
;
489 LOCK_STATE_EX lockState
;
490 BOOLEAN isInternalPort
= FALSE
;
492 VPORT_NIC_ENTER(nicParam
);
494 /* Wait for lists to be initialized. */
495 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
497 if (!switchContext
->isActivated
) {
498 OVS_LOG_WARN("Switch is not activated yet.");
502 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
503 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
508 OVS_LOG_WARN("Vport not present.");
509 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
513 vport
->nicState
= NdisSwitchNicStateDisconnected
;
514 vport
->ovsState
= OVS_STATE_NIC_CREATED
;
515 portNo
= vport
->portNo
;
517 if (vport
->ovsType
== OVS_VPORT_TYPE_INTERNAL
) {
518 isInternalPort
= TRUE
;
521 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
523 /* XXX if portNo != INVALID or always? */
524 OvsPostEvent(portNo
, OVS_EVENT_LINK_DOWN
);
526 if (isInternalPort
) {
527 OvsInternalAdapterDown();
531 VPORT_NIC_EXIT(nicParam
);
536 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext
,
537 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
539 LOCK_STATE_EX lockState
;
540 POVS_VPORT_ENTRY vport
;
543 VPORT_NIC_ENTER(nicParam
);
544 /* Wait for lists to be initialized. */
545 OvsWaitActivate(switchContext
, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC
);
547 if (!switchContext
->isActivated
) {
548 OVS_LOG_WARN("Switch is not activated yet.");
552 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
553 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
558 OVS_LOG_WARN("Vport not present.");
559 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
563 vport
->nicState
= NdisSwitchNicStateUnknown
;
564 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
566 portNo
= vport
->portNo
;
567 if (vport
->portType
== NdisSwitchPortTypeExternal
&&
568 vport
->nicIndex
!= 0) {
569 OvsRemoveAndDeleteVport(NULL
, switchContext
, vport
, TRUE
, FALSE
);
572 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
573 /* XXX if portNo != INVALID or always? */
574 OvsPostEvent(portNo
, OVS_EVENT_DISCONNECT
);
577 VPORT_NIC_EXIT(nicParam
);
582 * OVS Vport related functionality.
585 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext
,
588 POVS_VPORT_ENTRY vport
;
589 PLIST_ENTRY head
, link
;
590 UINT32 hash
= OvsJhashBytes((const VOID
*)&portNo
, sizeof(portNo
),
592 head
= &(switchContext
->portNoHashArray
[hash
& OVS_VPORT_MASK
]);
593 LIST_FORALL(head
, link
) {
594 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portNoLink
);
595 if (vport
->portNo
== portNo
) {
604 OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext
,
607 POVS_VPORT_ENTRY vport
;
608 PLIST_ENTRY head
, link
;
609 UINT32 hash
= OvsJhashBytes((const VOID
*)&dstPort
, sizeof(dstPort
),
611 head
= &(switchContext
->tunnelVportsArray
[hash
& OVS_VPORT_MASK
]);
612 LIST_FORALL(head
, link
) {
613 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, tunnelVportLink
);
614 if (((POVS_VXLAN_VPORT
)vport
->priv
)->dstPort
== dstPort
) {
623 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext
,
626 POVS_VPORT_ENTRY vport
;
627 PLIST_ENTRY head
, link
;
629 SIZE_T length
= strlen(name
) + 1;
631 hash
= OvsJhashBytes((const VOID
*)name
, length
, OVS_HASH_BASIS
);
632 head
= &(switchContext
->ovsPortNameHashArray
[hash
& OVS_VPORT_MASK
]);
634 LIST_FORALL(head
, link
) {
635 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, ovsNameLink
);
636 if (!strcmp(name
, vport
->ovsName
)) {
644 /* OvsFindVportByHvName: "name" is assumed to be null-terminated */
646 OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext
,
647 PWSTR wsName
, SIZE_T wstrSize
)
649 POVS_VPORT_ENTRY vport
= NULL
;
650 PLIST_ENTRY head
, link
;
653 for (i
= 0; i
< OVS_MAX_VPORT_ARRAY_SIZE
; i
++) {
654 head
= &(switchContext
->portIdHashArray
[i
]);
655 LIST_FORALL(head
, link
) {
656 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portIdLink
);
659 * NOTE about portFriendlyName:
660 * If the string is NULL-terminated, the Length member does not
661 * include the terminating NULL character.
663 if (vport
->portFriendlyName
.Length
== wstrSize
&&
664 RtlEqualMemory(wsName
, vport
->portFriendlyName
.String
,
665 vport
->portFriendlyName
.Length
)) {
674 * Look in the list of ports that were added from the Hyper-V switch and
678 for (i
= 0; i
< OVS_MAX_VPORT_ARRAY_SIZE
; i
++) {
679 head
= &(switchContext
->portNoHashArray
[i
]);
680 LIST_FORALL(head
, link
) {
681 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portNoLink
);
682 if (vport
->portFriendlyName
.Length
== wstrSize
&&
683 RtlEqualMemory(wsName
, vport
->portFriendlyName
.String
,
684 vport
->portFriendlyName
.Length
)) {
698 OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext
,
701 POVS_VPORT_ENTRY vport
= NULL
;
702 /* 'portFriendlyName' is not NUL-terminated. */
703 SIZE_T length
= strlen(name
);
704 SIZE_T wstrSize
= length
* sizeof(WCHAR
);
707 PWSTR wsName
= OvsAllocateMemoryWithTag(wstrSize
, OVS_VPORT_POOL_TAG
);
711 for (i
= 0; i
< length
; i
++) {
714 vport
= OvsFindVportByHvNameW(switchContext
, wsName
, wstrSize
);
715 OvsFreeMemoryWithTag(wsName
, OVS_VPORT_POOL_TAG
);
720 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext
,
721 NDIS_SWITCH_PORT_ID portId
,
722 NDIS_SWITCH_NIC_INDEX index
)
724 if (switchContext
->virtualExternalVport
&&
725 portId
== switchContext
->virtualExternalPortId
&&
726 index
== switchContext
->virtualExternalVport
->nicIndex
) {
727 return (POVS_VPORT_ENTRY
)switchContext
->virtualExternalVport
;
728 } else if (switchContext
->internalVport
&&
729 portId
== switchContext
->internalPortId
&&
730 index
== switchContext
->internalVport
->nicIndex
) {
731 return (POVS_VPORT_ENTRY
)switchContext
->internalVport
;
733 PLIST_ENTRY head
, link
;
734 POVS_VPORT_ENTRY vport
;
736 hash
= OvsJhashWords((UINT32
*)&portId
, 1, OVS_HASH_BASIS
);
737 head
= &(switchContext
->portIdHashArray
[hash
& OVS_VPORT_MASK
]);
738 LIST_FORALL(head
, link
) {
739 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portIdLink
);
740 if (portId
== vport
->portId
&& index
== vport
->nicIndex
) {
749 OvsAllocateVport(VOID
)
751 POVS_VPORT_ENTRY vport
;
752 vport
= (POVS_VPORT_ENTRY
)OvsAllocateMemoryWithTag(
753 sizeof(OVS_VPORT_ENTRY
), OVS_VPORT_POOL_TAG
);
757 RtlZeroMemory(vport
, sizeof (OVS_VPORT_ENTRY
));
758 vport
->ovsState
= OVS_STATE_UNKNOWN
;
759 vport
->isPresentOnHv
= FALSE
;
760 vport
->portNo
= OVS_DPPORT_NUMBER_INVALID
;
762 InitializeListHead(&vport
->ovsNameLink
);
763 InitializeListHead(&vport
->portIdLink
);
764 InitializeListHead(&vport
->portNoLink
);
770 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport
,
771 PNDIS_SWITCH_PORT_PARAMETERS portParam
)
773 vport
->portType
= portParam
->PortType
;
774 vport
->portState
= portParam
->PortState
;
775 vport
->portId
= portParam
->PortId
;
776 vport
->nicState
= NdisSwitchNicStateUnknown
;
777 vport
->isExternal
= FALSE
;
778 vport
->isBridgeInternal
= FALSE
;
780 switch (vport
->portType
) {
781 case NdisSwitchPortTypeExternal
:
782 vport
->isExternal
= TRUE
;
783 vport
->ovsType
= OVS_VPORT_TYPE_NETDEV
;
785 case NdisSwitchPortTypeInternal
:
786 vport
->ovsType
= OVS_VPORT_TYPE_INTERNAL
;
788 case NdisSwitchPortTypeSynthetic
:
789 case NdisSwitchPortTypeEmulated
:
790 vport
->ovsType
= OVS_VPORT_TYPE_NETDEV
;
793 RtlCopyMemory(&vport
->hvPortName
, &portParam
->PortName
,
794 sizeof (NDIS_SWITCH_PORT_NAME
));
795 /* For external and internal ports, 'portFriendlyName' is overwritten
797 RtlCopyMemory(&vport
->portFriendlyName
, &portParam
->PortFriendlyName
,
798 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME
));
800 switch (vport
->portState
) {
801 case NdisSwitchPortStateCreated
:
802 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
804 case NdisSwitchPortStateTeardown
:
805 vport
->ovsState
= OVS_STATE_PORT_TEAR_DOWN
;
807 case NdisSwitchPortStateDeleted
:
808 vport
->ovsState
= OVS_STATE_PORT_DELETED
;
815 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext
,
816 POVS_VPORT_ENTRY vport
,
817 PNDIS_SWITCH_NIC_PARAMETERS nicParam
)
819 ASSERT(vport
->portId
== nicParam
->PortId
);
820 ASSERT(vport
->ovsState
== OVS_STATE_PORT_CREATED
);
822 UNREFERENCED_PARAMETER(switchContext
);
824 RtlCopyMemory(vport
->permMacAddress
, nicParam
->PermanentMacAddress
,
825 sizeof (nicParam
->PermanentMacAddress
));
826 RtlCopyMemory(vport
->currMacAddress
, nicParam
->CurrentMacAddress
,
827 sizeof (nicParam
->CurrentMacAddress
));
829 if (nicParam
->NicType
== NdisSwitchNicTypeSynthetic
||
830 nicParam
->NicType
== NdisSwitchNicTypeEmulated
) {
831 RtlCopyMemory(vport
->vmMacAddress
, nicParam
->VMMacAddress
,
832 sizeof (nicParam
->VMMacAddress
));
833 RtlCopyMemory(&vport
->vmName
, &nicParam
->VmName
,
834 sizeof (nicParam
->VmName
));
836 RtlCopyMemory(&vport
->netCfgInstanceId
, &nicParam
->NetCfgInstanceId
,
837 sizeof (nicParam
->NetCfgInstanceId
));
839 RtlCopyMemory(&vport
->nicName
, &nicParam
->NicName
,
840 sizeof (nicParam
->NicName
));
841 vport
->mtu
= nicParam
->MTU
;
842 vport
->nicState
= nicParam
->NicState
;
843 vport
->nicIndex
= nicParam
->NicIndex
;
844 vport
->numaNodeId
= nicParam
->NumaNodeId
;
846 switch (vport
->nicState
) {
847 case NdisSwitchNicStateCreated
:
848 vport
->ovsState
= OVS_STATE_NIC_CREATED
;
850 case NdisSwitchNicStateConnected
:
851 vport
->ovsState
= OVS_STATE_CONNECTED
;
853 case NdisSwitchNicStateDisconnected
:
854 vport
->ovsState
= OVS_STATE_NIC_CREATED
;
856 case NdisSwitchNicStateDeleted
:
857 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
863 * --------------------------------------------------------------------------
864 * Copies the relevant NDIS port properties from a virtual (pseudo) external
865 * NIC to a physical (real) external NIC.
866 * --------------------------------------------------------------------------
869 OvsInitPhysNicVport(POVS_VPORT_ENTRY physExtVport
,
870 POVS_VPORT_ENTRY virtExtVport
,
873 physExtVport
->portType
= virtExtVport
->portType
;
874 physExtVport
->portState
= virtExtVport
->portState
;
875 physExtVport
->portId
= virtExtVport
->portId
;
876 physExtVport
->nicState
= NdisSwitchNicStateUnknown
;
877 physExtVport
->ovsType
= OVS_VPORT_TYPE_NETDEV
;
878 physExtVport
->isExternal
= TRUE
;
879 physExtVport
->isBridgeInternal
= FALSE
;
880 physExtVport
->nicIndex
= (NDIS_SWITCH_NIC_INDEX
)physNicIndex
;
882 RtlCopyMemory(&physExtVport
->hvPortName
, &virtExtVport
->hvPortName
,
883 sizeof (NDIS_SWITCH_PORT_NAME
));
885 /* 'portFriendlyName' is overwritten later. */
886 RtlCopyMemory(&physExtVport
->portFriendlyName
,
887 &virtExtVport
->portFriendlyName
,
888 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME
));
890 physExtVport
->ovsState
= OVS_STATE_PORT_CREATED
;
894 * --------------------------------------------------------------------------
895 * Initializes a tunnel vport.
896 * --------------------------------------------------------------------------
899 OvsInitTunnelVport(PVOID userContext
,
900 POVS_VPORT_ENTRY vport
,
901 OVS_VPORT_TYPE ovsType
,
904 NTSTATUS status
= STATUS_SUCCESS
;
905 POVS_USER_PARAMS_CONTEXT usrParamsCtx
=
906 (POVS_USER_PARAMS_CONTEXT
)userContext
;
908 vport
->isBridgeInternal
= FALSE
;
909 vport
->ovsType
= ovsType
;
910 vport
->ovsState
= OVS_STATE_PORT_CREATED
;
912 case OVS_VPORT_TYPE_GRE
:
914 case OVS_VPORT_TYPE_GRE64
:
916 case OVS_VPORT_TYPE_VXLAN
:
918 POVS_TUNFLT_INIT_CONTEXT tunnelContext
= NULL
;
920 tunnelContext
= OvsAllocateMemory(sizeof(*tunnelContext
));
921 if (tunnelContext
== NULL
) {
922 status
= STATUS_INSUFFICIENT_RESOURCES
;
925 tunnelContext
->inputBuffer
= usrParamsCtx
->inputBuffer
;
926 tunnelContext
->outputBuffer
= usrParamsCtx
->outputBuffer
;
927 tunnelContext
->outputLength
= usrParamsCtx
->outputLength
;
928 tunnelContext
->vport
= vport
;
930 status
= OvsInitVxlanTunnel(usrParamsCtx
->irp
,
933 OvsTunnelVportPendingInit
,
934 (PVOID
)tunnelContext
);
944 * --------------------------------------------------------------------------
945 * Initializes a bridge internal vport ie. a port of type
946 * OVS_VPORT_TYPE_INTERNAL but not present on the Hyper-V switch.
947 * --------------------------------------------------------------------------
950 OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport
)
952 vport
->isBridgeInternal
= TRUE
;
953 vport
->ovsType
= OVS_VPORT_TYPE_INTERNAL
;
954 /* Mark the status to be connected, since there is no other initialization
956 vport
->ovsState
= OVS_STATE_CONNECTED
;
957 return STATUS_SUCCESS
;
961 * --------------------------------------------------------------------------
962 * For external vports 'portFriendlyName' provided by Hyper-V is over-written
963 * by synthetic names.
964 * --------------------------------------------------------------------------
967 AssignNicNameSpecial(POVS_VPORT_ENTRY vport
)
971 if (vport
->portType
== NdisSwitchPortTypeExternal
) {
972 if (vport
->nicIndex
== 0) {
973 ASSERT(vport
->nicIndex
== 0);
974 RtlStringCbPrintfW(vport
->portFriendlyName
.String
,
976 L
"%s.virtualAdapter", OVS_DPPORT_EXTERNAL_NAME_W
);
978 RtlStringCbPrintfW(vport
->portFriendlyName
.String
,
980 L
"%s.%lu", OVS_DPPORT_EXTERNAL_NAME_W
,
981 (UINT32
)vport
->nicIndex
);
984 RtlStringCbPrintfW(vport
->portFriendlyName
.String
,
986 L
"%s", OVS_DPPORT_INTERNAL_NAME_W
);
989 RtlStringCbLengthW(vport
->portFriendlyName
.String
, IF_MAX_STRING_SIZE
,
991 vport
->portFriendlyName
.Length
= (USHORT
)len
;
996 * --------------------------------------------------------------------------
997 * Functionality common to any port on the Hyper-V switch. This function is not
998 * to be called for a port that is not on the Hyper-V switch.
1000 * Inserts the port into 'portIdHashArray' and caches the pointer in the
1001 * 'switchContext' if needed.
1003 * For external NIC, assigns the name for the NIC.
1004 * --------------------------------------------------------------------------
1007 InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext
,
1008 POVS_VPORT_ENTRY vport
,
1013 switch (vport
->portType
) {
1014 case NdisSwitchPortTypeExternal
:
1016 * Overwrite the 'portFriendlyName' of this external vport. The reason
1017 * for having this in common code is to be able to call it from the NDIS
1018 * Port callback as well as the NDIS NIC callback.
1020 AssignNicNameSpecial(vport
);
1022 if (vport
->nicIndex
== 0) {
1023 switchContext
->virtualExternalPortId
= vport
->portId
;
1024 switchContext
->virtualExternalVport
= vport
;
1026 switchContext
->numPhysicalNics
++;
1029 case NdisSwitchPortTypeInternal
:
1030 ASSERT(vport
->isBridgeInternal
== FALSE
);
1032 /* Overwrite the 'portFriendlyName' of the internal vport. */
1033 AssignNicNameSpecial(vport
);
1034 switchContext
->internalPortId
= vport
->portId
;
1035 switchContext
->internalVport
= vport
;
1037 case NdisSwitchPortTypeSynthetic
:
1038 case NdisSwitchPortTypeEmulated
:
1043 * It is important to not insert vport corresponding to virtual external
1044 * port into the 'portIdHashArray' since the port should not be exposed to
1047 if (vport
->portType
== NdisSwitchPortTypeExternal
&&
1048 vport
->nicIndex
== 0) {
1049 return NDIS_STATUS_SUCCESS
;
1053 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
1054 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
1055 * hyper-v switch seems to use only 2 bytes out of 4.
1057 hash
= OvsJhashWords(&vport
->portId
, 1, OVS_HASH_BASIS
);
1058 InsertHeadList(&switchContext
->portIdHashArray
[hash
& OVS_VPORT_MASK
],
1059 &vport
->portIdLink
);
1061 switchContext
->numHvVports
++;
1063 return NDIS_STATUS_SUCCESS
;
1067 * --------------------------------------------------------------------------
1068 * Functionality common to any port added from OVS userspace.
1070 * Inserts the port into 'portNoHashArray', 'ovsPortNameHashArray' and in
1071 * 'tunnelVportsArray' if appropriate.
1072 * --------------------------------------------------------------------------
1075 InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext
,
1076 POVS_VPORT_ENTRY vport
)
1080 switch(vport
->ovsType
) {
1081 case OVS_VPORT_TYPE_VXLAN
:
1083 POVS_VXLAN_VPORT vxlanVport
= (POVS_VXLAN_VPORT
)vport
->priv
;
1084 hash
= OvsJhashBytes(&vxlanVport
->dstPort
,
1085 sizeof(vxlanVport
->dstPort
),
1088 &gOvsSwitchContext
->tunnelVportsArray
[hash
& OVS_VPORT_MASK
],
1089 &vport
->tunnelVportLink
);
1090 switchContext
->numNonHvVports
++;
1093 case OVS_VPORT_TYPE_INTERNAL
:
1094 if (vport
->isBridgeInternal
) {
1095 switchContext
->numNonHvVports
++;
1102 * Insert the port into the hash array of ports: by port number and ovs
1103 * and ovs (datapath) port name.
1104 * NOTE: OvsJhashWords has portNo as "1" word. This is ok, because the
1105 * portNo is stored in 2 bytes only (max port number = MAXUINT16).
1107 hash
= OvsJhashWords(&vport
->portNo
, 1, OVS_HASH_BASIS
);
1108 InsertHeadList(&gOvsSwitchContext
->portNoHashArray
[hash
& OVS_VPORT_MASK
],
1109 &vport
->portNoLink
);
1111 hash
= OvsJhashBytes(vport
->ovsName
, strlen(vport
->ovsName
) + 1,
1114 &gOvsSwitchContext
->ovsPortNameHashArray
[hash
& OVS_VPORT_MASK
],
1115 &vport
->ovsNameLink
);
1117 return STATUS_SUCCESS
;
1121 OvsCleanupVportCommon(POVS_SWITCH_CONTEXT switchContext
,
1122 POVS_VPORT_ENTRY vport
,
1123 BOOLEAN hvSwitchPort
,
1127 BOOLEAN deletedOnOvs
= FALSE
;
1128 BOOLEAN deletedOnHv
= FALSE
;
1131 * 'hvDelete' == TRUE indicates that the port should be removed from the
1132 * 'portIdHashArray', while 'ovsDelete' == TRUE indicates that the port
1133 * should be removed from 'portNoHashArray' and the 'ovsPortNameHashArray'.
1135 * Both 'hvDelete' and 'ovsDelete' can be set to TRUE by the caller.
1137 if (vport
->isPresentOnHv
== TRUE
) {
1140 if (vport
->portNo
== OVS_DPPORT_NUMBER_INVALID
) {
1141 deletedOnOvs
= TRUE
;
1144 if (hvDelete
&& !deletedOnHv
) {
1145 vport
->isPresentOnHv
= TRUE
;
1147 /* Remove the port from the relevant lists. */
1148 RemoveEntryList(&vport
->portIdLink
);
1149 InitializeListHead(&vport
->portIdLink
);
1152 if (ovsDelete
&& !deletedOnOvs
) {
1153 vport
->portNo
= OVS_DPPORT_NUMBER_INVALID
;
1154 vport
->ovsName
[0] = '\0';
1156 /* Remove the port from the relevant lists. */
1157 RemoveEntryList(&vport
->ovsNameLink
);
1158 InitializeListHead(&vport
->ovsNameLink
);
1159 RemoveEntryList(&vport
->portNoLink
);
1160 InitializeListHead(&vport
->portNoLink
);
1161 if (OVS_VPORT_TYPE_VXLAN
== vport
->ovsType
) {
1162 RemoveEntryList(&vport
->tunnelVportLink
);
1163 InitializeListHead(&vport
->tunnelVportLink
);
1166 deletedOnOvs
= TRUE
;
1170 * Deallocate the port if it has been deleted on the Hyper-V switch as well
1173 if (deletedOnHv
&& deletedOnOvs
) {
1175 switchContext
->numHvVports
--;
1178 switchContext
->numNonHvVports
--;
1180 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
1185 * --------------------------------------------------------------------------
1186 * Provides functionality that is partly complementatry to
1187 * InitOvsVportCommon()/InitHvVportCommon().
1189 * 'hvDelete' indicates if caller is removing the vport as a result of the
1190 * port being removed on the Hyper-V switch.
1191 * 'ovsDelete' indicates if caller is removing the vport as a result of the
1192 * port being removed from OVS userspace.
1193 * --------------------------------------------------------------------------
1196 OvsRemoveAndDeleteVport(PVOID usrParamsContext
,
1197 POVS_SWITCH_CONTEXT switchContext
,
1198 POVS_VPORT_ENTRY vport
,
1202 NTSTATUS status
= STATUS_SUCCESS
;
1203 POVS_USER_PARAMS_CONTEXT usrParamsCtx
=
1204 (POVS_USER_PARAMS_CONTEXT
)usrParamsContext
;
1205 BOOLEAN hvSwitchPort
= FALSE
;
1207 if (vport
->isExternal
) {
1208 if (vport
->nicIndex
== 0) {
1209 ASSERT(switchContext
->numPhysicalNics
== 0);
1210 switchContext
->virtualExternalPortId
= 0;
1211 switchContext
->virtualExternalVport
= NULL
;
1212 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
1213 return STATUS_SUCCESS
;
1215 ASSERT(switchContext
->numPhysicalNics
);
1216 switchContext
->numPhysicalNics
--;
1217 hvSwitchPort
= TRUE
;
1221 switch (vport
->ovsType
) {
1222 case OVS_VPORT_TYPE_INTERNAL
:
1223 if (!vport
->isBridgeInternal
) {
1224 switchContext
->internalPortId
= 0;
1225 switchContext
->internalVport
= NULL
;
1226 OvsInternalAdapterDown();
1227 hvSwitchPort
= TRUE
;
1230 case OVS_VPORT_TYPE_VXLAN
:
1232 POVS_TUNFLT_INIT_CONTEXT tunnelContext
= NULL
;
1235 tunnelContext
= OvsAllocateMemory(sizeof(*tunnelContext
));
1236 if (tunnelContext
== NULL
) {
1237 status
= STATUS_INSUFFICIENT_RESOURCES
;
1240 RtlZeroMemory(tunnelContext
, sizeof(*tunnelContext
));
1242 tunnelContext
->switchContext
= switchContext
;
1243 tunnelContext
->hvSwitchPort
= hvSwitchPort
;
1244 tunnelContext
->hvDelete
= hvDelete
;
1245 tunnelContext
->ovsDelete
= ovsDelete
;
1246 tunnelContext
->vport
= vport
;
1249 tunnelContext
->inputBuffer
= usrParamsCtx
->inputBuffer
;
1250 tunnelContext
->outputBuffer
= usrParamsCtx
->outputBuffer
;
1251 tunnelContext
->outputLength
= usrParamsCtx
->outputLength
;
1252 irp
= usrParamsCtx
->irp
;
1255 status
= OvsCleanupVxlanTunnel(irp
,
1257 OvsTunnelVportPendingUninit
,
1261 case OVS_VPORT_TYPE_GRE
:
1262 case OVS_VPORT_TYPE_GRE64
:
1264 case OVS_VPORT_TYPE_NETDEV
:
1265 hvSwitchPort
= TRUE
;
1270 if (STATUS_SUCCESS
== status
) {
1271 OvsCleanupVportCommon(switchContext
,
1282 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext
)
1284 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
1286 PNDIS_SWITCH_PORT_PARAMETERS portParam
;
1287 PNDIS_SWITCH_PORT_ARRAY portArray
= NULL
;
1288 POVS_VPORT_ENTRY vport
;
1290 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext
);
1292 status
= OvsGetPortsOnSwitch(switchContext
, &portArray
);
1293 if (status
!= NDIS_STATUS_SUCCESS
) {
1297 for (arrIndex
= 0; arrIndex
< portArray
->NumElements
; arrIndex
++) {
1298 portParam
= NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray
, arrIndex
);
1300 if (portParam
->IsValidationPort
) {
1304 vport
= (POVS_VPORT_ENTRY
)OvsAllocateVport();
1305 if (vport
== NULL
) {
1306 status
= NDIS_STATUS_RESOURCES
;
1309 OvsInitVportWithPortParam(vport
, portParam
);
1310 status
= InitHvVportCommon(switchContext
, vport
, TRUE
);
1311 if (status
!= NDIS_STATUS_SUCCESS
) {
1312 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
1318 if (status
!= NDIS_STATUS_SUCCESS
) {
1319 OvsClearAllSwitchVports(switchContext
);
1322 OvsFreeSwitchPortsArray(portArray
);
1324 OVS_LOG_TRACE("Exit: status: %x", status
);
1331 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext
)
1333 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
1334 PNDIS_SWITCH_NIC_ARRAY nicArray
= NULL
;
1336 PNDIS_SWITCH_NIC_PARAMETERS nicParam
;
1337 POVS_VPORT_ENTRY vport
;
1339 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext
);
1341 * Now, get NIC list.
1343 status
= OvsGetNicsOnSwitch(switchContext
, &nicArray
);
1344 if (status
!= NDIS_STATUS_SUCCESS
) {
1347 for (arrIndex
= 0; arrIndex
< nicArray
->NumElements
; ++arrIndex
) {
1349 nicParam
= NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray
, arrIndex
);
1352 * XXX: Check if the port is configured with a VLAN. Disallow such a
1353 * configuration, since we don't support tag-in-tag.
1357 * XXX: Check if the port is connected to a VF. Disconnect the VF in
1361 if (nicParam
->NicType
== NdisSwitchNicTypeExternal
&&
1362 nicParam
->NicIndex
!= 0) {
1363 POVS_VPORT_ENTRY virtExtVport
=
1364 (POVS_VPORT_ENTRY
)switchContext
->virtualExternalVport
;
1366 vport
= OvsAllocateVport();
1368 OvsInitPhysNicVport(vport
, virtExtVport
,
1369 nicParam
->NicIndex
);
1370 status
= InitHvVportCommon(switchContext
, vport
, TRUE
);
1371 if (status
!= NDIS_STATUS_SUCCESS
) {
1372 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
1377 vport
= OvsFindVportByPortIdAndNicIndex(switchContext
,
1379 nicParam
->NicIndex
);
1381 if (vport
== NULL
) {
1382 OVS_LOG_ERROR("Fail to allocate vport");
1385 OvsInitVportWithNicParam(switchContext
, vport
, nicParam
);
1386 if (nicParam
->NicType
== NdisSwitchNicTypeInternal
) {
1387 OvsInternalAdapterUp(vport
->portNo
, &nicParam
->NetCfgInstanceId
);
1392 OvsFreeSwitchNicsArray(nicArray
);
1394 OVS_LOG_TRACE("Exit: status: %x", status
);
1399 * --------------------------------------------------------------------------
1400 * Deletes ports added from the Hyper-V switch as well as OVS usersapce. The
1401 * function deletes ports in 'portIdHashArray'. This will delete most of the
1402 * ports that are in the 'portNoHashArray' as well. Any remaining ports
1403 * are deleted by walking the the 'portNoHashArray'.
1404 * --------------------------------------------------------------------------
1407 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext
)
1409 for (UINT hash
= 0; hash
< OVS_MAX_VPORT_ARRAY_SIZE
; hash
++) {
1410 PLIST_ENTRY head
, link
, next
;
1412 head
= &(switchContext
->portIdHashArray
[hash
& OVS_VPORT_MASK
]);
1413 LIST_FORALL_SAFE(head
, link
, next
) {
1414 POVS_VPORT_ENTRY vport
;
1415 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portIdLink
);
1416 OvsRemoveAndDeleteVport(NULL
, switchContext
, vport
, TRUE
, TRUE
);
1421 * Remove 'virtualExternalVport' as well. This port is not part of the
1422 * 'portIdHashArray'.
1424 if (switchContext
->virtualExternalVport
) {
1425 OvsRemoveAndDeleteVport(NULL
, switchContext
,
1426 (POVS_VPORT_ENTRY
)switchContext
->virtualExternalVport
, TRUE
, TRUE
);
1430 for (UINT hash
= 0; hash
< OVS_MAX_VPORT_ARRAY_SIZE
; hash
++) {
1431 PLIST_ENTRY head
, link
, next
;
1432 head
= &(switchContext
->portNoHashArray
[hash
& OVS_VPORT_MASK
]);
1433 LIST_FORALL_SAFE(head
, link
, next
) {
1434 POVS_VPORT_ENTRY vport
;
1435 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portNoLink
);
1436 ASSERT(OvsIsTunnelVportType(vport
->ovsType
) ||
1437 (vport
->ovsType
== OVS_VPORT_TYPE_INTERNAL
&&
1438 vport
->isBridgeInternal
) || vport
->isPresentOnHv
== TRUE
);
1439 OvsRemoveAndDeleteVport(NULL
, switchContext
, vport
, TRUE
, TRUE
);
1443 ASSERT(switchContext
->virtualExternalVport
== NULL
);
1444 ASSERT(switchContext
->internalVport
== NULL
);
1449 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr
,
1454 UNICODE_STRING ustr
;
1458 ustr
.Buffer
= wStr
->String
;
1459 ustr
.Length
= wStr
->Length
;
1460 ustr
.MaximumLength
= IF_MAX_STRING_SIZE
;
1463 astr
.MaximumLength
= maxStrLen
;
1466 size
= RtlUnicodeStringToAnsiSize(&ustr
);
1467 if (size
> maxStrLen
) {
1468 return STATUS_BUFFER_OVERFLOW
;
1471 status
= RtlUnicodeStringToAnsiString(&astr
, &ustr
, FALSE
);
1473 ASSERT(status
== STATUS_SUCCESS
);
1474 if (status
!= STATUS_SUCCESS
) {
1477 ASSERT(astr
.Length
<= maxStrLen
);
1478 str
[astr
.Length
] = 0;
1479 return STATUS_SUCCESS
;
1483 * --------------------------------------------------------------------------
1484 * Utility function that populates a 'OVS_VPORT_EXT_INFO' structure for the
1486 * --------------------------------------------------------------------------
1489 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet
,
1490 POVS_VPORT_EXT_INFO extInfo
)
1492 POVS_VPORT_ENTRY vport
;
1494 LOCK_STATE_EX lockState
;
1495 NTSTATUS status
= STATUS_SUCCESS
;
1496 BOOLEAN doConvert
= FALSE
;
1498 RtlZeroMemory(extInfo
, sizeof (POVS_VPORT_EXT_INFO
));
1499 NdisAcquireRWLockRead(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
1500 if (vportGet
->portNo
== 0) {
1501 StringCbLengthA(vportGet
->name
, OVS_MAX_PORT_NAME_LENGTH
- 1, &len
);
1502 vport
= OvsFindVportByHvNameA(gOvsSwitchContext
, vportGet
->name
);
1503 if (vport
!= NULL
) {
1504 /* If the port is not a Hyper-V port and it has been added earlier,
1505 * we'll find it in 'ovsPortNameHashArray'. */
1506 vport
= OvsFindVportByOvsName(gOvsSwitchContext
, vportGet
->name
);
1509 vport
= OvsFindVportByPortNo(gOvsSwitchContext
, vportGet
->portNo
);
1511 if (vport
== NULL
|| (vport
->ovsState
!= OVS_STATE_CONNECTED
&&
1512 vport
->ovsState
!= OVS_STATE_NIC_CREATED
)) {
1513 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1514 if (vportGet
->portNo
) {
1515 OVS_LOG_WARN("vport %u does not exist any more", vportGet
->portNo
);
1517 OVS_LOG_WARN("vport %s does not exist any more", vportGet
->name
);
1519 status
= STATUS_DEVICE_DOES_NOT_EXIST
;
1522 extInfo
->dpNo
= vportGet
->dpNo
;
1523 extInfo
->portNo
= vport
->portNo
;
1524 RtlCopyMemory(extInfo
->macAddress
, vport
->currMacAddress
,
1525 sizeof (vport
->currMacAddress
));
1526 RtlCopyMemory(extInfo
->permMACAddress
, vport
->permMacAddress
,
1527 sizeof (vport
->permMacAddress
));
1528 if (vport
->ovsType
== OVS_VPORT_TYPE_NETDEV
) {
1529 RtlCopyMemory(extInfo
->vmMACAddress
, vport
->vmMacAddress
,
1530 sizeof (vport
->vmMacAddress
));
1532 extInfo
->nicIndex
= vport
->nicIndex
;
1533 extInfo
->portId
= vport
->portId
;
1534 extInfo
->type
= vport
->ovsType
;
1535 extInfo
->mtu
= vport
->mtu
;
1539 if (vport
->ovsState
== OVS_STATE_NIC_CREATED
) {
1540 extInfo
->status
= OVS_EVENT_CONNECT
| OVS_EVENT_LINK_DOWN
;
1541 } else if (vport
->ovsState
== OVS_STATE_CONNECTED
) {
1542 extInfo
->status
= OVS_EVENT_CONNECT
| OVS_EVENT_LINK_UP
;
1544 extInfo
->status
= OVS_EVENT_DISCONNECT
;
1546 if (extInfo
->type
== OVS_VPORT_TYPE_NETDEV
&&
1547 (vport
->ovsState
== OVS_STATE_NIC_CREATED
||
1548 vport
->ovsState
== OVS_STATE_CONNECTED
)) {
1551 extInfo
->vmUUID
[0] = 0;
1552 extInfo
->vifUUID
[0] = 0;
1554 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1556 status
= OvsConvertIfCountedStrToAnsiStr(&vport
->portFriendlyName
,
1558 OVS_MAX_PORT_NAME_LENGTH
);
1559 if (status
!= STATUS_SUCCESS
) {
1560 OVS_LOG_INFO("Fail to convert NIC name.");
1561 extInfo
->vmUUID
[0] = 0;
1564 status
= OvsConvertIfCountedStrToAnsiStr(&vport
->vmName
,
1566 OVS_MAX_VM_UUID_LEN
);
1567 if (status
!= STATUS_SUCCESS
) {
1568 OVS_LOG_INFO("Fail to convert VM name.");
1569 extInfo
->vmUUID
[0] = 0;
1572 status
= OvsConvertIfCountedStrToAnsiStr(&vport
->nicName
,
1574 OVS_MAX_VIF_UUID_LEN
);
1575 if (status
!= STATUS_SUCCESS
) {
1576 OVS_LOG_INFO("Fail to convert nic UUID");
1577 extInfo
->vifUUID
[0] = 0;
1580 * for now ignore status
1582 status
= STATUS_SUCCESS
;
1590 * --------------------------------------------------------------------------
1591 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1592 * --------------------------------------------------------------------------
1595 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
1598 NTSTATUS status
= STATUS_SUCCESS
;
1599 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
1600 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
1601 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
1602 OVS_VPORT_GET vportGet
;
1603 OVS_VPORT_EXT_INFO info
;
1605 static const NL_POLICY ovsNetdevPolicy
[] = {
1606 [OVS_WIN_NETDEV_ATTR_NAME
] = { .type
= NL_A_STRING
,
1608 .maxLen
= IFNAMSIZ
},
1610 PNL_ATTR netdevAttrs
[ARRAY_SIZE(ovsNetdevPolicy
)];
1612 /* input buffer has been validated while validating transaction dev op. */
1613 ASSERT(usrParamsCtx
->inputBuffer
!= NULL
&&
1614 usrParamsCtx
->inputLength
> sizeof *msgIn
);
1616 if (msgOut
== NULL
|| usrParamsCtx
->outputLength
< sizeof *msgOut
) {
1617 return STATUS_INVALID_BUFFER_SIZE
;
1620 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
1621 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
1622 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
1623 ovsNetdevPolicy
, netdevAttrs
, ARRAY_SIZE(netdevAttrs
))) {
1624 return STATUS_INVALID_PARAMETER
;
1627 vportGet
.portNo
= 0;
1628 RtlCopyMemory(&vportGet
.name
, NlAttrGet(netdevAttrs
[OVS_VPORT_ATTR_NAME
]),
1629 NlAttrGetSize(netdevAttrs
[OVS_VPORT_ATTR_NAME
]));
1631 status
= OvsGetExtInfoIoctl(&vportGet
, &info
);
1632 if (status
== STATUS_DEVICE_DOES_NOT_EXIST
) {
1633 nlError
= NL_ERROR_NODEV
;
1637 status
= CreateNetlinkMesgForNetdev(&info
, msgIn
,
1638 usrParamsCtx
->outputBuffer
, usrParamsCtx
->outputLength
,
1639 gOvsSwitchContext
->dpNo
);
1640 if (status
== STATUS_SUCCESS
) {
1641 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
1645 if (nlError
!= NL_ERROR_SUCCESS
) {
1646 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
1647 usrParamsCtx
->outputBuffer
;
1649 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
1650 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
1653 return STATUS_SUCCESS
;
1658 * --------------------------------------------------------------------------
1659 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1660 * OVS_MESSAGE contains the output of a netdev command.
1661 * --------------------------------------------------------------------------
1664 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info
,
1673 UINT32 netdevFlags
= 0;
1675 NlBufInit(&nlBuffer
, outBuffer
, outBufLen
);
1677 ok
= NlFillOvsMsg(&nlBuffer
, msgIn
->nlMsg
.nlmsgType
, NLM_F_MULTI
,
1678 msgIn
->nlMsg
.nlmsgSeq
, msgIn
->nlMsg
.nlmsgPid
,
1679 msgIn
->genlMsg
.cmd
, msgIn
->genlMsg
.version
,
1682 return STATUS_INVALID_BUFFER_SIZE
;
1685 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_PORT_NO
,
1688 return STATUS_INVALID_BUFFER_SIZE
;
1691 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_TYPE
, info
->type
);
1693 return STATUS_INVALID_BUFFER_SIZE
;
1696 ok
= NlMsgPutTailString(&nlBuffer
, OVS_WIN_NETDEV_ATTR_NAME
,
1699 return STATUS_INVALID_BUFFER_SIZE
;
1702 ok
= NlMsgPutTailUnspec(&nlBuffer
, OVS_WIN_NETDEV_ATTR_MAC_ADDR
,
1703 (PCHAR
)info
->macAddress
, sizeof (info
->macAddress
));
1705 return STATUS_INVALID_BUFFER_SIZE
;
1708 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_MTU
, info
->mtu
);
1710 return STATUS_INVALID_BUFFER_SIZE
;
1713 if (info
->status
!= OVS_EVENT_CONNECT
) {
1714 netdevFlags
= OVS_WIN_NETDEV_IFF_UP
;
1716 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_WIN_NETDEV_ATTR_IF_FLAGS
,
1719 return STATUS_INVALID_BUFFER_SIZE
;
1723 * XXX: add netdev_stats when we have the definition available in the
1727 nlMsg
= (PNL_MSG_HDR
)NlBufAt(&nlBuffer
, 0, 0);
1728 nlMsg
->nlmsgLen
= NlBufSize(&nlBuffer
);
1730 return STATUS_SUCCESS
;
1733 static __inline VOID
1734 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext
, ULONG sleepMicroSec
)
1736 while ((!switchContext
->isActivated
) &&
1737 (!switchContext
->isActivateFailed
)) {
1738 /* Wait for the switch to be active and
1739 * the list of ports in OVS to be initialized. */
1740 NdisMSleep(sleepMicroSec
);
1745 OvsCreateMsgFromVport(POVS_VPORT_ENTRY vport
,
1752 OVS_VPORT_FULL_STATS vportStats
;
1756 NlBufInit(&nlBuffer
, outBuffer
, outBufLen
);
1758 ok
= NlFillOvsMsg(&nlBuffer
, msgIn
->nlMsg
.nlmsgType
, NLM_F_MULTI
,
1759 msgIn
->nlMsg
.nlmsgSeq
, msgIn
->nlMsg
.nlmsgPid
,
1760 msgIn
->genlMsg
.cmd
, msgIn
->genlMsg
.version
,
1763 return STATUS_INVALID_BUFFER_SIZE
;
1766 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_VPORT_ATTR_PORT_NO
, vport
->portNo
);
1768 return STATUS_INVALID_BUFFER_SIZE
;
1771 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_VPORT_ATTR_TYPE
, vport
->ovsType
);
1773 return STATUS_INVALID_BUFFER_SIZE
;
1776 ok
= NlMsgPutTailString(&nlBuffer
, OVS_VPORT_ATTR_NAME
, vport
->ovsName
);
1778 return STATUS_INVALID_BUFFER_SIZE
;
1782 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1783 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1784 * it means we have an array of pids, instead of a single pid.
1785 * ATM we assume we have one pid only.
1788 ok
= NlMsgPutTailU32(&nlBuffer
, OVS_VPORT_ATTR_UPCALL_PID
,
1791 return STATUS_INVALID_BUFFER_SIZE
;
1795 vportStats
.rxPackets
= vport
->stats
.rxPackets
;
1796 vportStats
.rxBytes
= vport
->stats
.rxBytes
;
1797 vportStats
.txPackets
= vport
->stats
.txPackets
;
1798 vportStats
.txBytes
= vport
->stats
.txBytes
;
1799 vportStats
.rxErrors
= vport
->errStats
.rxErrors
;
1800 vportStats
.txErrors
= vport
->errStats
.txErrors
;
1801 vportStats
.rxDropped
= vport
->errStats
.rxDropped
;
1802 vportStats
.txDropped
= vport
->errStats
.txDropped
;
1804 ok
= NlMsgPutTailUnspec(&nlBuffer
, OVS_VPORT_ATTR_STATS
,
1806 sizeof(OVS_VPORT_FULL_STATS
));
1808 return STATUS_INVALID_BUFFER_SIZE
;
1812 * XXX: when vxlan udp dest port becomes configurable, we will also need
1813 * to add vport options
1816 nlMsg
= (PNL_MSG_HDR
)NlBufAt(&nlBuffer
, 0, 0);
1817 nlMsg
->nlmsgLen
= NlBufSize(&nlBuffer
);
1819 return STATUS_SUCCESS
;
1823 OvsGetVportDumpNext(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
1827 POVS_OPEN_INSTANCE instance
=
1828 (POVS_OPEN_INSTANCE
)usrParamsCtx
->ovsInstance
;
1829 LOCK_STATE_EX lockState
;
1830 UINT32 i
= OVS_MAX_VPORT_ARRAY_SIZE
;
1833 * XXX: this function shares some code with other dump command(s).
1834 * In the future, we will need to refactor the dump functions
1837 ASSERT(usrParamsCtx
->devOp
== OVS_READ_DEV_OP
);
1839 if (instance
->dumpState
.ovsMsg
== NULL
) {
1841 return STATUS_INVALID_DEVICE_STATE
;
1844 /* Output buffer has been validated while validating read dev op. */
1845 ASSERT(usrParamsCtx
->outputBuffer
!= NULL
);
1847 msgIn
= instance
->dumpState
.ovsMsg
;
1850 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1851 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1852 * it means we have an array of pids, instead of a single pid.
1853 * ATM we assume we have one pid only.
1855 NdisAcquireRWLockRead(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
1857 if (gOvsSwitchContext
->numHvVports
> 0 ||
1858 gOvsSwitchContext
->numNonHvVports
> 0) {
1859 /* inBucket: the bucket, used for lookup */
1860 UINT32 inBucket
= instance
->dumpState
.index
[0];
1861 /* inIndex: index within the given bucket, used for lookup */
1862 UINT32 inIndex
= instance
->dumpState
.index
[1];
1863 /* the bucket to be used for the next dump operation */
1864 UINT32 outBucket
= 0;
1865 /* the index within the outBucket to be used for the next dump */
1866 UINT32 outIndex
= 0;
1868 for (i
= inBucket
; i
< OVS_MAX_VPORT_ARRAY_SIZE
; i
++) {
1869 PLIST_ENTRY head
, link
;
1870 head
= &(gOvsSwitchContext
->portNoHashArray
[i
]);
1871 POVS_VPORT_ENTRY vport
= NULL
;
1874 LIST_FORALL(head
, link
) {
1877 * if one or more dumps were previously done on this same bucket,
1878 * inIndex will be > 0, so we'll need to reply with the
1879 * inIndex + 1 vport from the bucket.
1881 if (outIndex
>= inIndex
) {
1882 vport
= CONTAINING_RECORD(link
, OVS_VPORT_ENTRY
, portNoLink
);
1884 ASSERT(vport
->portNo
!= OVS_DPPORT_NUMBER_INVALID
);
1885 OvsCreateMsgFromVport(vport
, msgIn
,
1886 usrParamsCtx
->outputBuffer
,
1887 usrParamsCtx
->outputLength
,
1888 gOvsSwitchContext
->dpNo
);
1901 * if no vport was found above, check the next bucket, beginning
1902 * with the first (i.e. index 0) elem from within that bucket
1909 /* XXX: what about NLMSG_DONE (as msg type)? */
1910 instance
->dumpState
.index
[0] = outBucket
;
1911 instance
->dumpState
.index
[1] = outIndex
;
1914 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1916 /* if i < OVS_MAX_VPORT_ARRAY_SIZE => vport was found */
1917 if (i
< OVS_MAX_VPORT_ARRAY_SIZE
) {
1918 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
1919 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
1922 * if i >= OVS_MAX_VPORT_ARRAY_SIZE => vport was not found =>
1926 /* Free up the dump state, since there's no more data to continue. */
1927 FreeUserDumpState(instance
);
1930 return STATUS_SUCCESS
;
1934 OvsGetVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
1937 NTSTATUS status
= STATUS_SUCCESS
;
1938 LOCK_STATE_EX lockState
;
1940 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
1941 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
1942 POVS_VPORT_ENTRY vport
= NULL
;
1943 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
1944 PCHAR portName
= NULL
;
1945 UINT32 portNameLen
= 0;
1946 UINT32 portNumber
= OVS_DPPORT_NUMBER_INVALID
;
1948 static const NL_POLICY ovsVportPolicy
[] = {
1949 [OVS_VPORT_ATTR_PORT_NO
] = { .type
= NL_A_U32
, .optional
= TRUE
},
1950 [OVS_VPORT_ATTR_NAME
] = { .type
= NL_A_STRING
,
1955 PNL_ATTR vportAttrs
[ARRAY_SIZE(ovsVportPolicy
)];
1957 /* input buffer has been validated while validating write dev op. */
1958 ASSERT(usrParamsCtx
->inputBuffer
!= NULL
);
1960 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
1961 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
1962 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
1963 ovsVportPolicy
, vportAttrs
, ARRAY_SIZE(vportAttrs
))) {
1964 return STATUS_INVALID_PARAMETER
;
1967 /* Output buffer has been validated while validating transact dev op. */
1968 ASSERT(msgOut
!= NULL
&& usrParamsCtx
->outputLength
>= sizeof *msgOut
);
1970 NdisAcquireRWLockRead(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
1971 if (vportAttrs
[OVS_VPORT_ATTR_NAME
] != NULL
) {
1972 portName
= NlAttrGet(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
1973 portNameLen
= NlAttrGetSize(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
1975 /* the port name is expected to be null-terminated */
1976 ASSERT(portName
[portNameLen
- 1] == '\0');
1978 vport
= OvsFindVportByOvsName(gOvsSwitchContext
, portName
);
1979 } else if (vportAttrs
[OVS_VPORT_ATTR_PORT_NO
] != NULL
) {
1980 portNumber
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_PORT_NO
]);
1982 vport
= OvsFindVportByPortNo(gOvsSwitchContext
, portNumber
);
1984 nlError
= NL_ERROR_INVAL
;
1985 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1990 nlError
= NL_ERROR_NODEV
;
1991 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
1995 status
= OvsCreateMsgFromVport(vport
, msgIn
, usrParamsCtx
->outputBuffer
,
1996 usrParamsCtx
->outputLength
,
1997 gOvsSwitchContext
->dpNo
);
1998 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
2000 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2003 if (nlError
!= NL_ERROR_SUCCESS
) {
2004 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
2005 usrParamsCtx
->outputBuffer
;
2007 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2008 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
2011 return STATUS_SUCCESS
;
2015 * --------------------------------------------------------------------------
2016 * Command Handler for 'OVS_VPORT_CMD_GET'.
2018 * The function handles the initial call to setup the dump state, as well as
2019 * subsequent calls to continue dumping data.
2020 * --------------------------------------------------------------------------
2023 OvsGetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
2028 switch (usrParamsCtx
->devOp
) {
2029 case OVS_WRITE_DEV_OP
:
2030 return OvsSetupDumpStart(usrParamsCtx
);
2032 case OVS_READ_DEV_OP
:
2033 return OvsGetVportDumpNext(usrParamsCtx
, replyLen
);
2035 case OVS_TRANSACTION_DEV_OP
:
2036 return OvsGetVport(usrParamsCtx
, replyLen
);
2039 return STATUS_INVALID_DEVICE_REQUEST
;
2045 OvsComputeVportNo(POVS_SWITCH_CONTEXT switchContext
)
2047 /* we are not allowed to create the port OVS_DPPORT_NUMBER_LOCAL */
2048 for (ULONG i
= OVS_DPPORT_NUMBER_LOCAL
+ 1; i
< MAXUINT16
; ++i
) {
2049 POVS_VPORT_ENTRY vport
;
2051 vport
= OvsFindVportByPortNo(switchContext
, i
);
2057 return OVS_DPPORT_NUMBER_INVALID
;
2061 * --------------------------------------------------------------------------
2062 * Command Handler for 'OVS_VPORT_CMD_NEW'.
2063 * --------------------------------------------------------------------------
2066 OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
2069 NDIS_STATUS status
= STATUS_SUCCESS
;
2070 LOCK_STATE_EX lockState
;
2072 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
2073 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
2074 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
2075 POVS_VPORT_ENTRY vport
= NULL
;
2079 BOOLEAN isBridgeInternal
= FALSE
;
2080 BOOLEAN vportAllocated
= FALSE
, vportInitialized
= FALSE
;
2081 BOOLEAN addInternalPortAsNetdev
= FALSE
;
2083 static const NL_POLICY ovsVportPolicy
[] = {
2084 [OVS_VPORT_ATTR_PORT_NO
] = { .type
= NL_A_U32
, .optional
= TRUE
},
2085 [OVS_VPORT_ATTR_TYPE
] = { .type
= NL_A_U32
, .optional
= FALSE
},
2086 [OVS_VPORT_ATTR_NAME
] = { .type
= NL_A_STRING
, .maxLen
= IFNAMSIZ
,
2088 [OVS_VPORT_ATTR_UPCALL_PID
] = { .type
= NL_A_UNSPEC
,
2089 .optional
= FALSE
},
2090 [OVS_VPORT_ATTR_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= TRUE
},
2093 PNL_ATTR vportAttrs
[ARRAY_SIZE(ovsVportPolicy
)];
2095 /* input buffer has been validated while validating write dev op. */
2096 ASSERT(usrParamsCtx
->inputBuffer
!= NULL
);
2098 /* Output buffer has been validated while validating transact dev op. */
2099 ASSERT(msgOut
!= NULL
&& usrParamsCtx
->outputLength
>= sizeof *msgOut
);
2101 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
2102 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
2103 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
2104 ovsVportPolicy
, vportAttrs
, ARRAY_SIZE(vportAttrs
))) {
2105 return STATUS_INVALID_PARAMETER
;
2108 portName
= NlAttrGet(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2109 portNameLen
= NlAttrGetSize(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2110 portType
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_TYPE
]);
2112 /* we are expecting null terminated strings to be passed */
2113 ASSERT(portName
[portNameLen
- 1] == '\0');
2115 NdisAcquireRWLockWrite(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
2117 vport
= OvsFindVportByOvsName(gOvsSwitchContext
, portName
);
2119 nlError
= NL_ERROR_EXIST
;
2123 if (portName
&& portType
== OVS_VPORT_TYPE_NETDEV
&&
2124 !strcmp(OVS_DPPORT_INTERNAL_NAME_A
, portName
)) {
2125 addInternalPortAsNetdev
= TRUE
;
2128 if (portName
&& portType
== OVS_VPORT_TYPE_INTERNAL
&&
2129 strcmp(OVS_DPPORT_INTERNAL_NAME_A
, portName
)) {
2130 isBridgeInternal
= TRUE
;
2133 if (portType
== OVS_VPORT_TYPE_INTERNAL
&& !isBridgeInternal
) {
2134 vport
= gOvsSwitchContext
->internalVport
;
2135 } else if (portType
== OVS_VPORT_TYPE_NETDEV
) {
2136 /* External ports can also be looked up like VIF ports. */
2137 vport
= OvsFindVportByHvNameA(gOvsSwitchContext
, portName
);
2139 ASSERT(OvsIsTunnelVportType(portType
) ||
2140 (portType
== OVS_VPORT_TYPE_INTERNAL
&& isBridgeInternal
));
2142 vport
= (POVS_VPORT_ENTRY
)OvsAllocateVport();
2143 if (vport
== NULL
) {
2144 nlError
= NL_ERROR_NOMEM
;
2147 vportAllocated
= TRUE
;
2149 if (OvsIsTunnelVportType(portType
)) {
2150 UINT16 udpPortDest
= VXLAN_UDP_PORT
;
2151 PNL_ATTR attr
= NlAttrFindNested(vportAttrs
[OVS_VPORT_ATTR_OPTIONS
],
2152 OVS_TUNNEL_ATTR_DST_PORT
);
2154 udpPortDest
= NlAttrGetU16(attr
);
2157 status
= OvsInitTunnelVport(usrParamsCtx
,
2162 nlError
= NlMapStatusToNlErr(status
);
2164 OvsInitBridgeInternalVport(vport
);
2167 vportInitialized
= TRUE
;
2169 if (nlError
== NL_ERROR_SUCCESS
) {
2170 vport
->ovsState
= OVS_STATE_CONNECTED
;
2171 vport
->nicState
= NdisSwitchNicStateConnected
;
2174 * Allow the vport to be deleted, because there is no
2175 * corresponding hyper-v switch part.
2177 vport
->isPresentOnHv
= TRUE
;
2184 nlError
= NL_ERROR_INVAL
;
2187 if (vport
->portNo
!= OVS_DPPORT_NUMBER_INVALID
) {
2188 nlError
= NL_ERROR_EXIST
;
2192 /* Initialize the vport with OVS specific properties. */
2193 if (addInternalPortAsNetdev
!= TRUE
) {
2194 vport
->ovsType
= portType
;
2196 if (vportAttrs
[OVS_VPORT_ATTR_PORT_NO
] != NULL
) {
2198 * XXX: when we implement the limit for ovs port number to be
2199 * MAXUINT16, we'll need to check the port number received from the
2202 vport
->portNo
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_PORT_NO
]);
2204 vport
->portNo
= OvsComputeVportNo(gOvsSwitchContext
);
2205 if (vport
->portNo
== OVS_DPPORT_NUMBER_INVALID
) {
2206 nlError
= NL_ERROR_NOMEM
;
2211 /* The ovs port name must be uninitialized. */
2212 ASSERT(vport
->ovsName
[0] == '\0');
2213 ASSERT(portNameLen
<= OVS_MAX_PORT_NAME_LENGTH
);
2215 RtlCopyMemory(vport
->ovsName
, portName
, portNameLen
);
2216 /* if we don't have options, then vport->portOptions will be NULL */
2217 vport
->portOptions
= vportAttrs
[OVS_VPORT_ATTR_OPTIONS
];
2220 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2221 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2222 * it means we have an array of pids, instead of a single pid.
2223 * ATM we assume we have one pid only.
2225 vport
->upcallPid
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_UPCALL_PID
]);
2227 status
= InitOvsVportCommon(gOvsSwitchContext
, vport
);
2228 ASSERT(status
== STATUS_SUCCESS
);
2230 status
= OvsCreateMsgFromVport(vport
, msgIn
, usrParamsCtx
->outputBuffer
,
2231 usrParamsCtx
->outputLength
,
2232 gOvsSwitchContext
->dpNo
);
2234 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2237 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
2239 if ((nlError
!= NL_ERROR_SUCCESS
) && (nlError
!= NL_ERROR_PENDING
)) {
2240 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
2241 usrParamsCtx
->outputBuffer
;
2243 if (vport
&& vportAllocated
== TRUE
) {
2244 if (vportInitialized
== TRUE
) {
2245 if (OvsIsTunnelVportType(portType
)) {
2246 OvsCleanupVxlanTunnel(NULL
, vport
, NULL
, NULL
);
2249 OvsFreeMemoryWithTag(vport
, OVS_VPORT_POOL_TAG
);
2252 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2253 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
2256 return (status
== STATUS_PENDING
) ? STATUS_PENDING
: STATUS_SUCCESS
;
2261 * --------------------------------------------------------------------------
2262 * Command Handler for 'OVS_VPORT_CMD_SET'.
2263 * --------------------------------------------------------------------------
2266 OvsSetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
2269 NDIS_STATUS status
= STATUS_SUCCESS
;
2270 LOCK_STATE_EX lockState
;
2272 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
2273 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
2274 POVS_VPORT_ENTRY vport
= NULL
;
2275 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
2277 static const NL_POLICY ovsVportPolicy
[] = {
2278 [OVS_VPORT_ATTR_PORT_NO
] = { .type
= NL_A_U32
, .optional
= TRUE
},
2279 [OVS_VPORT_ATTR_TYPE
] = { .type
= NL_A_U32
, .optional
= TRUE
},
2280 [OVS_VPORT_ATTR_NAME
] = { .type
= NL_A_STRING
, .maxLen
= IFNAMSIZ
,
2282 [OVS_VPORT_ATTR_UPCALL_PID
] = { .type
= NL_A_UNSPEC
,
2284 [OVS_VPORT_ATTR_STATS
] = { .type
= NL_A_UNSPEC
,
2285 .minLen
= sizeof(OVS_VPORT_FULL_STATS
),
2286 .maxLen
= sizeof(OVS_VPORT_FULL_STATS
),
2288 [OVS_VPORT_ATTR_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= TRUE
},
2290 PNL_ATTR vportAttrs
[ARRAY_SIZE(ovsVportPolicy
)];
2292 ASSERT(usrParamsCtx
->inputBuffer
!= NULL
);
2294 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
2295 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
2296 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
2297 ovsVportPolicy
, vportAttrs
, ARRAY_SIZE(vportAttrs
))) {
2298 return STATUS_INVALID_PARAMETER
;
2301 /* Output buffer has been validated while validating transact dev op. */
2302 ASSERT(msgOut
!= NULL
&& usrParamsCtx
->outputLength
>= sizeof *msgOut
);
2304 NdisAcquireRWLockWrite(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
2305 if (vportAttrs
[OVS_VPORT_ATTR_NAME
] != NULL
) {
2306 PSTR portName
= NlAttrGet(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2308 UINT32 portNameLen
= NlAttrGetSize(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2310 /* the port name is expected to be null-terminated */
2311 ASSERT(portName
[portNameLen
- 1] == '\0');
2313 vport
= OvsFindVportByOvsName(gOvsSwitchContext
, portName
);
2314 } else if (vportAttrs
[OVS_VPORT_ATTR_PORT_NO
] != NULL
) {
2315 vport
= OvsFindVportByPortNo(gOvsSwitchContext
,
2316 NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_PORT_NO
]));
2320 nlError
= NL_ERROR_NODEV
;
2325 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2326 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2327 * it means we have an array of pids, instead of a single pid.
2328 * Currently, we support only one pid.
2330 if (vportAttrs
[OVS_VPORT_ATTR_UPCALL_PID
]) {
2331 vport
->upcallPid
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_UPCALL_PID
]);
2334 if (vportAttrs
[OVS_VPORT_ATTR_TYPE
]) {
2335 OVS_VPORT_TYPE type
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_TYPE
]);
2336 if (type
!= vport
->ovsType
) {
2337 nlError
= NL_ERROR_INVAL
;
2342 if (vportAttrs
[OVS_VPORT_ATTR_OPTIONS
]) {
2343 OVS_LOG_ERROR("Vport options not supported");
2344 nlError
= NL_ERROR_NOTSUPP
;
2348 status
= OvsCreateMsgFromVport(vport
, msgIn
, usrParamsCtx
->outputBuffer
,
2349 usrParamsCtx
->outputLength
,
2350 gOvsSwitchContext
->dpNo
);
2352 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2355 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
2357 if (nlError
!= NL_ERROR_SUCCESS
) {
2358 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
2359 usrParamsCtx
->outputBuffer
;
2361 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2362 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
2365 return STATUS_SUCCESS
;
2369 * --------------------------------------------------------------------------
2370 * Command Handler for 'OVS_VPORT_CMD_DEL'.
2371 * --------------------------------------------------------------------------
2374 OvsDeleteVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
2377 NDIS_STATUS status
= STATUS_SUCCESS
;
2378 LOCK_STATE_EX lockState
;
2380 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
2381 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
2382 POVS_VPORT_ENTRY vport
= NULL
;
2383 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
2384 PSTR portName
= NULL
;
2385 UINT32 portNameLen
= 0;
2387 static const NL_POLICY ovsVportPolicy
[] = {
2388 [OVS_VPORT_ATTR_PORT_NO
] = { .type
= NL_A_U32
, .optional
= TRUE
},
2389 [OVS_VPORT_ATTR_NAME
] = { .type
= NL_A_STRING
, .maxLen
= IFNAMSIZ
,
2392 PNL_ATTR vportAttrs
[ARRAY_SIZE(ovsVportPolicy
)];
2394 ASSERT(usrParamsCtx
->inputBuffer
!= NULL
);
2396 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
2397 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
2398 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
2399 ovsVportPolicy
, vportAttrs
, ARRAY_SIZE(vportAttrs
))) {
2400 return STATUS_INVALID_PARAMETER
;
2403 /* Output buffer has been validated while validating transact dev op. */
2404 ASSERT(msgOut
!= NULL
&& usrParamsCtx
->outputLength
>= sizeof *msgOut
);
2406 NdisAcquireRWLockWrite(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
2407 if (vportAttrs
[OVS_VPORT_ATTR_NAME
] != NULL
) {
2408 portName
= NlAttrGet(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2409 portNameLen
= NlAttrGetSize(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2411 /* the port name is expected to be null-terminated */
2412 ASSERT(portName
[portNameLen
- 1] == '\0');
2414 vport
= OvsFindVportByOvsName(gOvsSwitchContext
, portName
);
2416 else if (vportAttrs
[OVS_VPORT_ATTR_PORT_NO
] != NULL
) {
2417 vport
= OvsFindVportByPortNo(gOvsSwitchContext
,
2418 NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_PORT_NO
]));
2422 nlError
= NL_ERROR_NODEV
;
2426 status
= OvsCreateMsgFromVport(vport
, msgIn
, usrParamsCtx
->outputBuffer
,
2427 usrParamsCtx
->outputLength
,
2428 gOvsSwitchContext
->dpNo
);
2430 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2433 * Mark the port as deleted from OVS userspace. If the port does not exist
2434 * on the Hyper-V switch, it gets deallocated. Otherwise, it stays.
2436 status
= OvsRemoveAndDeleteVport(usrParamsCtx
,
2442 nlError
= NlMapStatusToNlErr(status
);
2446 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
2448 if ((nlError
!= NL_ERROR_SUCCESS
) && (nlError
!= NL_ERROR_PENDING
)) {
2449 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
2450 usrParamsCtx
->outputBuffer
;
2452 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2453 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
2456 return (status
== STATUS_PENDING
) ? STATUS_PENDING
: STATUS_SUCCESS
;
2460 OvsTunnelVportPendingUninit(PVOID context
,
2464 POVS_TUNFLT_INIT_CONTEXT tunnelContext
=
2465 (POVS_TUNFLT_INIT_CONTEXT
) context
;
2466 POVS_SWITCH_CONTEXT switchContext
= tunnelContext
->switchContext
;
2467 POVS_VPORT_ENTRY vport
= tunnelContext
->vport
;
2468 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)tunnelContext
->inputBuffer
;
2469 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)tunnelContext
->outputBuffer
;
2470 NL_ERROR nlError
= NlMapStatusToNlErr(status
);
2471 LOCK_STATE_EX lockState
;
2473 NdisAcquireRWLockWrite(switchContext
->dispatchLock
, &lockState
, 0);
2475 if (msgIn
&& msgOut
) {
2476 /* Check the received status to reply to the caller. */
2477 if (STATUS_SUCCESS
== status
) {
2478 OvsCreateMsgFromVport(vport
,
2481 tunnelContext
->outputLength
,
2482 switchContext
->dpNo
);
2484 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2486 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)msgOut
;
2488 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2489 *replyLen
= msgError
->nlMsg
.nlmsgLen
;
2493 OvsCleanupVportCommon(switchContext
,
2495 tunnelContext
->hvSwitchPort
,
2496 tunnelContext
->hvDelete
,
2497 tunnelContext
->ovsDelete
);
2499 NdisReleaseRWLock(switchContext
->dispatchLock
, &lockState
);
2503 OvsTunnelVportPendingInit(PVOID context
,
2507 POVS_TUNFLT_INIT_CONTEXT tunnelContext
=
2508 (POVS_TUNFLT_INIT_CONTEXT
) context
;
2509 POVS_VPORT_ENTRY vport
= tunnelContext
->vport
;
2510 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)tunnelContext
->inputBuffer
;
2511 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)tunnelContext
->outputBuffer
;
2513 ULONG portNameLen
= 0;
2514 UINT32 portType
= 0;
2515 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
2516 BOOLEAN error
= TRUE
;
2519 if (!NT_SUCCESS(status
)) {
2520 nlError
= NlMapStatusToNlErr(status
);
2524 static const NL_POLICY ovsVportPolicy
[] = {
2525 [OVS_VPORT_ATTR_PORT_NO
] = { .type
= NL_A_U32
, .optional
= TRUE
},
2526 [OVS_VPORT_ATTR_TYPE
] = { .type
= NL_A_U32
, .optional
= FALSE
},
2527 [OVS_VPORT_ATTR_NAME
] = { .type
= NL_A_STRING
, .maxLen
= IFNAMSIZ
,
2528 .optional
= FALSE
},
2529 [OVS_VPORT_ATTR_UPCALL_PID
] = { .type
= NL_A_UNSPEC
,
2530 .optional
= FALSE
},
2531 [OVS_VPORT_ATTR_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= TRUE
},
2534 PNL_ATTR vportAttrs
[ARRAY_SIZE(ovsVportPolicy
)];
2536 /* input buffer has been validated while validating write dev op. */
2537 ASSERT(msgIn
!= NULL
);
2539 /* Output buffer has been validated while validating transact dev op. */
2540 ASSERT(msgOut
!= NULL
&& tunnelContext
->outputLength
>= sizeof *msgOut
);
2542 if (!NlAttrParse((PNL_MSG_HDR
)msgIn
,
2543 NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
,
2544 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
),
2545 ovsVportPolicy
, vportAttrs
, ARRAY_SIZE(vportAttrs
))) {
2546 nlError
= NL_ERROR_INVAL
;
2550 portName
= NlAttrGet(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2551 portNameLen
= NlAttrGetSize(vportAttrs
[OVS_VPORT_ATTR_NAME
]);
2552 portType
= NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_TYPE
]);
2554 if (vport
->portNo
!= OVS_DPPORT_NUMBER_INVALID
) {
2555 nlError
= NL_ERROR_EXIST
;
2559 vport
->ovsState
= OVS_STATE_CONNECTED
;
2560 vport
->nicState
= NdisSwitchNicStateConnected
;
2563 * Allow the vport to be deleted, because there is no
2564 * corresponding hyper-v switch part.
2566 vport
->isPresentOnHv
= TRUE
;
2568 if (vportAttrs
[OVS_VPORT_ATTR_PORT_NO
] != NULL
) {
2570 * XXX: when we implement the limit for OVS port number to be
2571 * MAXUINT16, we'll need to check the port number received from the
2575 NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_PORT_NO
]);
2578 OvsComputeVportNo(gOvsSwitchContext
);
2579 if (vport
->portNo
== OVS_DPPORT_NUMBER_INVALID
) {
2580 nlError
= NL_ERROR_NOMEM
;
2585 /* The ovs port name must be uninitialized. */
2586 ASSERT(vport
->ovsName
[0] == '\0');
2587 ASSERT(portNameLen
<= OVS_MAX_PORT_NAME_LENGTH
);
2589 RtlCopyMemory(vport
->ovsName
, portName
, portNameLen
);
2590 /* if we don't have options, then vport->portOptions will be NULL */
2591 vport
->portOptions
= vportAttrs
[OVS_VPORT_ATTR_OPTIONS
];
2594 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2595 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2596 * it means we have an array of pids, instead of a single pid.
2597 * ATM we assume we have one pid only.
2600 NlAttrGetU32(vportAttrs
[OVS_VPORT_ATTR_UPCALL_PID
]);
2602 status
= InitOvsVportCommon(gOvsSwitchContext
, vport
);
2603 ASSERT(status
== STATUS_SUCCESS
);
2605 OvsCreateMsgFromVport(vport
,
2608 tunnelContext
->outputLength
,
2609 gOvsSwitchContext
->dpNo
);
2611 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
2617 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
) msgOut
;
2619 OvsCleanupVxlanTunnel(NULL
, vport
, NULL
, NULL
);
2620 OvsFreeMemory(vport
);
2622 NlBuildErrorMsg(msgIn
, msgError
, nlError
);
2623 *replyLen
= msgError
->nlMsg
.nlmsgLen
;