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.
34 #define OVS_DBG_MOD OVS_DBG_VPORT
37 #define VPORT_NIC_ENTER(_nic) \
38 OVS_LOG_TRACE("Enter: PortId: %x, NicIndex: %d", _nic->PortId, \
41 #define VPORT_NIC_EXIT(_nic) \
42 OVS_LOG_TRACE("Exit: PortId: %x, NicIndex: %d", _nic->PortId, \
45 #define VPORT_PORT_ENTER(_port) \
46 OVS_LOG_TRACE("Enter: PortId: %x", _port->PortId)
48 #define VPORT_PORT_EXIT(_port) \
49 OVS_LOG_TRACE("Exit: PortId: %x", _port->PortId)
51 #define OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC 100
53 /* Context structure used to pass back and forth information to the tunnel
55 typedef struct _OVS_TUNFLT_INIT_CONTEXT {
56 POVS_SWITCH_CONTEXT switchContext;
60 POVS_VPORT_ENTRY vport;
64 } OVS_TUNFLT_INIT_CONTEXT, *POVS_TUNFLT_INIT_CONTEXT;
67 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
69 static VOID OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
70 PNDIS_SWITCH_PORT_PARAMETERS portParam);
71 static VOID OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
72 POVS_VPORT_ENTRY vport, PNDIS_SWITCH_NIC_PARAMETERS nicParam);
73 static VOID OvsCopyPortParamsFromVport(POVS_VPORT_ENTRY vport,
74 PNDIS_SWITCH_PORT_PARAMETERS portParam);
75 static __inline VOID OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext,
77 static NTSTATUS OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
78 POVS_VPORT_EXT_INFO extInfo);
79 static NTSTATUS CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
84 static POVS_VPORT_ENTRY OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext,
85 PWSTR wsName, SIZE_T wstrSize);
86 static VOID UpdateSwitchCtxWithVport(POVS_SWITCH_CONTEXT switchContext,
87 POVS_VPORT_ENTRY vport, BOOLEAN newPort);
88 static NTSTATUS OvsRemoveTunnelVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
89 POVS_SWITCH_CONTEXT switchContext,
90 POVS_VPORT_ENTRY vport,
93 static VOID OvsTunnelVportPendingInit(PVOID context,
96 static VOID OvsTunnelVportPendingRemove(PVOID context,
99 static NTSTATUS GetNICAlias(GUID *netCfgInstanceId,
100 IF_COUNTED_STRING *portFriendlyName);
103 * --------------------------------------------------------------------------
104 * Creates a Vport entry for a Hyper-V switch port. 'nicIndex' is typically
105 * associated with a NIC than a port. We use it here for the special case
106 * where we need to create a Vport for an external NIC with NicIndex > 0.
107 * --------------------------------------------------------------------------
110 HvCreatePort(POVS_SWITCH_CONTEXT switchContext,
111 PNDIS_SWITCH_PORT_PARAMETERS portParam,
112 NDIS_SWITCH_NIC_INDEX nicIndex)
114 POVS_VPORT_ENTRY vport;
115 LOCK_STATE_EX lockState;
116 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
117 BOOLEAN newPort = FALSE;
119 VPORT_PORT_ENTER(portParam);
121 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
122 /* Lookup by port ID. */
123 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
124 portParam->PortId, nicIndex);
126 OVS_LOG_ERROR("Port add failed due to duplicate port name, "
127 "port Id: %u", portParam->PortId);
128 status = STATUS_DATA_NOT_ACCEPTED;
129 goto create_port_done;
133 * Lookup by port name to see if this port with this name had been added
134 * (and deleted) previously.
136 vport = OvsFindVportByHvNameW(gOvsSwitchContext,
137 portParam->PortFriendlyName.String,
138 portParam->PortFriendlyName.Length);
139 if (vport && vport->isAbsentOnHv == FALSE) {
140 OVS_LOG_ERROR("Port add failed since a port already exists on "
141 "the specified port Id: %u, ovsName: %s",
142 portParam->PortId, vport->ovsName);
143 status = STATUS_DATA_NOT_ACCEPTED;
144 goto create_port_done;
148 ASSERT(vport->isAbsentOnHv);
149 ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
152 * It should be possible to simply just mark this port as "not deleted"
153 * given that the port Id and the name are the same and also provided
154 * that the other properties that we cache have not changed.
156 if (vport->portType != portParam->PortType) {
157 OVS_LOG_INFO("Port add failed due to PortType change, port Id: %u"
158 " old: %u, new: %u", portParam->PortId,
159 vport->portType, portParam->PortType);
160 status = STATUS_DATA_NOT_ACCEPTED;
161 goto create_port_done;
163 vport->isAbsentOnHv = FALSE;
165 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
167 status = NDIS_STATUS_RESOURCES;
168 goto create_port_done;
172 OvsInitVportWithPortParam(vport, portParam);
173 vport->nicIndex = nicIndex;
174 UpdateSwitchCtxWithVport(switchContext, vport, newPort);
177 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
178 VPORT_PORT_EXIT(portParam);
184 * --------------------------------------------------------------------------
185 * Function to process updates to a port on the Hyper-Vs witch.
186 * --------------------------------------------------------------------------
189 HvUpdatePort(POVS_SWITCH_CONTEXT switchContext,
190 PNDIS_SWITCH_PORT_PARAMETERS portParam)
192 POVS_VPORT_ENTRY vport;
193 LOCK_STATE_EX lockState;
194 OVS_VPORT_STATE ovsState;
195 NDIS_SWITCH_NIC_STATE nicState;
197 VPORT_PORT_ENTER(portParam);
199 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
200 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
201 portParam->PortId, 0);
203 * Update properties only for NETDEV ports for supprting PS script
206 goto update_port_done;
209 /* Store the nic and the OVS states as Nic Create won't be called */
210 ovsState = vport->ovsState;
211 nicState = vport->nicState;
214 * Currently only the port friendly name is being updated
215 * Make sure that no other properties are changed
217 ASSERT(portParam->PortId == vport->portId);
218 ASSERT(portParam->PortState == vport->portState);
219 ASSERT(portParam->PortType == vport->portType);
222 * Call the set parameters function the handle all properties
223 * change in a single place in case future version supports change of
226 OvsInitVportWithPortParam(vport, portParam);
227 /* Retore the nic and OVS states */
228 vport->nicState = nicState;
229 vport->ovsState = ovsState;
232 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
233 VPORT_PORT_EXIT(portParam);
235 /* Must always return success */
236 return NDIS_STATUS_SUCCESS;
241 * --------------------------------------------------------------------------
242 * Function to process teardown of a port on the Hyper-V switch.
243 * --------------------------------------------------------------------------
246 HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
247 PNDIS_SWITCH_PORT_PARAMETERS portParam)
249 POVS_VPORT_ENTRY vport;
250 LOCK_STATE_EX lockState;
252 VPORT_PORT_ENTER(portParam);
254 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
255 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
256 portParam->PortId, 0);
258 /* add assertion here */
259 vport->portState = NdisSwitchPortStateTeardown;
260 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
262 OVS_LOG_WARN("Vport not present.");
264 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
266 VPORT_PORT_EXIT(portParam);
270 * --------------------------------------------------------------------------
271 * Function to process deletion of a port on the Hyper-V switch.
272 * --------------------------------------------------------------------------
275 HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
276 PNDIS_SWITCH_PORT_PARAMETERS portParams)
278 POVS_VPORT_ENTRY vport;
279 LOCK_STATE_EX lockState;
281 VPORT_PORT_ENTER(portParams);
283 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
284 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
285 portParams->PortId, 0);
288 * XXX: we can only destroy and remove the port if its datapath port
289 * counterpart was deleted. If the datapath port counterpart is present,
290 * we only mark the vport for deletion, so that a netlink command vport
291 * delete will delete the vport.
294 OVS_EVENT_ENTRY event;
296 event.portNo = vport->portNo;
297 event.ovsType = vport->ovsType;
298 event.upcallPid = vport->upcallPid;
299 RtlCopyMemory(&event.ovsName, &vport->ovsName, sizeof event.ovsName);
300 event.type = OVS_EVENT_LINK_DOWN;
301 OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, FALSE);
302 OvsPostEvent(&event);
304 OVS_LOG_WARN("Vport not present.");
306 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
308 VPORT_PORT_EXIT(portParams);
313 * --------------------------------------------------------------------------
314 * Function to process addition of a NIC connection on the Hyper-V switch.
315 * XXX: Posting an event to DPIF is incorrect here. However, it might be useful
316 * to post an event to netdev-windows.c.
317 * --------------------------------------------------------------------------
320 HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
321 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
323 POVS_VPORT_ENTRY vport;
324 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
325 IF_COUNTED_STRING portFriendlyName = {0};
326 LOCK_STATE_EX lockState;
328 VPORT_NIC_ENTER(nicParam);
330 /* Wait for lists to be initialized. */
331 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
333 if (!switchContext->isActivated) {
334 OVS_LOG_WARN("Switch is not activated yet.");
335 /* Veto the creation of nic */
336 status = NDIS_STATUS_NOT_SUPPORTED;
340 if (OvsIsInternalNIC(nicParam->NicType) ||
341 OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
342 GetNICAlias(&nicParam->NetCfgInstanceId, &portFriendlyName);
345 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
347 * There can be one or more NICs for the external port. We create a vport
348 * structure for each such NIC, and each NIC inherits a lot of properties
349 * from the parent external port.
351 if (OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
352 NDIS_SWITCH_PORT_PARAMETERS portParam;
353 POVS_VPORT_ENTRY virtExtVport =
354 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
356 ASSERT(virtExtVport);
357 ASSERT(OvsFindVportByPortIdAndNicIndex(switchContext,
359 nicParam->NicIndex) == NULL);
360 OvsCopyPortParamsFromVport(virtExtVport, &portParam);
361 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
362 status = HvCreatePort(switchContext, &portParam,
364 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
365 if (status != NDIS_STATUS_SUCCESS) {
370 vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId,
373 OVS_LOG_ERROR("Create NIC without Switch Port,"
374 " PortId: %x, NicIndex: %d",
375 nicParam->PortId, nicParam->NicIndex);
376 status = NDIS_STATUS_INVALID_PARAMETER;
379 OvsInitVportWithNicParam(switchContext, vport, nicParam);
380 if (OvsIsInternalNIC(nicParam->NicType) ||
381 OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
382 RtlCopyMemory(&vport->portFriendlyName, &portFriendlyName,
383 sizeof portFriendlyName);
387 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
390 VPORT_NIC_EXIT(nicParam);
391 OVS_LOG_TRACE("Exit: status %8x.\n", status);
397 * --------------------------------------------------------------------------
398 * Function to process connection event of a NIC on the Hyper-V switch.
399 * --------------------------------------------------------------------------
402 HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
403 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
405 LOCK_STATE_EX lockState;
406 POVS_VPORT_ENTRY vport;
409 VPORT_NIC_ENTER(nicParam);
411 /* Wait for lists to be initialized. */
412 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
414 if (!switchContext->isActivated) {
415 OVS_LOG_WARN("Switch is not activated yet.");
419 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
420 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
425 OVS_LOG_WARN("Vport not present.");
426 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
431 vport->ovsState = OVS_STATE_CONNECTED;
432 vport->nicState = NdisSwitchNicStateConnected;
433 portNo = vport->portNo;
435 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
437 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
438 OvsInternalAdapterUp(&nicParam->NetCfgInstanceId);
442 VPORT_NIC_EXIT(nicParam);
447 * --------------------------------------------------------------------------
448 * Function to process updates to a NIC on the Hyper-V switch.
449 * --------------------------------------------------------------------------
452 HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
453 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
455 POVS_VPORT_ENTRY vport;
456 LOCK_STATE_EX lockState;
458 IF_COUNTED_STRING portFriendlyName = {0};
459 BOOLEAN nameChanged = FALSE;
460 BOOLEAN aliasLookup = FALSE;
462 VPORT_NIC_ENTER(nicParam);
464 /* Wait for lists to be initialized. */
465 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
467 if (!switchContext->isActivated) {
468 OVS_LOG_WARN("Switch is not activated yet.");
469 goto update_nic_done;
472 /* GetNICAlias() must be called outside of a lock. */
473 if (nicParam->NicType == NdisSwitchNicTypeInternal ||
474 OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
475 GetNICAlias(&nicParam->NetCfgInstanceId, &portFriendlyName);
479 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
480 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
484 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
485 OVS_LOG_WARN("Vport search failed.");
486 goto update_nic_done;
488 switch (nicParam->NicType) {
489 case NdisSwitchNicTypeExternal:
490 case NdisSwitchNicTypeInternal:
491 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
494 if (RtlCompareMemory(&vport->portFriendlyName,
495 &portFriendlyName, vport->portFriendlyName.Length) !=
496 vport->portFriendlyName.Length) {
497 RtlCopyMemory(&vport->portFriendlyName, &portFriendlyName,
498 sizeof portFriendlyName);
503 case NdisSwitchNicTypeSynthetic:
504 case NdisSwitchNicTypeEmulated:
505 if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
506 sizeof (vport->vmMacAddress))) {
507 event |= OVS_EVENT_MAC_CHANGE;
508 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
509 sizeof (vport->vmMacAddress));
515 if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
516 sizeof (vport->permMacAddress))) {
517 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
518 sizeof (vport->permMacAddress));
519 event |= OVS_EVENT_MAC_CHANGE;
521 if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
522 sizeof (vport->currMacAddress))) {
523 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
524 sizeof (vport->currMacAddress));
525 event |= OVS_EVENT_MAC_CHANGE;
528 if (vport->mtu != nicParam->MTU) {
529 vport->mtu = nicParam->MTU;
530 event |= OVS_EVENT_MTU_CHANGE;
532 vport->numaNodeId = nicParam->NumaNodeId;
535 OVS_EVENT_ENTRY event;
536 event.portNo = vport->portNo;
537 event.ovsType = vport->ovsType;
538 event.upcallPid = vport->upcallPid;
539 RtlCopyMemory(&event.ovsName, &vport->ovsName, sizeof event.ovsName);
540 event.type = OVS_EVENT_LINK_DOWN;
541 OvsRemoveAndDeleteVport(NULL, switchContext, vport, FALSE, TRUE);
542 OvsPostEvent(&event);
545 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
548 * XXX: Not sure what kind of event to post here. DPIF is not interested in
549 * changes to MAC address. Netdev-windows might be intrested, though.
550 * That said, if the name chagnes, not clear what kind of event to be
551 * posted. We might have to delete the vport, and have userspace recreate
556 VPORT_NIC_EXIT(nicParam);
560 * --------------------------------------------------------------------------
561 * Function to process disconnect event of a NIC on the Hyper-V switch.
562 * --------------------------------------------------------------------------
565 HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
566 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
568 POVS_VPORT_ENTRY vport;
569 LOCK_STATE_EX lockState;
570 BOOLEAN isInternalPort = FALSE;
571 OVS_EVENT_ENTRY event;
573 VPORT_NIC_ENTER(nicParam);
575 /* Wait for lists to be initialized. */
576 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
578 if (!switchContext->isActivated) {
579 OVS_LOG_WARN("Switch is not activated yet.");
583 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
584 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
589 OVS_LOG_WARN("Vport not present.");
590 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
594 vport->nicState = NdisSwitchNicStateDisconnected;
595 vport->ovsState = OVS_STATE_NIC_CREATED;
597 if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
598 isInternalPort = TRUE;
601 event.portNo = vport->portNo;
602 event.ovsType = vport->ovsType;
603 event.upcallPid = vport->upcallPid;
604 RtlCopyMemory(&event.ovsName, &vport->ovsName, sizeof event.ovsName);
605 event.type = OVS_EVENT_LINK_DOWN;
608 * Delete the port from the hash tables accessible to userspace. After this
609 * point, userspace should not be able to access this port.
611 if (OvsIsRealExternalVport(vport)) {
612 OvsRemoveAndDeleteVport(NULL, switchContext, vport, FALSE, TRUE);
613 OvsPostEvent(&event);
615 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
617 if (isInternalPort) {
618 OvsInternalAdapterDown();
622 VPORT_NIC_EXIT(nicParam);
626 * --------------------------------------------------------------------------
627 * Function to process delete event of a NIC on the Hyper-V switch.
628 * --------------------------------------------------------------------------
631 HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
632 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
634 LOCK_STATE_EX lockState;
635 POVS_VPORT_ENTRY vport;
637 VPORT_NIC_ENTER(nicParam);
638 /* Wait for lists to be initialized. */
639 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
641 if (!switchContext->isActivated) {
642 OVS_LOG_WARN("Switch is not activated yet.");
646 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
647 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
652 OVS_LOG_WARN("Vport not present.");
653 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
657 vport->nicState = NdisSwitchNicStateUnknown;
658 vport->ovsState = OVS_STATE_PORT_CREATED;
660 if (OvsIsRealExternalVport(vport)) {
661 /* This vport was created in HvCreateNic(). */
662 OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, FALSE);
665 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
668 VPORT_NIC_EXIT(nicParam);
672 * OVS Vport related functionality.
675 OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
678 POVS_VPORT_ENTRY vport;
679 PLIST_ENTRY head, link;
680 UINT32 hash = OvsJhashBytes((const VOID *)&portNo, sizeof(portNo),
682 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
683 LIST_FORALL(head, link) {
684 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
685 if (vport->portNo == portNo) {
694 OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext,
696 OVS_VPORT_TYPE ovsPortType)
698 POVS_VPORT_ENTRY vport;
699 PLIST_ENTRY head, link;
700 UINT32 hash = OvsJhashBytes((const VOID *)&dstPort, sizeof(dstPort),
702 head = &(switchContext->tunnelVportsArray[hash & OVS_VPORT_MASK]);
703 LIST_FORALL(head, link) {
704 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, tunnelVportLink);
705 if (GetPortFromPriv(vport) == dstPort &&
706 vport->ovsType == ovsPortType) {
714 OvsFindTunnelVportByPortType(POVS_SWITCH_CONTEXT switchContext,
715 OVS_VPORT_TYPE ovsPortType)
717 POVS_VPORT_ENTRY vport;
718 PLIST_ENTRY head, link;
720 UINT32 hash = OvsJhashBytes((const VOID *)&dstPort, sizeof(dstPort),
722 head = &(switchContext->tunnelVportsArray[hash & OVS_VPORT_MASK]);
723 LIST_FORALL(head, link) {
724 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, tunnelVportLink);
725 if (vport->ovsType == ovsPortType) {
733 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
736 POVS_VPORT_ENTRY vport;
737 PLIST_ENTRY head, link;
739 SIZE_T length = strlen(name) + 1;
741 hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
742 head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
744 LIST_FORALL(head, link) {
745 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
746 if (!strcmp(name, vport->ovsName)) {
754 /* OvsFindVportByHvName: "name" is assumed to be null-terminated */
756 OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext,
757 PWSTR wsName, SIZE_T wstrSize)
759 POVS_VPORT_ENTRY vport = NULL;
760 PLIST_ENTRY head, link;
763 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
764 head = &(switchContext->portIdHashArray[i]);
765 LIST_FORALL(head, link) {
766 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
769 * NOTE about portFriendlyName:
770 * If the string is NULL-terminated, the Length member does not
771 * include the terminating NULL character.
773 if (vport->portFriendlyName.Length == wstrSize &&
774 RtlEqualMemory(wsName, vport->portFriendlyName.String,
775 vport->portFriendlyName.Length)) {
784 * Look in the list of ports that were added from the Hyper-V switch and
788 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
789 head = &(switchContext->portNoHashArray[i]);
790 LIST_FORALL(head, link) {
791 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
792 if (vport->portFriendlyName.Length == wstrSize &&
793 RtlEqualMemory(wsName, vport->portFriendlyName.String,
794 vport->portFriendlyName.Length)) {
808 OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext,
811 POVS_VPORT_ENTRY vport = NULL;
812 /* 'portFriendlyName' is not NUL-terminated. */
813 SIZE_T length = strlen(name);
814 SIZE_T wstrSize = length * sizeof(WCHAR);
817 PWSTR wsName = OvsAllocateMemoryWithTag(wstrSize, OVS_VPORT_POOL_TAG);
821 for (i = 0; i < length; i++) {
824 vport = OvsFindVportByHvNameW(switchContext, wsName, wstrSize);
825 OvsFreeMemoryWithTag(wsName, OVS_VPORT_POOL_TAG);
830 OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
831 NDIS_SWITCH_PORT_ID portId,
832 NDIS_SWITCH_NIC_INDEX index)
834 if (switchContext->virtualExternalVport &&
835 portId == switchContext->virtualExternalPortId &&
836 index == switchContext->virtualExternalVport->nicIndex) {
837 return (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
838 } else if (switchContext->internalVport &&
839 portId == switchContext->internalPortId &&
840 index == switchContext->internalVport->nicIndex) {
841 return (POVS_VPORT_ENTRY)switchContext->internalVport;
843 PLIST_ENTRY head, link;
844 POVS_VPORT_ENTRY vport;
846 hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
847 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
848 LIST_FORALL(head, link) {
849 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
850 if (portId == vport->portId && index == vport->nicIndex) {
859 OvsAllocateVport(VOID)
861 POVS_VPORT_ENTRY vport;
862 vport = (POVS_VPORT_ENTRY)OvsAllocateMemoryWithTag(
863 sizeof(OVS_VPORT_ENTRY), OVS_VPORT_POOL_TAG);
867 RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
868 vport->ovsState = OVS_STATE_UNKNOWN;
869 vport->isAbsentOnHv = FALSE;
870 vport->portNo = OVS_DPPORT_NUMBER_INVALID;
872 InitializeListHead(&vport->ovsNameLink);
873 InitializeListHead(&vport->portIdLink);
874 InitializeListHead(&vport->portNoLink);
880 OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
881 PNDIS_SWITCH_PORT_PARAMETERS portParam)
883 vport->portType = portParam->PortType;
884 vport->portState = portParam->PortState;
885 vport->portId = portParam->PortId;
886 vport->nicState = NdisSwitchNicStateUnknown;
887 vport->isExternal = FALSE;
888 vport->isBridgeInternal = FALSE;
890 switch (vport->portType) {
891 case NdisSwitchPortTypeExternal:
892 vport->isExternal = TRUE;
893 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
895 case NdisSwitchPortTypeInternal:
896 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
898 case NdisSwitchPortTypeSynthetic:
899 case NdisSwitchPortTypeEmulated:
900 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
903 RtlCopyMemory(&vport->hvPortName, &portParam->PortName,
904 sizeof (NDIS_SWITCH_PORT_NAME));
905 /* For external and internal ports, 'portFriendlyName' is overwritten
907 RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName,
908 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
910 switch (vport->portState) {
911 case NdisSwitchPortStateCreated:
912 vport->ovsState = OVS_STATE_PORT_CREATED;
914 case NdisSwitchPortStateTeardown:
915 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
917 case NdisSwitchPortStateDeleted:
918 vport->ovsState = OVS_STATE_PORT_DELETED;
925 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
926 POVS_VPORT_ENTRY vport,
927 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
929 ASSERT(vport->portId == nicParam->PortId);
930 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
932 UNREFERENCED_PARAMETER(switchContext);
934 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
935 sizeof (nicParam->PermanentMacAddress));
936 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
937 sizeof (nicParam->CurrentMacAddress));
939 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
940 nicParam->NicType == NdisSwitchNicTypeEmulated) {
941 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
942 sizeof (nicParam->VMMacAddress));
943 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
944 sizeof (nicParam->VmName));
946 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
947 sizeof (nicParam->NetCfgInstanceId));
949 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
950 sizeof (nicParam->NicName));
951 vport->mtu = nicParam->MTU;
952 vport->nicState = nicParam->NicState;
953 vport->nicIndex = nicParam->NicIndex;
954 vport->nicType = nicParam->NicType;
955 vport->numaNodeId = nicParam->NumaNodeId;
957 switch (vport->nicState) {
958 case NdisSwitchNicStateCreated:
959 vport->ovsState = OVS_STATE_NIC_CREATED;
961 case NdisSwitchNicStateConnected:
962 vport->ovsState = OVS_STATE_CONNECTED;
964 case NdisSwitchNicStateDisconnected:
965 vport->ovsState = OVS_STATE_NIC_CREATED;
967 case NdisSwitchNicStateDeleted:
968 vport->ovsState = OVS_STATE_PORT_CREATED;
974 * --------------------------------------------------------------------------
975 * Populates 'portParam' based on 'vport'.
976 * --------------------------------------------------------------------------
979 OvsCopyPortParamsFromVport(POVS_VPORT_ENTRY vport,
980 PNDIS_SWITCH_PORT_PARAMETERS portParam)
982 portParam->Flags = 0;
983 portParam->PortId = vport->portId;
984 RtlCopyMemory(&portParam->PortName, &vport->hvPortName,
985 sizeof (NDIS_SWITCH_PORT_NAME));
986 RtlCopyMemory(&portParam->PortFriendlyName,
987 &vport->portFriendlyName,
988 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
989 portParam->PortType = vport->portType;
990 portParam->IsValidationPort = FALSE;
991 portParam->PortState = vport->portState;
995 * --------------------------------------------------------------------------
996 * Initializes a tunnel vport.
997 * --------------------------------------------------------------------------
1000 OvsInitTunnelVport(PVOID userContext,
1001 POVS_VPORT_ENTRY vport,
1002 OVS_VPORT_TYPE ovsType,
1005 NTSTATUS status = STATUS_SUCCESS;
1006 POVS_USER_PARAMS_CONTEXT usrParamsCtx =
1007 (POVS_USER_PARAMS_CONTEXT)userContext;
1009 vport->isBridgeInternal = FALSE;
1010 vport->ovsType = ovsType;
1011 vport->ovsState = OVS_STATE_PORT_CREATED;
1013 case OVS_VPORT_TYPE_GRE:
1014 status = OvsInitGreTunnel(vport);
1016 case OVS_VPORT_TYPE_VXLAN:
1018 POVS_TUNFLT_INIT_CONTEXT tunnelContext = NULL;
1020 tunnelContext = OvsAllocateMemoryWithTag(sizeof(*tunnelContext),
1021 OVS_VPORT_POOL_TAG);
1022 if (tunnelContext == NULL) {
1023 status = STATUS_INSUFFICIENT_RESOURCES;
1026 tunnelContext->inputBuffer = usrParamsCtx->inputBuffer;
1027 tunnelContext->outputBuffer = usrParamsCtx->outputBuffer;
1028 tunnelContext->outputLength = usrParamsCtx->outputLength;
1029 tunnelContext->vport = vport;
1031 status = OvsInitVxlanTunnel(usrParamsCtx->irp,
1034 OvsTunnelVportPendingInit,
1035 (PVOID)tunnelContext);
1036 if (status != STATUS_PENDING) {
1037 OvsFreeMemoryWithTag(tunnelContext, OVS_VPORT_POOL_TAG);
1038 tunnelContext = NULL;
1042 case OVS_VPORT_TYPE_STT:
1043 status = OvsInitSttTunnel(vport, dstPort);
1052 * --------------------------------------------------------------------------
1053 * Initializes a bridge internal vport ie. a port of type
1054 * OVS_VPORT_TYPE_INTERNAL but not present on the Hyper-V switch.
1055 * --------------------------------------------------------------------------
1058 OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport)
1060 vport->isBridgeInternal = TRUE;
1061 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
1062 /* Mark the status to be connected, since there is no other initialization
1064 vport->ovsState = OVS_STATE_CONNECTED;
1065 return STATUS_SUCCESS;
1069 * --------------------------------------------------------------------------
1070 * For external and internal vports 'portFriendlyName' parameter, provided by
1071 * Hyper-V, is overwritten with the interface alias name.
1072 * --------------------------------------------------------------------------
1075 GetNICAlias(GUID *netCfgInstanceId,
1076 IF_COUNTED_STRING *portFriendlyName)
1079 WCHAR interfaceName[IF_MAX_STRING_SIZE + 1];
1080 NET_LUID interfaceLuid;
1083 status = ConvertInterfaceGuidToLuid(netCfgInstanceId,
1085 if (status == STATUS_SUCCESS) {
1087 * Must be called from PASSIVE_LEVEL. Resulted in a
1088 * STATUS_INVALID_DEVICE_REQUEST if not.
1090 status = ConvertInterfaceLuidToAlias(&interfaceLuid, interfaceName,
1091 IF_MAX_STRING_SIZE + 1);
1092 if (status == STATUS_SUCCESS) {
1093 RtlStringCbPrintfW(portFriendlyName->String,
1094 IF_MAX_STRING_SIZE, L"%s", interfaceName);
1095 RtlStringCbLengthW(portFriendlyName->String, IF_MAX_STRING_SIZE,
1097 portFriendlyName->Length = (USHORT)len;
1099 OVS_LOG_ERROR("Fail to convert interface LUID to alias, status: %x",
1103 OVS_LOG_ERROR("Fail to convert interface GUID to LUID, status: %x",
1112 * --------------------------------------------------------------------------
1113 * Functionality common to any port on the Hyper-V switch. This function is not
1114 * to be called for a port that is not on the Hyper-V switch.
1116 * Inserts the port into 'portIdHashArray' and caches the pointer in the
1117 * 'switchContext' if needed.
1118 * --------------------------------------------------------------------------
1121 UpdateSwitchCtxWithVport(POVS_SWITCH_CONTEXT switchContext,
1122 POVS_VPORT_ENTRY vport,
1127 switch (vport->portType) {
1128 case NdisSwitchPortTypeExternal:
1129 if (vport->nicIndex == 0) {
1130 switchContext->virtualExternalPortId = vport->portId;
1131 switchContext->virtualExternalVport = vport;
1133 switchContext->numPhysicalNics++;
1136 case NdisSwitchPortTypeInternal:
1137 ASSERT(vport->isBridgeInternal == FALSE);
1138 switchContext->internalPortId = vport->portId;
1139 switchContext->internalVport = vport;
1141 case NdisSwitchPortTypeSynthetic:
1142 case NdisSwitchPortTypeEmulated:
1147 * It is important to not insert vport corresponding to virtual external
1148 * port into the 'portIdHashArray' since the port should not be exposed to
1151 if (vport->portType == NdisSwitchPortTypeExternal &&
1152 vport->nicIndex == 0) {
1157 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
1158 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
1159 * hyper-v switch seems to use only 2 bytes out of 4.
1161 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
1162 InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK],
1163 &vport->portIdLink);
1165 switchContext->numHvVports++;
1171 * --------------------------------------------------------------------------
1172 * Functionality common to any port added from OVS userspace.
1174 * Inserts the port into 'portNoHashArray', 'ovsPortNameHashArray' and in
1175 * 'tunnelVportsArray' if appropriate.
1176 * --------------------------------------------------------------------------
1179 InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext,
1180 POVS_VPORT_ENTRY vport)
1184 switch(vport->ovsType) {
1185 case OVS_VPORT_TYPE_GRE:
1186 case OVS_VPORT_TYPE_VXLAN:
1187 case OVS_VPORT_TYPE_STT:
1189 UINT16 dstPort = GetPortFromPriv(vport);
1190 hash = OvsJhashBytes(&dstPort,
1194 &gOvsSwitchContext->tunnelVportsArray[hash & OVS_VPORT_MASK],
1195 &vport->tunnelVportLink);
1196 switchContext->numNonHvVports++;
1199 case OVS_VPORT_TYPE_INTERNAL:
1200 if (vport->isBridgeInternal) {
1201 switchContext->numNonHvVports++;
1208 * Insert the port into the hash array of ports: by port number and ovs
1209 * and ovs (datapath) port name.
1210 * NOTE: OvsJhashWords has portNo as "1" word. This is ok, because the
1211 * portNo is stored in 2 bytes only (max port number = MAXUINT16).
1213 hash = OvsJhashWords(&vport->portNo, 1, OVS_HASH_BASIS);
1214 InsertHeadList(&gOvsSwitchContext->portNoHashArray[hash & OVS_VPORT_MASK],
1215 &vport->portNoLink);
1217 hash = OvsJhashBytes(vport->ovsName, strlen(vport->ovsName) + 1,
1220 &gOvsSwitchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK],
1221 &vport->ovsNameLink);
1223 return STATUS_SUCCESS;
1228 * --------------------------------------------------------------------------
1229 * Provides functionality that is partly complementatry to
1230 * InitOvsVportCommon()/UpdateSwitchCtxWithVport().
1232 * 'hvDelete' indicates if caller is removing the vport as a result of the
1233 * port being removed on the Hyper-V switch.
1234 * 'ovsDelete' indicates if caller is removing the vport as a result of the
1235 * port being removed from OVS userspace.
1236 * --------------------------------------------------------------------------
1239 OvsRemoveAndDeleteVport(PVOID usrParamsContext,
1240 POVS_SWITCH_CONTEXT switchContext,
1241 POVS_VPORT_ENTRY vport,
1245 POVS_USER_PARAMS_CONTEXT usrParamsCtx =
1246 (POVS_USER_PARAMS_CONTEXT)usrParamsContext;
1247 BOOLEAN hvSwitchPort = FALSE;
1248 BOOLEAN deletedOnOvs = FALSE;
1249 BOOLEAN deletedOnHv = FALSE;
1251 switch (vport->ovsType) {
1252 case OVS_VPORT_TYPE_INTERNAL:
1253 if (!vport->isBridgeInternal) {
1254 if (hvDelete && vport->isAbsentOnHv == FALSE) {
1255 switchContext->internalPortId = 0;
1256 switchContext->internalVport = NULL;
1257 OvsInternalAdapterDown();
1259 hvSwitchPort = TRUE;
1262 case OVS_VPORT_TYPE_VXLAN:
1265 status = OvsRemoveTunnelVport(usrParamsCtx, switchContext, vport,
1266 hvDelete, ovsDelete);
1267 if (status != STATUS_SUCCESS) {
1271 case OVS_VPORT_TYPE_STT:
1272 OvsCleanupSttTunnel(vport);
1274 case OVS_VPORT_TYPE_GRE:
1275 OvsCleanupGreTunnel(vport);
1277 case OVS_VPORT_TYPE_NETDEV:
1278 if (vport->isExternal) {
1279 if (vport->nicIndex == 0) {
1280 /* Such a vport is not part of any of the hash tables, since it
1281 * is not exposed to userspace. See Vport.h for explanation. */
1282 ASSERT(hvDelete == TRUE);
1283 ASSERT(switchContext->numPhysicalNics == 0);
1284 switchContext->virtualExternalPortId = 0;
1285 switchContext->virtualExternalVport = NULL;
1286 OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
1287 return STATUS_SUCCESS;
1290 hvSwitchPort = TRUE;
1296 * 'hvDelete' == TRUE indicates that the port should be removed from the
1297 * 'portIdHashArray', while 'ovsDelete' == TRUE indicates that the port
1298 * should be removed from 'portNoHashArray' and the 'ovsPortNameHashArray'.
1300 * Both 'hvDelete' and 'ovsDelete' can be set to TRUE by the caller.
1302 if (vport->isAbsentOnHv == TRUE) {
1305 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
1306 deletedOnOvs = TRUE;
1309 if (hvDelete && !deletedOnHv) {
1310 vport->isAbsentOnHv = TRUE;
1312 if (vport->isExternal) {
1313 ASSERT(vport->nicIndex != 0);
1314 ASSERT(switchContext->numPhysicalNics);
1315 switchContext->numPhysicalNics--;
1318 /* Remove the port from the relevant lists. */
1319 RemoveEntryList(&vport->portIdLink);
1320 InitializeListHead(&vport->portIdLink);
1323 if (ovsDelete && !deletedOnOvs) {
1324 vport->portNo = OVS_DPPORT_NUMBER_INVALID;
1325 vport->ovsName[0] = '\0';
1327 /* Remove the port from the relevant lists. */
1328 RemoveEntryList(&vport->ovsNameLink);
1329 InitializeListHead(&vport->ovsNameLink);
1330 RemoveEntryList(&vport->portNoLink);
1331 InitializeListHead(&vport->portNoLink);
1332 if (OVS_VPORT_TYPE_VXLAN == vport->ovsType ||
1333 OVS_VPORT_TYPE_STT == vport->ovsType ||
1334 OVS_VPORT_TYPE_GRE == vport->ovsType) {
1335 RemoveEntryList(&vport->tunnelVportLink);
1336 InitializeListHead(&vport->tunnelVportLink);
1339 deletedOnOvs = TRUE;
1343 * Deallocate the port if it has been deleted on the Hyper-V switch as well
1346 if (deletedOnHv && deletedOnOvs) {
1348 switchContext->numHvVports--;
1350 switchContext->numNonHvVports--;
1352 OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
1355 return STATUS_SUCCESS;
1359 OvsRemoveTunnelVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1360 POVS_SWITCH_CONTEXT switchContext,
1361 POVS_VPORT_ENTRY vport,
1365 POVS_TUNFLT_INIT_CONTEXT tunnelContext = NULL;
1368 tunnelContext = OvsAllocateMemoryWithTag(sizeof(*tunnelContext),
1369 OVS_VPORT_POOL_TAG);
1370 if (tunnelContext == NULL) {
1371 return STATUS_INSUFFICIENT_RESOURCES;
1373 RtlZeroMemory(tunnelContext, sizeof(*tunnelContext));
1375 tunnelContext->switchContext = switchContext;
1376 tunnelContext->hvSwitchPort = FALSE;
1377 tunnelContext->hvDelete = hvDelete;
1378 tunnelContext->ovsDelete = ovsDelete;
1379 tunnelContext->vport = vport;
1382 tunnelContext->inputBuffer = usrParamsCtx->inputBuffer;
1383 tunnelContext->outputBuffer = usrParamsCtx->outputBuffer;
1384 tunnelContext->outputLength = usrParamsCtx->outputLength;
1385 irp = usrParamsCtx->irp;
1388 return OvsCleanupVxlanTunnel(irp, vport, OvsTunnelVportPendingRemove,
1393 * --------------------------------------------------------------------------
1394 * Enumerates the ports on the Hyper-V switch.
1395 * --------------------------------------------------------------------------
1398 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
1400 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1402 PNDIS_SWITCH_PORT_PARAMETERS portParam;
1403 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
1405 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
1407 status = OvsGetPortsOnSwitch(switchContext, &portArray);
1408 if (status != NDIS_STATUS_SUCCESS) {
1412 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
1413 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
1415 if (portParam->IsValidationPort) {
1419 status = HvCreatePort(switchContext, portParam, 0);
1420 if (status != STATUS_SUCCESS && status != STATUS_DATA_NOT_ACCEPTED) {
1426 if (status != NDIS_STATUS_SUCCESS) {
1427 OvsClearAllSwitchVports(switchContext);
1430 OvsFreeSwitchPortsArray(portArray);
1432 OVS_LOG_TRACE("Exit: status: %x", status);
1438 * --------------------------------------------------------------------------
1439 * Enumerates the NICs on the Hyper-V switch.
1440 * --------------------------------------------------------------------------
1443 OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
1445 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1446 PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
1448 PNDIS_SWITCH_NIC_PARAMETERS nicParam;
1450 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
1452 * Now, get NIC list.
1454 status = OvsGetNicsOnSwitch(switchContext, &nicArray);
1455 if (status != NDIS_STATUS_SUCCESS) {
1458 for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
1459 nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
1462 * XXX: Check if the port is configured with a VLAN. Disallow such a
1463 * configuration, since we don't support tag-in-tag.
1464 * XXX: Check if the port is connected to a VF. Disconnect the VF in
1468 status = HvCreateNic(switchContext, nicParam);
1469 if (status == NDIS_STATUS_SUCCESS) {
1470 HvConnectNic(switchContext, nicParam);
1475 OvsFreeSwitchNicsArray(nicArray);
1477 OVS_LOG_TRACE("Exit: status: %x", status);
1482 * --------------------------------------------------------------------------
1483 * Deletes ports added from the Hyper-V switch as well as OVS usersapce. The
1484 * function deletes ports in 'portIdHashArray'. This will delete most of the
1485 * ports that are in the 'portNoHashArray' as well. Any remaining ports
1486 * are deleted by walking the 'portNoHashArray'.
1487 * --------------------------------------------------------------------------
1490 OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
1492 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
1493 PLIST_ENTRY head, link, next;
1495 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
1496 LIST_FORALL_SAFE(head, link, next) {
1497 POVS_VPORT_ENTRY vport;
1498 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
1499 OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE);
1504 * Remove 'virtualExternalVport' as well. This port is not part of the
1505 * 'portIdHashArray'.
1507 if (switchContext->virtualExternalVport) {
1508 OvsRemoveAndDeleteVport(NULL, switchContext,
1509 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport, TRUE, TRUE);
1513 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
1514 PLIST_ENTRY head, link, next;
1515 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
1516 LIST_FORALL_SAFE(head, link, next) {
1517 POVS_VPORT_ENTRY vport;
1518 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
1519 ASSERT(OvsIsTunnelVportType(vport->ovsType) ||
1520 (vport->ovsType == OVS_VPORT_TYPE_INTERNAL &&
1521 vport->isBridgeInternal) || vport->isAbsentOnHv == TRUE);
1522 OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE);
1526 ASSERT(switchContext->virtualExternalVport == NULL);
1527 ASSERT(switchContext->internalVport == NULL);
1532 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
1537 UNICODE_STRING ustr;
1541 ustr.Buffer = wStr->String;
1542 ustr.Length = wStr->Length;
1543 ustr.MaximumLength = IF_MAX_STRING_SIZE;
1546 astr.MaximumLength = maxStrLen;
1549 size = RtlUnicodeStringToAnsiSize(&ustr);
1550 if (size > maxStrLen) {
1551 return STATUS_BUFFER_OVERFLOW;
1554 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
1556 ASSERT(status == STATUS_SUCCESS);
1557 if (status != STATUS_SUCCESS) {
1560 ASSERT(astr.Length <= maxStrLen);
1561 str[astr.Length] = 0;
1562 return STATUS_SUCCESS;
1566 * --------------------------------------------------------------------------
1567 * Utility function that populates a 'OVS_VPORT_EXT_INFO' structure for the
1569 * --------------------------------------------------------------------------
1572 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
1573 POVS_VPORT_EXT_INFO extInfo)
1575 POVS_VPORT_ENTRY vport;
1577 LOCK_STATE_EX lockState;
1578 NTSTATUS status = STATUS_SUCCESS;
1579 BOOLEAN doConvert = FALSE;
1581 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
1582 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1583 if (vportGet->portNo == 0) {
1584 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1585 vport = OvsFindVportByHvNameA(gOvsSwitchContext, vportGet->name);
1586 if (vport == NULL) {
1587 /* If the port is not a Hyper-V port and it has been added earlier,
1588 * we'll find it in 'ovsPortNameHashArray'. */
1589 vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name);
1592 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
1594 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1595 vport->ovsState != OVS_STATE_NIC_CREATED)) {
1596 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1597 if (vportGet->portNo) {
1598 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
1600 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
1602 status = STATUS_DEVICE_DOES_NOT_EXIST;
1605 extInfo->dpNo = vportGet->dpNo;
1606 extInfo->portNo = vport->portNo;
1607 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1608 sizeof (vport->currMacAddress));
1609 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1610 sizeof (vport->permMacAddress));
1611 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1612 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1613 sizeof (vport->vmMacAddress));
1615 extInfo->nicIndex = vport->nicIndex;
1616 extInfo->portId = vport->portId;
1617 extInfo->type = vport->ovsType;
1618 extInfo->mtu = vport->mtu;
1622 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1623 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1624 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
1625 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1627 extInfo->status = OVS_EVENT_DISCONNECT;
1629 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1630 (vport->ovsState == OVS_STATE_NIC_CREATED ||
1631 vport->ovsState == OVS_STATE_CONNECTED)) {
1634 extInfo->vmUUID[0] = 0;
1635 extInfo->vifUUID[0] = 0;
1637 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1639 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1641 OVS_MAX_PORT_NAME_LENGTH);
1642 if (status != STATUS_SUCCESS) {
1643 OVS_LOG_INFO("Fail to convert NIC name.");
1644 extInfo->vmUUID[0] = 0;
1647 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1649 OVS_MAX_VM_UUID_LEN);
1650 if (status != STATUS_SUCCESS) {
1651 OVS_LOG_INFO("Fail to convert VM name.");
1652 extInfo->vmUUID[0] = 0;
1655 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1657 OVS_MAX_VIF_UUID_LEN);
1658 if (status != STATUS_SUCCESS) {
1659 OVS_LOG_INFO("Fail to convert nic UUID");
1660 extInfo->vifUUID[0] = 0;
1663 * for now ignore status
1665 status = STATUS_SUCCESS;
1673 * --------------------------------------------------------------------------
1674 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1675 * --------------------------------------------------------------------------
1678 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1681 NTSTATUS status = STATUS_SUCCESS;
1682 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1683 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1684 NL_ERROR nlError = NL_ERROR_SUCCESS;
1685 OVS_VPORT_GET vportGet;
1686 OVS_VPORT_EXT_INFO info;
1688 static const NL_POLICY ovsNetdevPolicy[] = {
1689 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1691 .maxLen = IFNAMSIZ },
1693 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1695 /* input buffer has been validated while validating transaction dev op. */
1696 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1697 usrParamsCtx->inputLength > sizeof *msgIn);
1699 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1700 return STATUS_INVALID_BUFFER_SIZE;
1703 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1704 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1705 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1706 ovsNetdevPolicy, ARRAY_SIZE(ovsNetdevPolicy),
1707 netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1708 return STATUS_INVALID_PARAMETER;
1711 vportGet.portNo = 0;
1712 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1713 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1715 status = OvsGetExtInfoIoctl(&vportGet, &info);
1716 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1717 nlError = NL_ERROR_NODEV;
1721 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1722 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1723 gOvsSwitchContext->dpNo);
1724 if (status == STATUS_SUCCESS) {
1725 *replyLen = msgOut->nlMsg.nlmsgLen;
1729 if (nlError != NL_ERROR_SUCCESS) {
1730 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1731 usrParamsCtx->outputBuffer;
1733 NlBuildErrorMsg(msgIn, msgError, nlError);
1734 *replyLen = msgError->nlMsg.nlmsgLen;
1737 return STATUS_SUCCESS;
1742 * --------------------------------------------------------------------------
1743 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1744 * OVS_MESSAGE contains the output of a netdev command.
1745 * --------------------------------------------------------------------------
1748 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1757 UINT32 netdevFlags = 0;
1759 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1761 ok = NlFillOvsMsg(&nlBuffer, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
1762 msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
1763 msgIn->genlMsg.cmd, msgIn->genlMsg.version,
1766 return STATUS_INVALID_BUFFER_SIZE;
1769 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1772 return STATUS_INVALID_BUFFER_SIZE;
1775 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1777 return STATUS_INVALID_BUFFER_SIZE;
1780 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1783 return STATUS_INVALID_BUFFER_SIZE;
1786 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1787 (PCHAR)info->macAddress, sizeof (info->macAddress));
1789 return STATUS_INVALID_BUFFER_SIZE;
1792 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1794 return STATUS_INVALID_BUFFER_SIZE;
1797 if (info->status != OVS_EVENT_CONNECT) {
1798 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1800 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1803 return STATUS_INVALID_BUFFER_SIZE;
1807 * XXX: add netdev_stats when we have the definition available in the
1811 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1812 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1814 return STATUS_SUCCESS;
1817 static __inline VOID
1818 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1820 while ((!switchContext->isActivated) &&
1821 (!switchContext->isActivateFailed)) {
1822 /* Wait for the switch to be active and
1823 * the list of ports in OVS to be initialized. */
1824 NdisMSleep(sleepMicroSec);
1829 OvsCreateMsgFromVport(POVS_VPORT_ENTRY vport,
1836 OVS_VPORT_FULL_STATS vportStats;
1840 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1842 ok = NlFillOvsMsg(&nlBuffer, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
1843 msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
1844 msgIn->genlMsg.cmd, msgIn->genlMsg.version,
1847 return STATUS_INVALID_BUFFER_SIZE;
1850 ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_PORT_NO, vport->portNo);
1852 return STATUS_INVALID_BUFFER_SIZE;
1855 ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_TYPE, vport->ovsType);
1857 return STATUS_INVALID_BUFFER_SIZE;
1860 ok = NlMsgPutTailString(&nlBuffer, OVS_VPORT_ATTR_NAME, vport->ovsName);
1862 return STATUS_INVALID_BUFFER_SIZE;
1866 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1867 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1868 * it means we have an array of pids, instead of a single pid.
1869 * ATM we assume we have one pid only.
1872 ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_UPCALL_PID,
1875 return STATUS_INVALID_BUFFER_SIZE;
1879 vportStats.rxPackets = vport->stats.rxPackets;
1880 vportStats.rxBytes = vport->stats.rxBytes;
1881 vportStats.txPackets = vport->stats.txPackets;
1882 vportStats.txBytes = vport->stats.txBytes;
1883 vportStats.rxErrors = vport->errStats.rxErrors;
1884 vportStats.txErrors = vport->errStats.txErrors;
1885 vportStats.rxDropped = vport->errStats.rxDropped;
1886 vportStats.txDropped = vport->errStats.txDropped;
1888 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_VPORT_ATTR_STATS,
1890 sizeof(OVS_VPORT_FULL_STATS));
1892 return STATUS_INVALID_BUFFER_SIZE;
1896 * XXX: when vxlan udp dest port becomes configurable, we will also need
1897 * to add vport options
1900 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1901 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1903 return STATUS_SUCCESS;
1907 OvsGetVportDumpNext(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1911 POVS_OPEN_INSTANCE instance =
1912 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1913 LOCK_STATE_EX lockState;
1914 UINT32 i = OVS_MAX_VPORT_ARRAY_SIZE;
1917 * XXX: this function shares some code with other dump command(s).
1918 * In the future, we will need to refactor the dump functions
1921 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1923 if (instance->dumpState.ovsMsg == NULL) {
1925 return STATUS_INVALID_DEVICE_STATE;
1928 /* Output buffer has been validated while validating read dev op. */
1929 ASSERT(usrParamsCtx->outputBuffer != NULL);
1931 msgIn = instance->dumpState.ovsMsg;
1934 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1935 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1936 * it means we have an array of pids, instead of a single pid.
1937 * ATM we assume we have one pid only.
1939 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1941 if (gOvsSwitchContext->numHvVports > 0 ||
1942 gOvsSwitchContext->numNonHvVports > 0) {
1943 /* inBucket: the bucket, used for lookup */
1944 UINT32 inBucket = instance->dumpState.index[0];
1945 /* inIndex: index within the given bucket, used for lookup */
1946 UINT32 inIndex = instance->dumpState.index[1];
1947 /* the bucket to be used for the next dump operation */
1948 UINT32 outBucket = 0;
1949 /* the index within the outBucket to be used for the next dump */
1950 UINT32 outIndex = 0;
1952 for (i = inBucket; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
1953 PLIST_ENTRY head, link;
1954 head = &(gOvsSwitchContext->portNoHashArray[i]);
1955 POVS_VPORT_ENTRY vport = NULL;
1958 LIST_FORALL(head, link) {
1961 * if one or more dumps were previously done on this same bucket,
1962 * inIndex will be > 0, so we'll need to reply with the
1963 * inIndex + 1 vport from the bucket.
1965 if (outIndex >= inIndex) {
1966 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
1968 ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
1969 OvsCreateMsgFromVport(vport, msgIn,
1970 usrParamsCtx->outputBuffer,
1971 usrParamsCtx->outputLength,
1972 gOvsSwitchContext->dpNo);
1985 * if no vport was found above, check the next bucket, beginning
1986 * with the first (i.e. index 0) elem from within that bucket
1993 /* XXX: what about NLMSG_DONE (as msg type)? */
1994 instance->dumpState.index[0] = outBucket;
1995 instance->dumpState.index[1] = outIndex;
1998 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2000 /* if i < OVS_MAX_VPORT_ARRAY_SIZE => vport was found */
2001 if (i < OVS_MAX_VPORT_ARRAY_SIZE) {
2002 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2003 *replyLen = msgOut->nlMsg.nlmsgLen;
2006 * if i >= OVS_MAX_VPORT_ARRAY_SIZE => vport was not found =>
2010 /* Free up the dump state, since there's no more data to continue. */
2011 FreeUserDumpState(instance);
2014 return STATUS_SUCCESS;
2018 OvsGetVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2021 NTSTATUS status = STATUS_SUCCESS;
2022 LOCK_STATE_EX lockState;
2024 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2025 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2026 POVS_VPORT_ENTRY vport = NULL;
2027 NL_ERROR nlError = NL_ERROR_SUCCESS;
2028 PCHAR portName = NULL;
2029 UINT32 portNameLen = 0;
2030 UINT32 portNumber = OVS_DPPORT_NUMBER_INVALID;
2032 static const NL_POLICY ovsVportPolicy[] = {
2033 [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2034 [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING,
2039 PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2041 /* input buffer has been validated while validating write dev op. */
2042 ASSERT(usrParamsCtx->inputBuffer != NULL);
2044 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2045 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2046 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
2047 ovsVportPolicy, ARRAY_SIZE(ovsVportPolicy),
2048 vportAttrs, ARRAY_SIZE(vportAttrs))) {
2049 return STATUS_INVALID_PARAMETER;
2052 /* Output buffer has been validated while validating transact dev op. */
2053 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2055 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
2056 if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
2057 portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2058 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2060 /* the port name is expected to be null-terminated */
2061 ASSERT(portName[portNameLen - 1] == '\0');
2063 vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2064 } else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2065 portNumber = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
2067 vport = OvsFindVportByPortNo(gOvsSwitchContext, portNumber);
2069 nlError = NL_ERROR_INVAL;
2070 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2075 nlError = NL_ERROR_NODEV;
2076 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2080 status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2081 usrParamsCtx->outputLength,
2082 gOvsSwitchContext->dpNo);
2083 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2085 *replyLen = msgOut->nlMsg.nlmsgLen;
2088 if (nlError != NL_ERROR_SUCCESS) {
2089 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2090 usrParamsCtx->outputBuffer;
2092 NlBuildErrorMsg(msgIn, msgError, nlError);
2093 *replyLen = msgError->nlMsg.nlmsgLen;
2096 return STATUS_SUCCESS;
2100 * --------------------------------------------------------------------------
2101 * Command Handler for 'OVS_VPORT_CMD_GET'.
2103 * The function handles the initial call to setup the dump state, as well as
2104 * subsequent calls to continue dumping data.
2105 * --------------------------------------------------------------------------
2108 OvsGetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2113 switch (usrParamsCtx->devOp) {
2114 case OVS_WRITE_DEV_OP:
2115 return OvsSetupDumpStart(usrParamsCtx);
2117 case OVS_READ_DEV_OP:
2118 return OvsGetVportDumpNext(usrParamsCtx, replyLen);
2120 case OVS_TRANSACTION_DEV_OP:
2121 return OvsGetVport(usrParamsCtx, replyLen);
2124 return STATUS_INVALID_DEVICE_REQUEST;
2130 OvsComputeVportNo(POVS_SWITCH_CONTEXT switchContext)
2132 /* we are not allowed to create the port OVS_DPPORT_NUMBER_LOCAL */
2133 for (ULONG i = OVS_DPPORT_NUMBER_LOCAL + 1; i < MAXUINT16; ++i) {
2134 POVS_VPORT_ENTRY vport;
2136 vport = OvsFindVportByPortNo(switchContext, i);
2142 return OVS_DPPORT_NUMBER_INVALID;
2146 * --------------------------------------------------------------------------
2147 * Command Handler for 'OVS_VPORT_CMD_NEW'.
2148 * --------------------------------------------------------------------------
2151 OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2154 NDIS_STATUS status = STATUS_SUCCESS;
2155 LOCK_STATE_EX lockState;
2157 NL_ERROR nlError = NL_ERROR_SUCCESS;
2158 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2159 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2160 POVS_VPORT_ENTRY vport = NULL;
2164 BOOLEAN vportAllocated = FALSE, vportInitialized = FALSE;
2166 static const NL_POLICY ovsVportPolicy[] = {
2167 [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2168 [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = FALSE },
2169 [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2171 [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
2172 .optional = FALSE },
2173 [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
2176 PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2178 /* input buffer has been validated while validating write dev op. */
2179 ASSERT(usrParamsCtx->inputBuffer != NULL);
2181 /* Output buffer has been validated while validating transact dev op. */
2182 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2184 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2185 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2186 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
2187 ovsVportPolicy, ARRAY_SIZE(ovsVportPolicy),
2188 vportAttrs, ARRAY_SIZE(vportAttrs))) {
2189 return STATUS_INVALID_PARAMETER;
2192 portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2193 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2194 portType = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
2196 /* we are expecting null terminated strings to be passed */
2197 ASSERT(portName[portNameLen - 1] == '\0');
2199 NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
2201 vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2203 nlError = NL_ERROR_EXIST;
2207 if (portType == OVS_VPORT_TYPE_NETDEV) {
2208 /* External ports can also be looked up like VIF ports. */
2209 vport = OvsFindVportByHvNameA(gOvsSwitchContext, portName);
2211 ASSERT(OvsIsTunnelVportType(portType) ||
2212 portType == OVS_VPORT_TYPE_INTERNAL);
2214 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
2215 if (vport == NULL) {
2216 nlError = NL_ERROR_NOMEM;
2219 vportAllocated = TRUE;
2221 if (OvsIsTunnelVportType(portType)) {
2222 UINT16 transportPortDest = 0;
2225 case OVS_VPORT_TYPE_GRE:
2227 case OVS_VPORT_TYPE_VXLAN:
2228 transportPortDest = VXLAN_UDP_PORT;
2230 case OVS_VPORT_TYPE_STT:
2231 transportPortDest = STT_TCP_PORT;
2234 nlError = NL_ERROR_INVAL;
2238 if (vportAttrs[OVS_VPORT_ATTR_OPTIONS]) {
2239 PNL_ATTR attr = NlAttrFindNested(vportAttrs[OVS_VPORT_ATTR_OPTIONS],
2240 OVS_TUNNEL_ATTR_DST_PORT);
2242 transportPortDest = NlAttrGetU16(attr);
2246 status = OvsInitTunnelVport(usrParamsCtx,
2251 nlError = NlMapStatusToNlErr(status);
2253 OvsInitBridgeInternalVport(vport);
2256 vportInitialized = TRUE;
2258 if (nlError == NL_ERROR_SUCCESS) {
2259 vport->ovsState = OVS_STATE_CONNECTED;
2260 vport->nicState = NdisSwitchNicStateConnected;
2263 * Allow the vport to be deleted, because there is no
2264 * corresponding hyper-v switch part.
2266 vport->isAbsentOnHv = TRUE;
2273 nlError = NL_ERROR_INVAL;
2276 if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
2277 nlError = NL_ERROR_EXIST;
2281 if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2283 * XXX: when we implement the limit for ovs port number to be
2284 * MAXUINT16, we'll need to check the port number received from the
2287 vport->portNo = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
2289 vport->portNo = OvsComputeVportNo(gOvsSwitchContext);
2290 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
2291 nlError = NL_ERROR_NOMEM;
2296 /* The ovs port name must be uninitialized. */
2297 ASSERT(vport->ovsName[0] == '\0');
2298 ASSERT(portNameLen <= OVS_MAX_PORT_NAME_LENGTH);
2300 RtlCopyMemory(vport->ovsName, portName, portNameLen);
2301 /* if we don't have options, then vport->portOptions will be NULL */
2302 vport->portOptions = vportAttrs[OVS_VPORT_ATTR_OPTIONS];
2305 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2306 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2307 * it means we have an array of pids, instead of a single pid.
2308 * ATM we assume we have one pid only.
2310 vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
2312 status = InitOvsVportCommon(gOvsSwitchContext, vport);
2313 ASSERT(status == STATUS_SUCCESS);
2315 status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2316 usrParamsCtx->outputLength,
2317 gOvsSwitchContext->dpNo);
2319 *replyLen = msgOut->nlMsg.nlmsgLen;
2322 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2324 if ((nlError != NL_ERROR_SUCCESS) && (nlError != NL_ERROR_PENDING)) {
2325 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2326 usrParamsCtx->outputBuffer;
2328 if (vport && vportAllocated == TRUE) {
2329 if (vportInitialized == TRUE) {
2330 if (OvsIsTunnelVportType(portType)) {
2331 switch (vport->ovsType) {
2332 case OVS_VPORT_TYPE_VXLAN:
2333 OvsCleanupVxlanTunnel(NULL, vport, NULL, NULL);
2335 case OVS_VPORT_TYPE_STT:
2336 OvsCleanupSttTunnel(vport);
2339 ASSERT(!"Invalid tunnel port type");
2343 OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
2346 NlBuildErrorMsg(msgIn, msgError, nlError);
2347 *replyLen = msgError->nlMsg.nlmsgLen;
2350 return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
2355 * --------------------------------------------------------------------------
2356 * Command Handler for 'OVS_VPORT_CMD_SET'.
2357 * --------------------------------------------------------------------------
2360 OvsSetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2363 NDIS_STATUS status = STATUS_SUCCESS;
2364 LOCK_STATE_EX lockState;
2366 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2367 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2368 POVS_VPORT_ENTRY vport = NULL;
2369 NL_ERROR nlError = NL_ERROR_SUCCESS;
2371 static const NL_POLICY ovsVportPolicy[] = {
2372 [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2373 [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = TRUE },
2374 [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2376 [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
2378 [OVS_VPORT_ATTR_STATS] = { .type = NL_A_UNSPEC,
2379 .minLen = sizeof(OVS_VPORT_FULL_STATS),
2380 .maxLen = sizeof(OVS_VPORT_FULL_STATS),
2382 [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
2384 PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2386 ASSERT(usrParamsCtx->inputBuffer != NULL);
2388 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2389 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2390 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
2391 ovsVportPolicy, ARRAY_SIZE(ovsVportPolicy),
2392 vportAttrs, ARRAY_SIZE(vportAttrs))) {
2393 return STATUS_INVALID_PARAMETER;
2396 /* Output buffer has been validated while validating transact dev op. */
2397 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2399 NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
2400 if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
2401 PSTR portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2403 UINT32 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2405 /* the port name is expected to be null-terminated */
2406 ASSERT(portName[portNameLen - 1] == '\0');
2408 vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2409 } else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2410 vport = OvsFindVportByPortNo(gOvsSwitchContext,
2411 NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]));
2415 nlError = NL_ERROR_NODEV;
2420 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2421 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2422 * it means we have an array of pids, instead of a single pid.
2423 * Currently, we support only one pid.
2425 if (vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]) {
2426 vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
2429 if (vportAttrs[OVS_VPORT_ATTR_TYPE]) {
2430 OVS_VPORT_TYPE type = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
2431 if (type != vport->ovsType) {
2432 nlError = NL_ERROR_INVAL;
2437 if (vportAttrs[OVS_VPORT_ATTR_OPTIONS]) {
2438 OVS_LOG_ERROR("Vport options not supported");
2439 nlError = NL_ERROR_NOTSUPP;
2443 status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2444 usrParamsCtx->outputLength,
2445 gOvsSwitchContext->dpNo);
2447 *replyLen = msgOut->nlMsg.nlmsgLen;
2450 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2452 if (nlError != NL_ERROR_SUCCESS) {
2453 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2454 usrParamsCtx->outputBuffer;
2456 NlBuildErrorMsg(msgIn, msgError, nlError);
2457 *replyLen = msgError->nlMsg.nlmsgLen;
2460 return STATUS_SUCCESS;
2464 * --------------------------------------------------------------------------
2465 * Command Handler for 'OVS_VPORT_CMD_DEL'.
2466 * --------------------------------------------------------------------------
2469 OvsDeleteVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2472 NDIS_STATUS status = STATUS_SUCCESS;
2473 LOCK_STATE_EX lockState;
2475 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2476 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2477 POVS_VPORT_ENTRY vport = NULL;
2478 NL_ERROR nlError = NL_ERROR_SUCCESS;
2479 PSTR portName = NULL;
2480 UINT32 portNameLen = 0;
2482 static const NL_POLICY ovsVportPolicy[] = {
2483 [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2484 [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2487 PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2489 ASSERT(usrParamsCtx->inputBuffer != NULL);
2491 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2492 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2493 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
2494 ovsVportPolicy, ARRAY_SIZE(ovsVportPolicy),
2495 vportAttrs, ARRAY_SIZE(vportAttrs))) {
2496 return STATUS_INVALID_PARAMETER;
2499 /* Output buffer has been validated while validating transact dev op. */
2500 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2502 NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
2503 if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
2504 portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2505 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2507 /* the port name is expected to be null-terminated */
2508 ASSERT(portName[portNameLen - 1] == '\0');
2510 vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2512 else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2513 vport = OvsFindVportByPortNo(gOvsSwitchContext,
2514 NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]));
2518 nlError = NL_ERROR_NODEV;
2522 status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2523 usrParamsCtx->outputLength,
2524 gOvsSwitchContext->dpNo);
2526 *replyLen = msgOut->nlMsg.nlmsgLen;
2529 * Mark the port as deleted from OVS userspace. If the port does not exist
2530 * on the Hyper-V switch, it gets deallocated. Otherwise, it stays.
2532 status = OvsRemoveAndDeleteVport(usrParamsCtx,
2538 nlError = NlMapStatusToNlErr(status);
2542 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2544 if ((nlError != NL_ERROR_SUCCESS) && (nlError != NL_ERROR_PENDING)) {
2545 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2546 usrParamsCtx->outputBuffer;
2548 NlBuildErrorMsg(msgIn, msgError, nlError);
2549 *replyLen = msgError->nlMsg.nlmsgLen;
2552 return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
2556 OvsTunnelVportPendingRemove(PVOID context,
2560 POVS_TUNFLT_INIT_CONTEXT tunnelContext =
2561 (POVS_TUNFLT_INIT_CONTEXT) context;
2562 POVS_SWITCH_CONTEXT switchContext = tunnelContext->switchContext;
2563 POVS_VPORT_ENTRY vport = tunnelContext->vport;
2564 POVS_MESSAGE msgIn = (POVS_MESSAGE)tunnelContext->inputBuffer;
2565 POVS_MESSAGE msgOut = (POVS_MESSAGE)tunnelContext->outputBuffer;
2566 NL_ERROR nlError = NlMapStatusToNlErr(status);
2567 LOCK_STATE_EX lockState;
2569 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
2571 if (msgIn && msgOut) {
2572 /* Check the received status to reply to the caller. */
2573 if (STATUS_SUCCESS == status) {
2574 OvsCreateMsgFromVport(vport,
2577 tunnelContext->outputLength,
2578 switchContext->dpNo);
2580 *replyLen = msgOut->nlMsg.nlmsgLen;
2582 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)msgOut;
2584 NlBuildErrorMsg(msgIn, msgError, nlError);
2585 *replyLen = msgError->nlMsg.nlmsgLen;
2589 ASSERT(vport->isAbsentOnHv == TRUE);
2590 ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
2592 /* Remove the port from the relevant lists. */
2593 switchContext->numNonHvVports--;
2594 RemoveEntryList(&vport->ovsNameLink);
2595 RemoveEntryList(&vport->portNoLink);
2596 RemoveEntryList(&vport->tunnelVportLink);
2599 OvsFreeMemoryWithTag(vport->priv, OVS_VXLAN_POOL_TAG);
2603 OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
2605 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
2609 OvsTunnelVportPendingInit(PVOID context,
2613 POVS_TUNFLT_INIT_CONTEXT tunnelContext =
2614 (POVS_TUNFLT_INIT_CONTEXT) context;
2615 POVS_VPORT_ENTRY vport = tunnelContext->vport;
2616 POVS_MESSAGE msgIn = (POVS_MESSAGE)tunnelContext->inputBuffer;
2617 POVS_MESSAGE msgOut = (POVS_MESSAGE)tunnelContext->outputBuffer;
2619 ULONG portNameLen = 0;
2620 UINT32 portType = 0;
2621 NL_ERROR nlError = NL_ERROR_SUCCESS;
2622 BOOLEAN error = TRUE;
2625 if (!NT_SUCCESS(status)) {
2626 nlError = NlMapStatusToNlErr(status);
2630 static const NL_POLICY ovsVportPolicy[] = {
2631 [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2632 [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = FALSE },
2633 [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2634 .optional = FALSE },
2635 [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
2636 .optional = FALSE },
2637 [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
2640 PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2642 /* input buffer has been validated while validating write dev op. */
2643 ASSERT(msgIn != NULL);
2645 /* Output buffer has been validated while validating transact dev op. */
2646 ASSERT(msgOut != NULL && tunnelContext->outputLength >= sizeof *msgOut);
2648 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2649 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2650 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
2651 ovsVportPolicy, ARRAY_SIZE(ovsVportPolicy),
2652 vportAttrs, ARRAY_SIZE(vportAttrs))) {
2653 nlError = NL_ERROR_INVAL;
2657 portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2658 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2659 portType = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
2661 if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
2662 nlError = NL_ERROR_EXIST;
2666 vport->ovsState = OVS_STATE_CONNECTED;
2667 vport->nicState = NdisSwitchNicStateConnected;
2670 * Allow the vport to be deleted, because there is no
2671 * corresponding hyper-v switch part.
2673 vport->isAbsentOnHv = TRUE;
2675 if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2677 * XXX: when we implement the limit for OVS port number to be
2678 * MAXUINT16, we'll need to check the port number received from the
2682 NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
2685 OvsComputeVportNo(gOvsSwitchContext);
2686 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
2687 nlError = NL_ERROR_NOMEM;
2692 /* The ovs port name must be uninitialized. */
2693 ASSERT(vport->ovsName[0] == '\0');
2694 ASSERT(portNameLen <= OVS_MAX_PORT_NAME_LENGTH);
2696 RtlCopyMemory(vport->ovsName, portName, portNameLen);
2697 /* if we don't have options, then vport->portOptions will be NULL */
2698 vport->portOptions = vportAttrs[OVS_VPORT_ATTR_OPTIONS];
2701 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2702 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2703 * it means we have an array of pids, instead of a single pid.
2704 * ATM we assume we have one pid only.
2707 NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
2709 status = InitOvsVportCommon(gOvsSwitchContext, vport);
2710 ASSERT(status == STATUS_SUCCESS);
2712 OvsCreateMsgFromVport(vport,
2715 tunnelContext->outputLength,
2716 gOvsSwitchContext->dpNo);
2718 *replyLen = msgOut->nlMsg.nlmsgLen;
2724 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR) msgOut;
2726 OvsCleanupVxlanTunnel(NULL, vport, NULL, NULL);
2727 OvsFreeMemory(vport);
2729 NlBuildErrorMsg(msgIn, msgError, nlError);
2730 *replyLen = msgError->nlMsg.nlmsgLen;