]> git.proxmox.com Git - mirror_ovs.git/blame - datapath-windows/ovsext/Vport.c
ovn-northd: no logical router icmp response for directed broadcasts
[mirror_ovs.git] / datapath-windows / ovsext / Vport.c
CommitLineData
c803536e
SS
1/*
2 * Copyright (c) 2014 VMware, Inc.
3 *
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:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include "precomp.h"
85571a3d
AS
18
19#include "Datapath.h"
20#include "Event.h"
21#include "Gre.h"
22#include "IpHelper.h"
fa1324c9 23#include "Jhash.h"
85571a3d
AS
24#include "Oid.h"
25#include "Stt.h"
fa1324c9 26#include "Switch.h"
fa1324c9 27#include "User.h"
85571a3d 28#include "Vport.h"
fa1324c9 29#include "Vxlan.h"
c803536e
SS
30
31#ifdef OVS_DBG_MOD
32#undef OVS_DBG_MOD
33#endif
34#define OVS_DBG_MOD OVS_DBG_VPORT
fa1324c9 35#include "Debug.h"
c803536e
SS
36
37#define VPORT_NIC_ENTER(_nic) \
38 OVS_LOG_TRACE("Enter: PortId: %x, NicIndex: %d", _nic->PortId, \
39 _nic->NicIndex)
40
41#define VPORT_NIC_EXIT(_nic) \
42 OVS_LOG_TRACE("Exit: PortId: %x, NicIndex: %d", _nic->PortId, \
43 _nic->NicIndex)
44
45#define VPORT_PORT_ENTER(_port) \
46 OVS_LOG_TRACE("Enter: PortId: %x", _port->PortId)
47
48#define VPORT_PORT_EXIT(_port) \
49 OVS_LOG_TRACE("Exit: PortId: %x", _port->PortId)
50
51#define OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC 100
52
5e82ceef
SV
53/* Context structure used to pass back and forth information to the tunnel
54 * filter threads. */
55typedef struct _OVS_TUNFLT_INIT_CONTEXT {
56 POVS_SWITCH_CONTEXT switchContext;
57 UINT32 outputLength;
58 PVOID outputBuffer;
59 PVOID inputBuffer;
60 POVS_VPORT_ENTRY vport;
61 BOOLEAN hvSwitchPort;
62 BOOLEAN hvDelete;
63 BOOLEAN ovsDelete;
64} OVS_TUNFLT_INIT_CONTEXT, *POVS_TUNFLT_INIT_CONTEXT;
65
66
c803536e 67extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
c803536e 68
c803536e
SS
69static VOID OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
70 PNDIS_SWITCH_PORT_PARAMETERS portParam);
71static VOID OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
72 POVS_VPORT_ENTRY vport, PNDIS_SWITCH_NIC_PARAMETERS nicParam);
958227c6
NR
73static VOID OvsCopyPortParamsFromVport(POVS_VPORT_ENTRY vport,
74 PNDIS_SWITCH_PORT_PARAMETERS portParam);
c803536e
SS
75static __inline VOID OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext,
76 ULONG sleepMicroSec);
be581675
NR
77static NTSTATUS OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
78 POVS_VPORT_EXT_INFO extInfo);
79static NTSTATUS CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
80 POVS_MESSAGE msgIn,
81 PVOID outBuffer,
82 UINT32 outBufLen,
83 int dpIfIndex);
70e56250
NR
84static POVS_VPORT_ENTRY OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext,
85 PWSTR wsName, SIZE_T wstrSize);
958227c6
NR
86static VOID UpdateSwitchCtxWithVport(POVS_SWITCH_CONTEXT switchContext,
87 POVS_VPORT_ENTRY vport, BOOLEAN newPort);
b8155080
NR
88static NTSTATUS OvsRemoveTunnelVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
89 POVS_SWITCH_CONTEXT switchContext,
90 POVS_VPORT_ENTRY vport,
91 BOOLEAN hvDelete,
92 BOOLEAN ovsDelete);
5e82ceef
SV
93static VOID OvsTunnelVportPendingInit(PVOID context,
94 NTSTATUS status,
95 UINT32 *replyLen);
b8155080 96static VOID OvsTunnelVportPendingRemove(PVOID context,
5e82ceef
SV
97 NTSTATUS status,
98 UINT32 *replyLen);
34be96ca
NR
99static NTSTATUS GetNICAlias(GUID *netCfgInstanceId,
100 IF_COUNTED_STRING *portFriendlyName);
c803536e
SS
101
102/*
958227c6
NR
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 * --------------------------------------------------------------------------
c803536e
SS
108 */
109NDIS_STATUS
fa048323 110HvCreatePort(POVS_SWITCH_CONTEXT switchContext,
958227c6
NR
111 PNDIS_SWITCH_PORT_PARAMETERS portParam,
112 NDIS_SWITCH_NIC_INDEX nicIndex)
c803536e
SS
113{
114 POVS_VPORT_ENTRY vport;
115 LOCK_STATE_EX lockState;
116 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
25f44d58 117 BOOLEAN newPort = FALSE;
c803536e
SS
118
119 VPORT_PORT_ENTER(portParam);
120
121 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
25f44d58 122 /* Lookup by port ID. */
c803536e 123 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
958227c6 124 portParam->PortId, nicIndex);
25f44d58
NR
125 if (vport != NULL) {
126 OVS_LOG_ERROR("Port add failed due to duplicate port name, "
127 "port Id: %u", portParam->PortId);
c803536e
SS
128 status = STATUS_DATA_NOT_ACCEPTED;
129 goto create_port_done;
25f44d58
NR
130 }
131
132 /*
133 * Lookup by port name to see if this port with this name had been added
134 * (and deleted) previously.
135 */
136 vport = OvsFindVportByHvNameW(gOvsSwitchContext,
137 portParam->PortFriendlyName.String,
138 portParam->PortFriendlyName.Length);
421e2422 139 if (vport && vport->isAbsentOnHv == FALSE) {
25f44d58
NR
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;
145 }
146
147 if (vport != NULL) {
421e2422 148 ASSERT(vport->isAbsentOnHv);
25f44d58
NR
149 ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
150
151 /*
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.
155 */
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;
162 }
421e2422 163 vport->isAbsentOnHv = FALSE;
25f44d58 164 } else {
8d9f1e0c
NR
165 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
166 if (vport == NULL) {
167 status = NDIS_STATUS_RESOURCES;
168 goto create_port_done;
169 }
25f44d58 170 newPort = TRUE;
c803536e 171 }
c803536e 172 OvsInitVportWithPortParam(vport, portParam);
958227c6
NR
173 vport->nicIndex = nicIndex;
174 UpdateSwitchCtxWithVport(switchContext, vport, newPort);
c803536e
SS
175
176create_port_done:
177 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
178 VPORT_PORT_EXIT(portParam);
179 return status;
180}
181
b5af03d7
EE
182
183/*
958227c6
NR
184 * --------------------------------------------------------------------------
185 * Function to process updates to a port on the Hyper-Vs witch.
186 * --------------------------------------------------------------------------
b5af03d7
EE
187 */
188NDIS_STATUS
189HvUpdatePort(POVS_SWITCH_CONTEXT switchContext,
190 PNDIS_SWITCH_PORT_PARAMETERS portParam)
191{
192 POVS_VPORT_ENTRY vport;
193 LOCK_STATE_EX lockState;
194 OVS_VPORT_STATE ovsState;
195 NDIS_SWITCH_NIC_STATE nicState;
196
197 VPORT_PORT_ENTER(portParam);
198
199 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
200 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
201 portParam->PortId, 0);
202 /*
203 * Update properties only for NETDEV ports for supprting PS script
b5af03d7 204 */
7845b703 205 if (vport == NULL) {
b5af03d7
EE
206 goto update_port_done;
207 }
208
209 /* Store the nic and the OVS states as Nic Create won't be called */
210 ovsState = vport->ovsState;
211 nicState = vport->nicState;
b8155080 212
b5af03d7
EE
213 /*
214 * Currently only the port friendly name is being updated
215 * Make sure that no other properties are changed
216 */
217 ASSERT(portParam->PortId == vport->portId);
218 ASSERT(portParam->PortState == vport->portState);
219 ASSERT(portParam->PortType == vport->portType);
220
221 /*
222 * Call the set parameters function the handle all properties
223 * change in a single place in case future version supports change of
224 * other properties
225 */
226 OvsInitVportWithPortParam(vport, portParam);
227 /* Retore the nic and OVS states */
228 vport->nicState = nicState;
229 vport->ovsState = ovsState;
230
231update_port_done:
232 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
233 VPORT_PORT_EXIT(portParam);
234
235 /* Must always return success */
236 return NDIS_STATUS_SUCCESS;
237}
238
958227c6
NR
239
240/*
241 * --------------------------------------------------------------------------
242 * Function to process teardown of a port on the Hyper-V switch.
243 * --------------------------------------------------------------------------
244 */
c803536e 245VOID
fa048323
AS
246HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
247 PNDIS_SWITCH_PORT_PARAMETERS portParam)
c803536e
SS
248{
249 POVS_VPORT_ENTRY vport;
250 LOCK_STATE_EX lockState;
251
252 VPORT_PORT_ENTER(portParam);
253
254 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
255 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
256 portParam->PortId, 0);
257 if (vport) {
c22f284b 258 /* add assertion here */
c803536e
SS
259 vport->portState = NdisSwitchPortStateTeardown;
260 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
261 } else {
262 OVS_LOG_WARN("Vport not present.");
263 }
264 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
265
266 VPORT_PORT_EXIT(portParam);
267}
268
958227c6
NR
269/*
270 * --------------------------------------------------------------------------
271 * Function to process deletion of a port on the Hyper-V switch.
272 * --------------------------------------------------------------------------
273 */
c803536e 274VOID
fa048323 275HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
611531c1 276 PNDIS_SWITCH_PORT_PARAMETERS portParams)
c803536e
SS
277{
278 POVS_VPORT_ENTRY vport;
279 LOCK_STATE_EX lockState;
280
611531c1 281 VPORT_PORT_ENTER(portParams);
c803536e
SS
282
283 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
284 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
611531c1
NR
285 portParams->PortId, 0);
286
287 /*
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.
292 */
c803536e 293 if (vport) {
fbeb0f3f
NR
294 OVS_EVENT_ENTRY event;
295
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;
5e82ceef 301 OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, FALSE);
fbeb0f3f 302 OvsPostEvent(&event);
c803536e
SS
303 } else {
304 OVS_LOG_WARN("Vport not present.");
305 }
306 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
307
611531c1 308 VPORT_PORT_EXIT(portParams);
c803536e
SS
309}
310
311
312/*
958227c6
NR
313 * --------------------------------------------------------------------------
314 * Function to process addition of a NIC connection on the Hyper-V switch.
9be4a837
NR
315 * XXX: Posting an event to DPIF is incorrect here. However, it might be useful
316 * to post an event to netdev-windows.c.
958227c6 317 * --------------------------------------------------------------------------
c803536e
SS
318 */
319NDIS_STATUS
fa048323
AS
320HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
321 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
c803536e
SS
322{
323 POVS_VPORT_ENTRY vport;
c803536e 324 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
34be96ca 325 IF_COUNTED_STRING portFriendlyName = {0};
c803536e
SS
326 LOCK_STATE_EX lockState;
327
328 VPORT_NIC_ENTER(nicParam);
329
330 /* Wait for lists to be initialized. */
331 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
332
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;
337 goto done;
338 }
339
d49b001d
NR
340 if (OvsIsInternalNIC(nicParam->NicType) ||
341 OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
34be96ca
NR
342 GetNICAlias(&nicParam->NetCfgInstanceId, &portFriendlyName);
343 }
344
c803536e 345 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
958227c6
NR
346 /*
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.
350 */
d49b001d
NR
351 if (OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
352 NDIS_SWITCH_PORT_PARAMETERS portParam;
f1613007 353 POVS_VPORT_ENTRY virtExtVport =
25e39a60 354 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
f1613007 355
d49b001d
NR
356 ASSERT(virtExtVport);
357 ASSERT(OvsFindVportByPortIdAndNicIndex(switchContext,
358 nicParam->PortId,
359 nicParam->NicIndex) == NULL);
360 OvsCopyPortParamsFromVport(virtExtVport, &portParam);
361 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
362 status = HvCreatePort(switchContext, &portParam,
363 nicParam->NicIndex);
364 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
365 if (status != NDIS_STATUS_SUCCESS) {
366 goto add_nic_done;
c803536e 367 }
958227c6 368 }
ac79a988 369
958227c6
NR
370 vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId,
371 nicParam->NicIndex);
372 if (vport == NULL) {
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;
377 goto add_nic_done;
378 }
379 OvsInitVportWithNicParam(switchContext, vport, nicParam);
d49b001d
NR
380 if (OvsIsInternalNIC(nicParam->NicType) ||
381 OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
34be96ca
NR
382 RtlCopyMemory(&vport->portFriendlyName, &portFriendlyName,
383 sizeof portFriendlyName);
c803536e 384 }
958227c6 385
c803536e
SS
386add_nic_done:
387 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
c803536e
SS
388
389done:
390 VPORT_NIC_EXIT(nicParam);
391 OVS_LOG_TRACE("Exit: status %8x.\n", status);
392
393 return status;
394}
395
958227c6
NR
396/*
397 * --------------------------------------------------------------------------
398 * Function to process connection event of a NIC on the Hyper-V switch.
399 * --------------------------------------------------------------------------
400 */
c803536e 401VOID
fa048323
AS
402HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
403 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
c803536e
SS
404{
405 LOCK_STATE_EX lockState;
406 POVS_VPORT_ENTRY vport;
c803536e
SS
407
408 VPORT_NIC_ENTER(nicParam);
409
410 /* Wait for lists to be initialized. */
411 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
412
413 if (!switchContext->isActivated) {
414 OVS_LOG_WARN("Switch is not activated yet.");
415 goto done;
416 }
417
418 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
419 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
420 nicParam->PortId,
421 nicParam->NicIndex);
422
423 if (!vport) {
424 OVS_LOG_WARN("Vport not present.");
425 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
426 ASSERT(0);
427 goto done;
428 }
429
430 vport->ovsState = OVS_STATE_CONNECTED;
431 vport->nicState = NdisSwitchNicStateConnected;
c803536e
SS
432
433 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
434
c803536e 435 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
12e888ba 436 OvsInternalAdapterUp(&nicParam->NetCfgInstanceId);
c803536e
SS
437 }
438
439done:
440 VPORT_NIC_EXIT(nicParam);
441}
442
958227c6
NR
443
444/*
445 * --------------------------------------------------------------------------
446 * Function to process updates to a NIC on the Hyper-V switch.
447 * --------------------------------------------------------------------------
448 */
c803536e 449VOID
fa048323
AS
450HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
451 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
c803536e
SS
452{
453 POVS_VPORT_ENTRY vport;
454 LOCK_STATE_EX lockState;
9be4a837 455 UINT32 event = 0;
34be96ca 456 IF_COUNTED_STRING portFriendlyName = {0};
d49b001d
NR
457 BOOLEAN nameChanged = FALSE;
458 BOOLEAN aliasLookup = FALSE;
c803536e
SS
459
460 VPORT_NIC_ENTER(nicParam);
461
462 /* Wait for lists to be initialized. */
463 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
464
465 if (!switchContext->isActivated) {
466 OVS_LOG_WARN("Switch is not activated yet.");
467 goto update_nic_done;
468 }
469
34be96ca
NR
470 /* GetNICAlias() must be called outside of a lock. */
471 if (nicParam->NicType == NdisSwitchNicTypeInternal ||
d49b001d 472 OvsIsRealExternalNIC(nicParam->NicType, nicParam->NicIndex)) {
34be96ca 473 GetNICAlias(&nicParam->NetCfgInstanceId, &portFriendlyName);
d49b001d 474 aliasLookup = TRUE;
34be96ca
NR
475 }
476
c803536e
SS
477 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
478 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
479 nicParam->PortId,
480 nicParam->NicIndex);
481 if (vport == NULL) {
6c6045a7 482 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
c803536e
SS
483 OVS_LOG_WARN("Vport search failed.");
484 goto update_nic_done;
485 }
486 switch (nicParam->NicType) {
487 case NdisSwitchNicTypeExternal:
488 case NdisSwitchNicTypeInternal:
489 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
490 sizeof (GUID));
d49b001d
NR
491 if (aliasLookup) {
492 if (RtlCompareMemory(&vport->portFriendlyName,
493 &portFriendlyName, vport->portFriendlyName.Length) !=
494 vport->portFriendlyName.Length) {
495 RtlCopyMemory(&vport->portFriendlyName, &portFriendlyName,
496 sizeof portFriendlyName);
497 nameChanged = TRUE;
498 }
499 }
c803536e
SS
500 break;
501 case NdisSwitchNicTypeSynthetic:
502 case NdisSwitchNicTypeEmulated:
503 if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
504 sizeof (vport->vmMacAddress))) {
9be4a837 505 event |= OVS_EVENT_MAC_CHANGE;
c803536e
SS
506 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
507 sizeof (vport->vmMacAddress));
508 }
509 break;
510 default:
511 ASSERT(0);
512 }
513 if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
514 sizeof (vport->permMacAddress))) {
515 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
516 sizeof (vport->permMacAddress));
9be4a837 517 event |= OVS_EVENT_MAC_CHANGE;
c803536e
SS
518 }
519 if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
520 sizeof (vport->currMacAddress))) {
521 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
522 sizeof (vport->currMacAddress));
9be4a837 523 event |= OVS_EVENT_MAC_CHANGE;
c803536e
SS
524 }
525
526 if (vport->mtu != nicParam->MTU) {
527 vport->mtu = nicParam->MTU;
9be4a837 528 event |= OVS_EVENT_MTU_CHANGE;
c803536e
SS
529 }
530 vport->numaNodeId = nicParam->NumaNodeId;
c803536e 531
d49b001d
NR
532 if (nameChanged) {
533 OVS_EVENT_ENTRY event;
534 event.portNo = vport->portNo;
535 event.ovsType = vport->ovsType;
536 event.upcallPid = vport->upcallPid;
537 RtlCopyMemory(&event.ovsName, &vport->ovsName, sizeof event.ovsName);
538 event.type = OVS_EVENT_LINK_DOWN;
539 OvsRemoveAndDeleteVport(NULL, switchContext, vport, FALSE, TRUE);
540 OvsPostEvent(&event);
541 }
542
c803536e 543 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
9be4a837
NR
544
545 /*
546 * XXX: Not sure what kind of event to post here. DPIF is not interested in
547 * changes to MAC address. Netdev-windows might be intrested, though.
548 * That said, if the name chagnes, not clear what kind of event to be
549 * posted. We might have to delete the vport, and have userspace recreate
550 * it.
551 */
552
c803536e
SS
553update_nic_done:
554 VPORT_NIC_EXIT(nicParam);
555}
556
958227c6
NR
557/*
558 * --------------------------------------------------------------------------
559 * Function to process disconnect event of a NIC on the Hyper-V switch.
560 * --------------------------------------------------------------------------
561 */
c803536e 562VOID
fa048323
AS
563HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
564 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
c803536e
SS
565{
566 POVS_VPORT_ENTRY vport;
c803536e
SS
567 LOCK_STATE_EX lockState;
568 BOOLEAN isInternalPort = FALSE;
9be4a837 569 OVS_EVENT_ENTRY event;
c803536e
SS
570
571 VPORT_NIC_ENTER(nicParam);
572
573 /* Wait for lists to be initialized. */
574 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
575
576 if (!switchContext->isActivated) {
577 OVS_LOG_WARN("Switch is not activated yet.");
578 goto done;
579 }
580
581 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
582 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
583 nicParam->PortId,
584 nicParam->NicIndex);
585
586 if (!vport) {
587 OVS_LOG_WARN("Vport not present.");
588 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
589 goto done;
590 }
591
592 vport->nicState = NdisSwitchNicStateDisconnected;
593 vport->ovsState = OVS_STATE_NIC_CREATED;
c803536e 594
e00afcf6 595 if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
c803536e
SS
596 isInternalPort = TRUE;
597 }
598
9be4a837
NR
599 event.portNo = vport->portNo;
600 event.ovsType = vport->ovsType;
601 event.upcallPid = vport->upcallPid;
602 RtlCopyMemory(&event.ovsName, &vport->ovsName, sizeof event.ovsName);
603 event.type = OVS_EVENT_LINK_DOWN;
604
9be4a837
NR
605 /*
606 * Delete the port from the hash tables accessible to userspace. After this
607 * point, userspace should not be able to access this port.
608 */
d49b001d
NR
609 if (OvsIsRealExternalVport(vport)) {
610 OvsRemoveAndDeleteVport(NULL, switchContext, vport, FALSE, TRUE);
611 OvsPostEvent(&event);
612 }
613 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
c803536e
SS
614
615 if (isInternalPort) {
616 OvsInternalAdapterDown();
617 }
618
619done:
620 VPORT_NIC_EXIT(nicParam);
621}
622
958227c6
NR
623/*
624 * --------------------------------------------------------------------------
625 * Function to process delete event of a NIC on the Hyper-V switch.
626 * --------------------------------------------------------------------------
627 */
c803536e 628VOID
fa048323
AS
629HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
630 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
c803536e
SS
631{
632 LOCK_STATE_EX lockState;
633 POVS_VPORT_ENTRY vport;
c803536e
SS
634
635 VPORT_NIC_ENTER(nicParam);
636 /* Wait for lists to be initialized. */
637 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
638
639 if (!switchContext->isActivated) {
640 OVS_LOG_WARN("Switch is not activated yet.");
641 goto done;
642 }
643
644 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
645 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
646 nicParam->PortId,
647 nicParam->NicIndex);
648
649 if (!vport) {
650 OVS_LOG_WARN("Vport not present.");
651 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
652 goto done;
653 }
654
5e82ceef
SV
655 vport->nicState = NdisSwitchNicStateUnknown;
656 vport->ovsState = OVS_STATE_PORT_CREATED;
657
d49b001d
NR
658 if (OvsIsRealExternalVport(vport)) {
659 /* This vport was created in HvCreateNic(). */
5e82ceef 660 OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, FALSE);
c803536e 661 }
c803536e
SS
662
663 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
c803536e
SS
664
665done:
666 VPORT_NIC_EXIT(nicParam);
667}
668
c803536e
SS
669/*
670 * OVS Vport related functionality.
671 */
672POVS_VPORT_ENTRY
673OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
674 UINT32 portNo)
675{
429d4556
AS
676 POVS_VPORT_ENTRY vport;
677 PLIST_ENTRY head, link;
678 UINT32 hash = OvsJhashBytes((const VOID *)&portNo, sizeof(portNo),
679 OVS_HASH_BASIS);
680 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
681 LIST_FORALL(head, link) {
682 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
683 if (vport->portNo == portNo) {
684 return vport;
c803536e
SS
685 }
686 }
687 return NULL;
688}
689
690
ffde5f8f 691POVS_VPORT_ENTRY
885b8265
NR
692OvsFindTunnelVportByDstPortAndType(POVS_SWITCH_CONTEXT switchContext,
693 UINT16 dstPort,
694 OVS_VPORT_TYPE ovsPortType)
ffde5f8f
SV
695{
696 POVS_VPORT_ENTRY vport;
697 PLIST_ENTRY head, link;
698 UINT32 hash = OvsJhashBytes((const VOID *)&dstPort, sizeof(dstPort),
699 OVS_HASH_BASIS);
700 head = &(switchContext->tunnelVportsArray[hash & OVS_VPORT_MASK]);
701 LIST_FORALL(head, link) {
702 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, tunnelVportLink);
022c2040
EE
703 if (GetPortFromPriv(vport) == dstPort &&
704 vport->ovsType == ovsPortType) {
ffde5f8f
SV
705 return vport;
706 }
707 }
708 return NULL;
709}
710
885b8265
NR
711POVS_VPORT_ENTRY
712OvsFindTunnelVportByDstPortAndNWProto(POVS_SWITCH_CONTEXT switchContext,
713 UINT16 dstPort,
714 UINT8 nwProto)
715{
716 POVS_VPORT_ENTRY vport;
717 PLIST_ENTRY head, link;
718 UINT32 hash = OvsJhashBytes((const VOID *)&dstPort, sizeof(dstPort),
719 OVS_HASH_BASIS);
720 head = &(switchContext->tunnelVportsArray[hash & OVS_VPORT_MASK]);
721 LIST_FORALL(head, link) {
722 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, tunnelVportLink);
723 if (GetPortFromPriv(vport) == dstPort) {
724 switch (nwProto) {
725 case IPPROTO_UDP:
726 if (vport->ovsType != OVS_VPORT_TYPE_VXLAN) {
727 continue;
728 }
729 break;
730 case IPPROTO_TCP:
731 if (vport->ovsType != OVS_VPORT_TYPE_STT) {
732 continue;
733 }
734 break;
735 case IPPROTO_GRE:
736 break;
737 default:
738 continue;
739 }
740 return vport;
741 }
742 }
743 return NULL;
744}
745
85571a3d
AS
746POVS_VPORT_ENTRY
747OvsFindTunnelVportByPortType(POVS_SWITCH_CONTEXT switchContext,
748 OVS_VPORT_TYPE ovsPortType)
749{
750 POVS_VPORT_ENTRY vport;
751 PLIST_ENTRY head, link;
752 UINT16 dstPort = 0;
753 UINT32 hash = OvsJhashBytes((const VOID *)&dstPort, sizeof(dstPort),
754 OVS_HASH_BASIS);
755 head = &(switchContext->tunnelVportsArray[hash & OVS_VPORT_MASK]);
756 LIST_FORALL(head, link) {
757 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, tunnelVportLink);
758 if (vport->ovsType == ovsPortType) {
759 return vport;
760 }
761 }
762 return NULL;
763}
ffde5f8f 764
c803536e
SS
765POVS_VPORT_ENTRY
766OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
8d9f1e0c 767 PSTR name)
c803536e
SS
768{
769 POVS_VPORT_ENTRY vport;
770 PLIST_ENTRY head, link;
8d9f1e0c
NR
771 UINT32 hash;
772 SIZE_T length = strlen(name) + 1;
773
774 hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
147c91db 775 head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
8d9f1e0c 776
c803536e 777 LIST_FORALL(head, link) {
147c91db 778 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
8d9f1e0c 779 if (!strcmp(name, vport->ovsName)) {
c803536e
SS
780 return vport;
781 }
782 }
8d9f1e0c 783
c803536e
SS
784 return NULL;
785}
786
1b859c58
AS
787/* OvsFindVportByHvName: "name" is assumed to be null-terminated */
788POVS_VPORT_ENTRY
70e56250
NR
789OvsFindVportByHvNameW(POVS_SWITCH_CONTEXT switchContext,
790 PWSTR wsName, SIZE_T wstrSize)
1b859c58
AS
791{
792 POVS_VPORT_ENTRY vport = NULL;
793 PLIST_ENTRY head, link;
d752e054 794 UINT i;
1b859c58 795
d752e054 796 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
1b859c58
AS
797 head = &(switchContext->portIdHashArray[i]);
798 LIST_FORALL(head, link) {
799 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
800
801 /*
802 * NOTE about portFriendlyName:
803 * If the string is NULL-terminated, the Length member does not
804 * include the terminating NULL character.
805 */
806 if (vport->portFriendlyName.Length == wstrSize &&
807 RtlEqualMemory(wsName, vport->portFriendlyName.String,
808 vport->portFriendlyName.Length)) {
809 goto Cleanup;
810 }
811
812 vport = NULL;
813 }
814 }
815
25f44d58
NR
816 /*
817 * Look in the list of ports that were added from the Hyper-V switch and
818 * deleted.
819 */
820 if (vport == NULL) {
821 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
822 head = &(switchContext->portNoHashArray[i]);
823 LIST_FORALL(head, link) {
824 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
825 if (vport->portFriendlyName.Length == wstrSize &&
826 RtlEqualMemory(wsName, vport->portFriendlyName.String,
827 vport->portFriendlyName.Length)) {
828 goto Cleanup;
829 }
830
831 vport = NULL;
832 }
833 }
834 }
1b859c58 835
25f44d58 836Cleanup:
1b859c58
AS
837 return vport;
838}
839
70e56250
NR
840POVS_VPORT_ENTRY
841OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext,
842 PSTR name)
843{
844 POVS_VPORT_ENTRY vport = NULL;
845 /* 'portFriendlyName' is not NUL-terminated. */
846 SIZE_T length = strlen(name);
847 SIZE_T wstrSize = length * sizeof(WCHAR);
848 UINT i;
849
2be9ec26 850 PWSTR wsName = OvsAllocateMemoryWithTag(wstrSize, OVS_VPORT_POOL_TAG);
70e56250
NR
851 if (!wsName) {
852 return NULL;
853 }
854 for (i = 0; i < length; i++) {
855 wsName[i] = name[i];
856 }
857 vport = OvsFindVportByHvNameW(switchContext, wsName, wstrSize);
2be9ec26 858 OvsFreeMemoryWithTag(wsName, OVS_VPORT_POOL_TAG);
70e56250
NR
859 return vport;
860}
827e07be 861
c803536e
SS
862POVS_VPORT_ENTRY
863OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
864 NDIS_SWITCH_PORT_ID portId,
865 NDIS_SWITCH_NIC_INDEX index)
866{
3aa40c83
NR
867 if (switchContext->virtualExternalVport &&
868 portId == switchContext->virtualExternalPortId &&
869 index == switchContext->virtualExternalVport->nicIndex) {
25e39a60 870 return (POVS_VPORT_ENTRY)switchContext->virtualExternalVport;
3aa40c83
NR
871 } else if (switchContext->internalVport &&
872 portId == switchContext->internalPortId &&
873 index == switchContext->internalVport->nicIndex) {
c803536e
SS
874 return (POVS_VPORT_ENTRY)switchContext->internalVport;
875 } else {
876 PLIST_ENTRY head, link;
877 POVS_VPORT_ENTRY vport;
878 UINT32 hash;
879 hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
91c261cd 880 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
c803536e 881 LIST_FORALL(head, link) {
91c261cd 882 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
c803536e
SS
883 if (portId == vport->portId && index == vport->nicIndex) {
884 return vport;
885 }
886 }
887 return NULL;
888 }
889}
890
8d9f1e0c 891POVS_VPORT_ENTRY
c803536e
SS
892OvsAllocateVport(VOID)
893{
894 POVS_VPORT_ENTRY vport;
2be9ec26
SV
895 vport = (POVS_VPORT_ENTRY)OvsAllocateMemoryWithTag(
896 sizeof(OVS_VPORT_ENTRY), OVS_VPORT_POOL_TAG);
c803536e
SS
897 if (vport == NULL) {
898 return NULL;
899 }
900 RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
901 vport->ovsState = OVS_STATE_UNKNOWN;
421e2422 902 vport->isAbsentOnHv = FALSE;
429d4556
AS
903 vport->portNo = OVS_DPPORT_NUMBER_INVALID;
904
905 InitializeListHead(&vport->ovsNameLink);
906 InitializeListHead(&vport->portIdLink);
907 InitializeListHead(&vport->portNoLink);
908
c803536e
SS
909 return vport;
910}
911
912static VOID
913OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
914 PNDIS_SWITCH_PORT_PARAMETERS portParam)
915{
c803536e
SS
916 vport->portType = portParam->PortType;
917 vport->portState = portParam->PortState;
918 vport->portId = portParam->PortId;
919 vport->nicState = NdisSwitchNicStateUnknown;
e00afcf6 920 vport->isExternal = FALSE;
f1613007 921 vport->isBridgeInternal = FALSE;
c803536e
SS
922
923 switch (vport->portType) {
924 case NdisSwitchPortTypeExternal:
e00afcf6
SG
925 vport->isExternal = TRUE;
926 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
c803536e
SS
927 break;
928 case NdisSwitchPortTypeInternal:
e00afcf6 929 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
c803536e
SS
930 break;
931 case NdisSwitchPortTypeSynthetic:
c803536e 932 case NdisSwitchPortTypeEmulated:
e00afcf6 933 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
c803536e
SS
934 break;
935 }
1b859c58 936 RtlCopyMemory(&vport->hvPortName, &portParam->PortName,
c803536e 937 sizeof (NDIS_SWITCH_PORT_NAME));
f1613007
NR
938 /* For external and internal ports, 'portFriendlyName' is overwritten
939 * later. */
1b859c58
AS
940 RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName,
941 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
942
c803536e
SS
943 switch (vport->portState) {
944 case NdisSwitchPortStateCreated:
945 vport->ovsState = OVS_STATE_PORT_CREATED;
946 break;
947 case NdisSwitchPortStateTeardown:
948 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
949 break;
950 case NdisSwitchPortStateDeleted:
951 vport->ovsState = OVS_STATE_PORT_DELETED;
952 break;
953 }
954}
955
956
957static VOID
958OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
959 POVS_VPORT_ENTRY vport,
960 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
961{
962 ASSERT(vport->portId == nicParam->PortId);
963 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
964
965 UNREFERENCED_PARAMETER(switchContext);
966
967 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
7f796a85 968 sizeof (vport->permMacAddress));
c803536e 969 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
7f796a85 970 sizeof (vport->currMacAddress));
c803536e
SS
971
972 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
973 nicParam->NicType == NdisSwitchNicTypeEmulated) {
974 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
7f796a85 975 sizeof (vport->vmMacAddress));
c803536e
SS
976 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
977 sizeof (nicParam->VmName));
978 } else {
979 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
980 sizeof (nicParam->NetCfgInstanceId));
981 }
982 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
983 sizeof (nicParam->NicName));
984 vport->mtu = nicParam->MTU;
985 vport->nicState = nicParam->NicState;
986 vport->nicIndex = nicParam->NicIndex;
d49b001d 987 vport->nicType = nicParam->NicType;
c803536e
SS
988 vport->numaNodeId = nicParam->NumaNodeId;
989
990 switch (vport->nicState) {
991 case NdisSwitchNicStateCreated:
992 vport->ovsState = OVS_STATE_NIC_CREATED;
993 break;
994 case NdisSwitchNicStateConnected:
995 vport->ovsState = OVS_STATE_CONNECTED;
996 break;
997 case NdisSwitchNicStateDisconnected:
998 vport->ovsState = OVS_STATE_NIC_CREATED;
999 break;
1000 case NdisSwitchNicStateDeleted:
1001 vport->ovsState = OVS_STATE_PORT_CREATED;
1002 break;
1003 }
1004}
1005
f1613007
NR
1006/*
1007 * --------------------------------------------------------------------------
958227c6 1008 * Populates 'portParam' based on 'vport'.
f1613007
NR
1009 * --------------------------------------------------------------------------
1010 */
c803536e 1011static VOID
958227c6
NR
1012OvsCopyPortParamsFromVport(POVS_VPORT_ENTRY vport,
1013 PNDIS_SWITCH_PORT_PARAMETERS portParam)
c803536e 1014{
958227c6
NR
1015 portParam->Flags = 0;
1016 portParam->PortId = vport->portId;
1017 RtlCopyMemory(&portParam->PortName, &vport->hvPortName,
c803536e 1018 sizeof (NDIS_SWITCH_PORT_NAME));
958227c6
NR
1019 RtlCopyMemory(&portParam->PortFriendlyName,
1020 &vport->portFriendlyName,
1b859c58 1021 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
958227c6
NR
1022 portParam->PortType = vport->portType;
1023 portParam->IsValidationPort = FALSE;
1024 portParam->PortState = vport->portState;
c803536e 1025}
8d9f1e0c 1026
b3b8a9c3
NR
1027/*
1028 * --------------------------------------------------------------------------
1029 * Initializes a tunnel vport.
1030 * --------------------------------------------------------------------------
1031 */
1032NTSTATUS
5e82ceef
SV
1033OvsInitTunnelVport(PVOID userContext,
1034 POVS_VPORT_ENTRY vport,
b3b8a9c3
NR
1035 OVS_VPORT_TYPE ovsType,
1036 UINT16 dstPort)
1037{
1038 NTSTATUS status = STATUS_SUCCESS;
5e82ceef
SV
1039 POVS_USER_PARAMS_CONTEXT usrParamsCtx =
1040 (POVS_USER_PARAMS_CONTEXT)userContext;
b3b8a9c3 1041
b3b8a9c3
NR
1042 vport->isBridgeInternal = FALSE;
1043 vport->ovsType = ovsType;
1044 vport->ovsState = OVS_STATE_PORT_CREATED;
1045 switch (ovsType) {
1046 case OVS_VPORT_TYPE_GRE:
85571a3d 1047 status = OvsInitGreTunnel(vport);
b3b8a9c3 1048 break;
b3b8a9c3 1049 case OVS_VPORT_TYPE_VXLAN:
5e82ceef
SV
1050 {
1051 POVS_TUNFLT_INIT_CONTEXT tunnelContext = NULL;
1052
1d3950e9
SV
1053 tunnelContext = OvsAllocateMemoryWithTag(sizeof(*tunnelContext),
1054 OVS_VPORT_POOL_TAG);
5e82ceef
SV
1055 if (tunnelContext == NULL) {
1056 status = STATUS_INSUFFICIENT_RESOURCES;
1057 break;
1058 }
1059 tunnelContext->inputBuffer = usrParamsCtx->inputBuffer;
1060 tunnelContext->outputBuffer = usrParamsCtx->outputBuffer;
1061 tunnelContext->outputLength = usrParamsCtx->outputLength;
1062 tunnelContext->vport = vport;
1063
1064 status = OvsInitVxlanTunnel(usrParamsCtx->irp,
1065 vport,
1066 dstPort,
1067 OvsTunnelVportPendingInit,
1068 (PVOID)tunnelContext);
1d3950e9
SV
1069 if (status != STATUS_PENDING) {
1070 OvsFreeMemoryWithTag(tunnelContext, OVS_VPORT_POOL_TAG);
1071 tunnelContext = NULL;
1072 }
b3b8a9c3 1073 break;
5e82ceef 1074 }
022c2040
EE
1075 case OVS_VPORT_TYPE_STT:
1076 status = OvsInitSttTunnel(vport, dstPort);
1077 break;
b3b8a9c3
NR
1078 default:
1079 ASSERT(0);
1080 }
1081 return status;
1082}
1083
1084/*
1085 * --------------------------------------------------------------------------
1086 * Initializes a bridge internal vport ie. a port of type
1087 * OVS_VPORT_TYPE_INTERNAL but not present on the Hyper-V switch.
1088 * --------------------------------------------------------------------------
1089 */
1090NTSTATUS
1091OvsInitBridgeInternalVport(POVS_VPORT_ENTRY vport)
1092{
1093 vport->isBridgeInternal = TRUE;
1094 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
1095 /* Mark the status to be connected, since there is no other initialization
1096 * for this port. */
1097 vport->ovsState = OVS_STATE_CONNECTED;
1098 return STATUS_SUCCESS;
1099}
1100
f1613007
NR
1101/*
1102 * --------------------------------------------------------------------------
7845b703
SV
1103 * For external and internal vports 'portFriendlyName' parameter, provided by
1104 * Hyper-V, is overwritten with the interface alias name.
f1613007
NR
1105 * --------------------------------------------------------------------------
1106 */
34be96ca
NR
1107static NTSTATUS
1108GetNICAlias(GUID *netCfgInstanceId,
1109 IF_COUNTED_STRING *portFriendlyName)
f1613007 1110{
e6d25999
NR
1111 NTSTATUS status;
1112 WCHAR interfaceName[IF_MAX_STRING_SIZE + 1];
1113 NET_LUID interfaceLuid;
1114 size_t len;
f1613007 1115
34be96ca 1116 status = ConvertInterfaceGuidToLuid(netCfgInstanceId,
7845b703
SV
1117 &interfaceLuid);
1118 if (status == STATUS_SUCCESS) {
13165df9
NR
1119 /*
1120 * Must be called from PASSIVE_LEVEL. Resulted in a
1121 * STATUS_INVALID_DEVICE_REQUEST if not.
1122 */
7845b703
SV
1123 status = ConvertInterfaceLuidToAlias(&interfaceLuid, interfaceName,
1124 IF_MAX_STRING_SIZE + 1);
1125 if (status == STATUS_SUCCESS) {
34be96ca
NR
1126 RtlStringCbPrintfW(portFriendlyName->String,
1127 IF_MAX_STRING_SIZE, L"%s", interfaceName);
1128 RtlStringCbLengthW(portFriendlyName->String, IF_MAX_STRING_SIZE,
7845b703 1129 &len);
34be96ca 1130 portFriendlyName->Length = (USHORT)len;
f1613007 1131 } else {
34be96ca 1132 OVS_LOG_ERROR("Fail to convert interface LUID to alias, status: %x",
7845b703 1133 status);
f1613007
NR
1134 }
1135 } else {
34be96ca 1136 OVS_LOG_ERROR("Fail to convert interface GUID to LUID, status: %x",
7845b703 1137 status);
f1613007 1138 }
34be96ca
NR
1139
1140 return status;
f1613007
NR
1141}
1142
1143
1144/*
1145 * --------------------------------------------------------------------------
1146 * Functionality common to any port on the Hyper-V switch. This function is not
1147 * to be called for a port that is not on the Hyper-V switch.
1148 *
1149 * Inserts the port into 'portIdHashArray' and caches the pointer in the
1150 * 'switchContext' if needed.
f1613007
NR
1151 * --------------------------------------------------------------------------
1152 */
958227c6
NR
1153static VOID
1154UpdateSwitchCtxWithVport(POVS_SWITCH_CONTEXT switchContext,
1155 POVS_VPORT_ENTRY vport,
1156 BOOLEAN newPort)
c803536e
SS
1157{
1158 UINT32 hash;
c803536e 1159
c803536e
SS
1160 switch (vport->portType) {
1161 case NdisSwitchPortTypeExternal:
1162 if (vport->nicIndex == 0) {
25e39a60
NR
1163 switchContext->virtualExternalPortId = vport->portId;
1164 switchContext->virtualExternalVport = vport;
429d4556 1165 } else {
c803536e 1166 switchContext->numPhysicalNics++;
c803536e
SS
1167 }
1168 break;
1169 case NdisSwitchPortTypeInternal:
f1613007 1170 ASSERT(vport->isBridgeInternal == FALSE);
c803536e
SS
1171 switchContext->internalPortId = vport->portId;
1172 switchContext->internalVport = vport;
c803536e
SS
1173 break;
1174 case NdisSwitchPortTypeSynthetic:
c803536e 1175 case NdisSwitchPortTypeEmulated:
c803536e
SS
1176 break;
1177 }
429d4556 1178
f1613007
NR
1179 /*
1180 * It is important to not insert vport corresponding to virtual external
1181 * port into the 'portIdHashArray' since the port should not be exposed to
1182 * OVS userspace.
1183 */
c803536e
SS
1184 if (vport->portType == NdisSwitchPortTypeExternal &&
1185 vport->nicIndex == 0) {
958227c6 1186 return;
c803536e 1187 }
429d4556
AS
1188
1189 /*
1190 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
1191 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
1192 * hyper-v switch seems to use only 2 bytes out of 4.
1193 */
c803536e 1194 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
91c261cd
AS
1195 InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK],
1196 &vport->portIdLink);
827e07be
NR
1197 if (newPort) {
1198 switchContext->numHvVports++;
1199 }
958227c6 1200 return;
c803536e
SS
1201}
1202
f1613007
NR
1203/*
1204 * --------------------------------------------------------------------------
1205 * Functionality common to any port added from OVS userspace.
1206 *
ffde5f8f
SV
1207 * Inserts the port into 'portNoHashArray', 'ovsPortNameHashArray' and in
1208 * 'tunnelVportsArray' if appropriate.
f1613007
NR
1209 * --------------------------------------------------------------------------
1210 */
1211NDIS_STATUS
1212InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext,
1213 POVS_VPORT_ENTRY vport)
1214{
1215 UINT32 hash;
1216
1217 switch(vport->ovsType) {
85571a3d 1218 case OVS_VPORT_TYPE_GRE:
f1613007 1219 case OVS_VPORT_TYPE_VXLAN:
022c2040 1220 case OVS_VPORT_TYPE_STT:
ffde5f8f 1221 {
022c2040
EE
1222 UINT16 dstPort = GetPortFromPriv(vport);
1223 hash = OvsJhashBytes(&dstPort,
1224 sizeof(dstPort),
ffde5f8f
SV
1225 OVS_HASH_BASIS);
1226 InsertHeadList(
1227 &gOvsSwitchContext->tunnelVportsArray[hash & OVS_VPORT_MASK],
1228 &vport->tunnelVportLink);
f1613007
NR
1229 switchContext->numNonHvVports++;
1230 break;
ffde5f8f 1231 }
35f20164
NR
1232 case OVS_VPORT_TYPE_INTERNAL:
1233 if (vport->isBridgeInternal) {
1234 switchContext->numNonHvVports++;
1235 }
f1613007
NR
1236 default:
1237 break;
1238 }
1239
1240 /*
1241 * Insert the port into the hash array of ports: by port number and ovs
1242 * and ovs (datapath) port name.
1243 * NOTE: OvsJhashWords has portNo as "1" word. This is ok, because the
1244 * portNo is stored in 2 bytes only (max port number = MAXUINT16).
1245 */
1246 hash = OvsJhashWords(&vport->portNo, 1, OVS_HASH_BASIS);
1247 InsertHeadList(&gOvsSwitchContext->portNoHashArray[hash & OVS_VPORT_MASK],
1248 &vport->portNoLink);
1249
1250 hash = OvsJhashBytes(vport->ovsName, strlen(vport->ovsName) + 1,
1251 OVS_HASH_BASIS);
827e07be
NR
1252 InsertHeadList(
1253 &gOvsSwitchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK],
1254 &vport->ovsNameLink);
f1613007
NR
1255
1256 return STATUS_SUCCESS;
1257}
1258
b8155080
NR
1259
1260/*
1261 * --------------------------------------------------------------------------
1262 * Provides functionality that is partly complementatry to
958227c6 1263 * InitOvsVportCommon()/UpdateSwitchCtxWithVport().
b8155080
NR
1264 *
1265 * 'hvDelete' indicates if caller is removing the vport as a result of the
1266 * port being removed on the Hyper-V switch.
1267 * 'ovsDelete' indicates if caller is removing the vport as a result of the
1268 * port being removed from OVS userspace.
1269 * --------------------------------------------------------------------------
1270 */
1271NTSTATUS
1272OvsRemoveAndDeleteVport(PVOID usrParamsContext,
1273 POVS_SWITCH_CONTEXT switchContext,
1274 POVS_VPORT_ENTRY vport,
1275 BOOLEAN hvDelete,
1276 BOOLEAN ovsDelete)
5e82ceef 1277{
b8155080
NR
1278 POVS_USER_PARAMS_CONTEXT usrParamsCtx =
1279 (POVS_USER_PARAMS_CONTEXT)usrParamsContext;
1280 BOOLEAN hvSwitchPort = FALSE;
5e82ceef
SV
1281 BOOLEAN deletedOnOvs = FALSE;
1282 BOOLEAN deletedOnHv = FALSE;
1283
b8155080
NR
1284 switch (vport->ovsType) {
1285 case OVS_VPORT_TYPE_INTERNAL:
1286 if (!vport->isBridgeInternal) {
421e2422 1287 if (hvDelete && vport->isAbsentOnHv == FALSE) {
b8155080
NR
1288 switchContext->internalPortId = 0;
1289 switchContext->internalVport = NULL;
1290 OvsInternalAdapterDown();
1291 }
1292 hvSwitchPort = TRUE;
1293 }
1294 break;
1295 case OVS_VPORT_TYPE_VXLAN:
1296 {
1297 NTSTATUS status;
1298 status = OvsRemoveTunnelVport(usrParamsCtx, switchContext, vport,
1299 hvDelete, ovsDelete);
1300 if (status != STATUS_SUCCESS) {
1301 return status;
1302 }
1303 }
1304 case OVS_VPORT_TYPE_STT:
1305 OvsCleanupSttTunnel(vport);
1306 break;
1307 case OVS_VPORT_TYPE_GRE:
85571a3d 1308 OvsCleanupGreTunnel(vport);
b8155080
NR
1309 break;
1310 case OVS_VPORT_TYPE_NETDEV:
1311 if (vport->isExternal) {
1312 if (vport->nicIndex == 0) {
1313 /* Such a vport is not part of any of the hash tables, since it
1314 * is not exposed to userspace. See Vport.h for explanation. */
1315 ASSERT(hvDelete == TRUE);
1316 ASSERT(switchContext->numPhysicalNics == 0);
1317 switchContext->virtualExternalPortId = 0;
1318 switchContext->virtualExternalVport = NULL;
1319 OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
1320 return STATUS_SUCCESS;
1321 }
1322 }
1323 hvSwitchPort = TRUE;
1324 default:
1325 break;
1326 }
1327
5e82ceef
SV
1328 /*
1329 * 'hvDelete' == TRUE indicates that the port should be removed from the
1330 * 'portIdHashArray', while 'ovsDelete' == TRUE indicates that the port
1331 * should be removed from 'portNoHashArray' and the 'ovsPortNameHashArray'.
1332 *
1333 * Both 'hvDelete' and 'ovsDelete' can be set to TRUE by the caller.
1334 */
421e2422 1335 if (vport->isAbsentOnHv == TRUE) {
5e82ceef
SV
1336 deletedOnHv = TRUE;
1337 }
1338 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
1339 deletedOnOvs = TRUE;
1340 }
1341
1342 if (hvDelete && !deletedOnHv) {
421e2422 1343 vport->isAbsentOnHv = TRUE;
5e82ceef 1344
b8155080
NR
1345 if (vport->isExternal) {
1346 ASSERT(vport->nicIndex != 0);
1347 ASSERT(switchContext->numPhysicalNics);
1348 switchContext->numPhysicalNics--;
1349 }
1350
5e82ceef
SV
1351 /* Remove the port from the relevant lists. */
1352 RemoveEntryList(&vport->portIdLink);
1353 InitializeListHead(&vport->portIdLink);
1354 deletedOnHv = TRUE;
1355 }
1356 if (ovsDelete && !deletedOnOvs) {
1357 vport->portNo = OVS_DPPORT_NUMBER_INVALID;
1358 vport->ovsName[0] = '\0';
1359
1360 /* Remove the port from the relevant lists. */
1361 RemoveEntryList(&vport->ovsNameLink);
1362 InitializeListHead(&vport->ovsNameLink);
1363 RemoveEntryList(&vport->portNoLink);
1364 InitializeListHead(&vport->portNoLink);
022c2040 1365 if (OVS_VPORT_TYPE_VXLAN == vport->ovsType ||
85571a3d
AS
1366 OVS_VPORT_TYPE_STT == vport->ovsType ||
1367 OVS_VPORT_TYPE_GRE == vport->ovsType) {
ffde5f8f
SV
1368 RemoveEntryList(&vport->tunnelVportLink);
1369 InitializeListHead(&vport->tunnelVportLink);
1370 }
1371
5e82ceef
SV
1372 deletedOnOvs = TRUE;
1373 }
1374
1375 /*
1376 * Deallocate the port if it has been deleted on the Hyper-V switch as well
1377 * as OVS userspace.
1378 */
1379 if (deletedOnHv && deletedOnOvs) {
1380 if (hvSwitchPort) {
1381 switchContext->numHvVports--;
b8155080 1382 } else {
5e82ceef
SV
1383 switchContext->numNonHvVports--;
1384 }
1385 OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
1386 }
b8155080
NR
1387
1388 return STATUS_SUCCESS;
5e82ceef 1389}
f1613007 1390
b8155080
NR
1391static NTSTATUS
1392OvsRemoveTunnelVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1393 POVS_SWITCH_CONTEXT switchContext,
1394 POVS_VPORT_ENTRY vport,
1395 BOOLEAN hvDelete,
1396 BOOLEAN ovsDelete)
c803536e 1397{
b8155080
NR
1398 POVS_TUNFLT_INIT_CONTEXT tunnelContext = NULL;
1399 PIRP irp = NULL;
f1613007 1400
cc474fad
SV
1401 tunnelContext = OvsAllocateMemoryWithTag(sizeof(*tunnelContext),
1402 OVS_VPORT_POOL_TAG);
b8155080
NR
1403 if (tunnelContext == NULL) {
1404 return STATUS_INSUFFICIENT_RESOURCES;
e00afcf6 1405 }
b8155080 1406 RtlZeroMemory(tunnelContext, sizeof(*tunnelContext));
e00afcf6 1407
b8155080
NR
1408 tunnelContext->switchContext = switchContext;
1409 tunnelContext->hvSwitchPort = FALSE;
1410 tunnelContext->hvDelete = hvDelete;
1411 tunnelContext->ovsDelete = ovsDelete;
1412 tunnelContext->vport = vport;
5e82ceef 1413
b8155080
NR
1414 if (usrParamsCtx) {
1415 tunnelContext->inputBuffer = usrParamsCtx->inputBuffer;
1416 tunnelContext->outputBuffer = usrParamsCtx->outputBuffer;
1417 tunnelContext->outputLength = usrParamsCtx->outputLength;
1418 irp = usrParamsCtx->irp;
c22f284b 1419 }
c22f284b 1420
b8155080
NR
1421 return OvsCleanupVxlanTunnel(irp, vport, OvsTunnelVportPendingRemove,
1422 tunnelContext);
c22f284b 1423}
c803536e 1424
13165df9
NR
1425/*
1426 * --------------------------------------------------------------------------
1427 * Enumerates the ports on the Hyper-V switch.
1428 * --------------------------------------------------------------------------
1429 */
c803536e
SS
1430NDIS_STATUS
1431OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
1432{
1433 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1434 ULONG arrIndex;
1435 PNDIS_SWITCH_PORT_PARAMETERS portParam;
1436 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
c803536e
SS
1437
1438 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
1439
1440 status = OvsGetPortsOnSwitch(switchContext, &portArray);
1441 if (status != NDIS_STATUS_SUCCESS) {
1442 goto cleanup;
1443 }
1444
1445 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
1446 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
c99e6500
AS
1447
1448 if (portParam->IsValidationPort) {
1449 continue;
1450 }
1451
958227c6 1452 status = HvCreatePort(switchContext, portParam, 0);
13165df9
NR
1453 if (status != STATUS_SUCCESS && status != STATUS_DATA_NOT_ACCEPTED) {
1454 break;
c803536e
SS
1455 }
1456 }
2be9ec26 1457
c803536e
SS
1458cleanup:
1459 if (status != NDIS_STATUS_SUCCESS) {
1460 OvsClearAllSwitchVports(switchContext);
1461 }
1462
2be9ec26
SV
1463 OvsFreeSwitchPortsArray(portArray);
1464
c803536e 1465 OVS_LOG_TRACE("Exit: status: %x", status);
2be9ec26 1466
c803536e
SS
1467 return status;
1468}
1469
13165df9
NR
1470/*
1471 * --------------------------------------------------------------------------
1472 * Enumerates the NICs on the Hyper-V switch.
1473 * --------------------------------------------------------------------------
1474 */
c803536e
SS
1475NDIS_STATUS
1476OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
1477{
1478 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1479 PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
1480 ULONG arrIndex;
1481 PNDIS_SWITCH_NIC_PARAMETERS nicParam;
c803536e
SS
1482
1483 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
1484 /*
1485 * Now, get NIC list.
1486 */
1487 status = OvsGetNicsOnSwitch(switchContext, &nicArray);
1488 if (status != NDIS_STATUS_SUCCESS) {
1489 goto cleanup;
1490 }
1491 for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
c803536e
SS
1492 nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
1493
1494 /*
1495 * XXX: Check if the port is configured with a VLAN. Disallow such a
1496 * configuration, since we don't support tag-in-tag.
c803536e
SS
1497 * XXX: Check if the port is connected to a VF. Disconnect the VF in
1498 * such a case.
1499 */
1500
13165df9
NR
1501 status = HvCreateNic(switchContext, nicParam);
1502 if (status == NDIS_STATUS_SUCCESS) {
1503 HvConnectNic(switchContext, nicParam);
c803536e
SS
1504 }
1505 }
1506cleanup:
1507
2be9ec26
SV
1508 OvsFreeSwitchNicsArray(nicArray);
1509
c803536e
SS
1510 OVS_LOG_TRACE("Exit: status: %x", status);
1511 return status;
1512}
1513
f1613007
NR
1514/*
1515 * --------------------------------------------------------------------------
1516 * Deletes ports added from the Hyper-V switch as well as OVS usersapce. The
1517 * function deletes ports in 'portIdHashArray'. This will delete most of the
1518 * ports that are in the 'portNoHashArray' as well. Any remaining ports
898dcef1 1519 * are deleted by walking the 'portNoHashArray'.
f1613007
NR
1520 * --------------------------------------------------------------------------
1521 */
c803536e
SS
1522VOID
1523OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
1524{
d752e054 1525 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
53165234 1526 PLIST_ENTRY head, link, next;
c803536e 1527
53165234
NR
1528 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
1529 LIST_FORALL_SAFE(head, link, next) {
429d4556 1530 POVS_VPORT_ENTRY vport;
53165234 1531 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
5e82ceef 1532 OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE);
c803536e
SS
1533 }
1534 }
ffde5f8f 1535
f1613007
NR
1536 /*
1537 * Remove 'virtualExternalVport' as well. This port is not part of the
1538 * 'portIdHashArray'.
1539 */
25e39a60 1540 if (switchContext->virtualExternalVport) {
5e82ceef
SV
1541 OvsRemoveAndDeleteVport(NULL, switchContext,
1542 (POVS_VPORT_ENTRY)switchContext->virtualExternalVport, TRUE, TRUE);
c803536e 1543 }
f1613007 1544
ffde5f8f 1545
f1613007
NR
1546 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
1547 PLIST_ENTRY head, link, next;
f1613007
NR
1548 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
1549 LIST_FORALL_SAFE(head, link, next) {
1550 POVS_VPORT_ENTRY vport;
1551 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
35f20164 1552 ASSERT(OvsIsTunnelVportType(vport->ovsType) ||
f1613007 1553 (vport->ovsType == OVS_VPORT_TYPE_INTERNAL &&
421e2422 1554 vport->isBridgeInternal) || vport->isAbsentOnHv == TRUE);
5e82ceef 1555 OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE);
f1613007
NR
1556 }
1557 }
1558
1559 ASSERT(switchContext->virtualExternalVport == NULL);
1560 ASSERT(switchContext->internalVport == NULL);
c803536e
SS
1561}
1562
c803536e 1563
c803536e
SS
1564NTSTATUS
1565OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
1566 CHAR *str,
1567 UINT16 maxStrLen)
1568{
1569 ANSI_STRING astr;
1570 UNICODE_STRING ustr;
1571 NTSTATUS status;
1572 UINT32 size;
1573
1574 ustr.Buffer = wStr->String;
1575 ustr.Length = wStr->Length;
1576 ustr.MaximumLength = IF_MAX_STRING_SIZE;
1577
1578 astr.Buffer = str;
1579 astr.MaximumLength = maxStrLen;
1580 astr.Length = 0;
1581
1582 size = RtlUnicodeStringToAnsiSize(&ustr);
1583 if (size > maxStrLen) {
1584 return STATUS_BUFFER_OVERFLOW;
1585 }
1586
1587 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
1588
1589 ASSERT(status == STATUS_SUCCESS);
1590 if (status != STATUS_SUCCESS) {
1591 return status;
1592 }
1593 ASSERT(astr.Length <= maxStrLen);
1594 str[astr.Length] = 0;
1595 return STATUS_SUCCESS;
1596}
1597
2ba81132
NR
1598/*
1599 * --------------------------------------------------------------------------
1600 * Utility function that populates a 'OVS_VPORT_EXT_INFO' structure for the
1601 * specified vport.
2ba81132
NR
1602 * --------------------------------------------------------------------------
1603 */
c803536e 1604NTSTATUS
be581675
NR
1605OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
1606 POVS_VPORT_EXT_INFO extInfo)
c803536e 1607{
c803536e
SS
1608 POVS_VPORT_ENTRY vport;
1609 size_t len;
1610 LOCK_STATE_EX lockState;
1611 NTSTATUS status = STATUS_SUCCESS;
c803536e
SS
1612 BOOLEAN doConvert = FALSE;
1613
be581675 1614 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
3ed424e5 1615 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
be581675
NR
1616 if (vportGet->portNo == 0) {
1617 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
70e56250 1618 vport = OvsFindVportByHvNameA(gOvsSwitchContext, vportGet->name);
f3e4015f 1619 if (vport == NULL) {
2ba81132
NR
1620 /* If the port is not a Hyper-V port and it has been added earlier,
1621 * we'll find it in 'ovsPortNameHashArray'. */
1622 vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name);
1623 }
c803536e 1624 } else {
be581675 1625 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
c803536e
SS
1626 }
1627 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1628 vport->ovsState != OVS_STATE_NIC_CREATED)) {
1629 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
be581675
NR
1630 if (vportGet->portNo) {
1631 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
c803536e 1632 } else {
be581675 1633 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
c803536e
SS
1634 }
1635 status = STATUS_DEVICE_DOES_NOT_EXIST;
1636 goto ext_info_done;
1637 }
be581675
NR
1638 extInfo->dpNo = vportGet->dpNo;
1639 extInfo->portNo = vport->portNo;
1640 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
c803536e 1641 sizeof (vport->currMacAddress));
be581675 1642 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
c803536e 1643 sizeof (vport->permMacAddress));
e00afcf6 1644 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
be581675 1645 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
c803536e
SS
1646 sizeof (vport->vmMacAddress));
1647 }
be581675
NR
1648 extInfo->nicIndex = vport->nicIndex;
1649 extInfo->portId = vport->portId;
1650 extInfo->type = vport->ovsType;
1651 extInfo->mtu = vport->mtu;
c803536e
SS
1652 /*
1653 * TO be revisit XXX
1654 */
1655 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
be581675 1656 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
c803536e 1657 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
be581675 1658 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
c803536e 1659 } else {
be581675 1660 extInfo->status = OVS_EVENT_DISCONNECT;
c803536e 1661 }
be581675 1662 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
c803536e
SS
1663 (vport->ovsState == OVS_STATE_NIC_CREATED ||
1664 vport->ovsState == OVS_STATE_CONNECTED)) {
c803536e
SS
1665 doConvert = TRUE;
1666 } else {
be581675
NR
1667 extInfo->vmUUID[0] = 0;
1668 extInfo->vifUUID[0] = 0;
c803536e 1669 }
c803536e 1670 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
c803536e 1671 if (doConvert) {
d8cecf58
NR
1672 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1673 extInfo->name,
1674 OVS_MAX_PORT_NAME_LENGTH);
1675 if (status != STATUS_SUCCESS) {
1676 OVS_LOG_INFO("Fail to convert NIC name.");
b243ee29 1677 extInfo->name[0] = 0;
d8cecf58 1678 }
d8cecf58
NR
1679
1680 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
be581675 1681 extInfo->vmUUID,
c803536e
SS
1682 OVS_MAX_VM_UUID_LEN);
1683 if (status != STATUS_SUCCESS) {
1684 OVS_LOG_INFO("Fail to convert VM name.");
be581675 1685 extInfo->vmUUID[0] = 0;
c803536e
SS
1686 }
1687
d8cecf58 1688 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
be581675 1689 extInfo->vifUUID,
c803536e
SS
1690 OVS_MAX_VIF_UUID_LEN);
1691 if (status != STATUS_SUCCESS) {
d8cecf58 1692 OVS_LOG_INFO("Fail to convert nic UUID");
be581675 1693 extInfo->vifUUID[0] = 0;
c803536e
SS
1694 }
1695 /*
1696 * for now ignore status
1697 */
1698 status = STATUS_SUCCESS;
1699 }
c803536e
SS
1700
1701ext_info_done:
c803536e
SS
1702 return status;
1703}
be581675 1704
2b144cbb
NR
1705/*
1706 * --------------------------------------------------------------------------
1707 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1708 * --------------------------------------------------------------------------
1709 */
1710NTSTATUS
1711OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1712 UINT32 *replyLen)
1713{
be581675
NR
1714 NTSTATUS status = STATUS_SUCCESS;
1715 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1716 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1717 NL_ERROR nlError = NL_ERROR_SUCCESS;
1718 OVS_VPORT_GET vportGet;
1719 OVS_VPORT_EXT_INFO info;
be581675
NR
1720
1721 static const NL_POLICY ovsNetdevPolicy[] = {
1722 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1723 .minLen = 2,
1724 .maxLen = IFNAMSIZ },
1725 };
1726 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1727
1728 /* input buffer has been validated while validating transaction dev op. */
1729 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1730 usrParamsCtx->inputLength > sizeof *msgIn);
1731
1732 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1733 return STATUS_INVALID_BUFFER_SIZE;
1734 }
1735
1736 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1737 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1738 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
b8b00f0c
SV
1739 ovsNetdevPolicy, ARRAY_SIZE(ovsNetdevPolicy),
1740 netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
be581675
NR
1741 return STATUS_INVALID_PARAMETER;
1742 }
1743
be581675
NR
1744 vportGet.portNo = 0;
1745 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1746 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1747
be581675
NR
1748 status = OvsGetExtInfoIoctl(&vportGet, &info);
1749 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1750 nlError = NL_ERROR_NODEV;
be581675
NR
1751 goto cleanup;
1752 }
be581675
NR
1753
1754 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1755 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1756 gOvsSwitchContext->dpNo);
1757 if (status == STATUS_SUCCESS) {
1758 *replyLen = msgOut->nlMsg.nlmsgLen;
1759 }
be581675
NR
1760
1761cleanup:
1762 if (nlError != NL_ERROR_SUCCESS) {
1763 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1764 usrParamsCtx->outputBuffer;
1765
7e98ed23
NR
1766 ASSERT(msgError);
1767 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
1768 ASSERT(*replyLen != 0);
be581675
NR
1769 }
1770
1771 return STATUS_SUCCESS;
2b144cbb 1772}
c803536e
SS
1773
1774
be581675
NR
1775/*
1776 * --------------------------------------------------------------------------
1777 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1778 * OVS_MESSAGE contains the output of a netdev command.
1779 * --------------------------------------------------------------------------
1780 */
1781static NTSTATUS
1782CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1783 POVS_MESSAGE msgIn,
1784 PVOID outBuffer,
1785 UINT32 outBufLen,
1786 int dpIfIndex)
1787{
1788 NL_BUFFER nlBuffer;
1789 BOOLEAN ok;
be581675
NR
1790 PNL_MSG_HDR nlMsg;
1791 UINT32 netdevFlags = 0;
1792
1793 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1794
5fc8ea2d
NR
1795 ok = NlFillOvsMsg(&nlBuffer, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
1796 msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
1797 msgIn->genlMsg.cmd, msgIn->genlMsg.version,
1ad44ad4 1798 dpIfIndex);
be581675 1799 if (!ok) {
1ad44ad4 1800 return STATUS_INVALID_BUFFER_SIZE;
be581675
NR
1801 }
1802
1803 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1804 info->portNo);
1805 if (!ok) {
1ad44ad4 1806 return STATUS_INVALID_BUFFER_SIZE;
be581675
NR
1807 }
1808
1809 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1810 if (!ok) {
1ad44ad4 1811 return STATUS_INVALID_BUFFER_SIZE;
be581675
NR
1812 }
1813
1814 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1815 info->name);
1816 if (!ok) {
1ad44ad4 1817 return STATUS_INVALID_BUFFER_SIZE;
be581675
NR
1818 }
1819
1820 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1821 (PCHAR)info->macAddress, sizeof (info->macAddress));
1822 if (!ok) {
1ad44ad4 1823 return STATUS_INVALID_BUFFER_SIZE;
be581675
NR
1824 }
1825
1826 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1827 if (!ok) {
1ad44ad4 1828 return STATUS_INVALID_BUFFER_SIZE;
be581675
NR
1829 }
1830
1831 if (info->status != OVS_EVENT_CONNECT) {
1832 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1833 }
1834 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1835 netdevFlags);
1836 if (!ok) {
1ad44ad4 1837 return STATUS_INVALID_BUFFER_SIZE;
be581675
NR
1838 }
1839
1840 /*
1841 * XXX: add netdev_stats when we have the definition available in the
1842 * kernel.
1843 */
1844
1845 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1846 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1847
1848 return STATUS_SUCCESS;
1849}
1850
c803536e
SS
1851static __inline VOID
1852OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1853{
1854 while ((!switchContext->isActivated) &&
1855 (!switchContext->isActivateFailed)) {
1856 /* Wait for the switch to be active and
1857 * the list of ports in OVS to be initialized. */
1858 NdisMSleep(sleepMicroSec);
1859 }
1860}
012b5d13 1861
012b5d13
NR
1862static NTSTATUS
1863OvsCreateMsgFromVport(POVS_VPORT_ENTRY vport,
1864 POVS_MESSAGE msgIn,
1865 PVOID outBuffer,
1866 UINT32 outBufLen,
1867 int dpIfIndex)
1868{
1869 NL_BUFFER nlBuffer;
1870 OVS_VPORT_FULL_STATS vportStats;
1871 BOOLEAN ok;
012b5d13
NR
1872 PNL_MSG_HDR nlMsg;
1873
1874 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1875
5fc8ea2d
NR
1876 ok = NlFillOvsMsg(&nlBuffer, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
1877 msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
1878 msgIn->genlMsg.cmd, msgIn->genlMsg.version,
1ad44ad4 1879 dpIfIndex);
012b5d13 1880 if (!ok) {
1ad44ad4 1881 return STATUS_INVALID_BUFFER_SIZE;
012b5d13
NR
1882 }
1883
1884 ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_PORT_NO, vport->portNo);
1885 if (!ok) {
1ad44ad4 1886 return STATUS_INVALID_BUFFER_SIZE;
012b5d13
NR
1887 }
1888
1889 ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_TYPE, vport->ovsType);
1890 if (!ok) {
1ad44ad4 1891 return STATUS_INVALID_BUFFER_SIZE;
012b5d13
NR
1892 }
1893
1894 ok = NlMsgPutTailString(&nlBuffer, OVS_VPORT_ATTR_NAME, vport->ovsName);
1895 if (!ok) {
1ad44ad4 1896 return STATUS_INVALID_BUFFER_SIZE;
012b5d13
NR
1897 }
1898
1899 /*
1900 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1901 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1902 * it means we have an array of pids, instead of a single pid.
1903 * ATM we assume we have one pid only.
1904 */
1905
1906 ok = NlMsgPutTailU32(&nlBuffer, OVS_VPORT_ATTR_UPCALL_PID,
1907 vport->upcallPid);
1908 if (!ok) {
1ad44ad4 1909 return STATUS_INVALID_BUFFER_SIZE;
012b5d13
NR
1910 }
1911
1912 /*stats*/
1913 vportStats.rxPackets = vport->stats.rxPackets;
1914 vportStats.rxBytes = vport->stats.rxBytes;
1915 vportStats.txPackets = vport->stats.txPackets;
1916 vportStats.txBytes = vport->stats.txBytes;
1917 vportStats.rxErrors = vport->errStats.rxErrors;
1918 vportStats.txErrors = vport->errStats.txErrors;
1919 vportStats.rxDropped = vport->errStats.rxDropped;
1920 vportStats.txDropped = vport->errStats.txDropped;
1921
1922 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_VPORT_ATTR_STATS,
1923 (PCHAR)&vportStats,
1924 sizeof(OVS_VPORT_FULL_STATS));
1925 if (!ok) {
1ad44ad4 1926 return STATUS_INVALID_BUFFER_SIZE;
012b5d13
NR
1927 }
1928
1929 /*
1930 * XXX: when vxlan udp dest port becomes configurable, we will also need
1931 * to add vport options
1932 */
1933
1934 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1935 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1936
1937 return STATUS_SUCCESS;
1938}
1939
1940static NTSTATUS
1941OvsGetVportDumpNext(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1942 UINT32 *replyLen)
1943{
1944 POVS_MESSAGE msgIn;
1945 POVS_OPEN_INSTANCE instance =
1946 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1947 LOCK_STATE_EX lockState;
1948 UINT32 i = OVS_MAX_VPORT_ARRAY_SIZE;
1949
1950 /*
1951 * XXX: this function shares some code with other dump command(s).
1952 * In the future, we will need to refactor the dump functions
1953 */
1954
1955 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1956
1957 if (instance->dumpState.ovsMsg == NULL) {
1958 ASSERT(FALSE);
1959 return STATUS_INVALID_DEVICE_STATE;
1960 }
1961
1962 /* Output buffer has been validated while validating read dev op. */
1963 ASSERT(usrParamsCtx->outputBuffer != NULL);
1964
1965 msgIn = instance->dumpState.ovsMsg;
1966
012b5d13
NR
1967 /*
1968 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
1969 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
1970 * it means we have an array of pids, instead of a single pid.
1971 * ATM we assume we have one pid only.
1972 */
3ed424e5 1973 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
012b5d13
NR
1974
1975 if (gOvsSwitchContext->numHvVports > 0 ||
1976 gOvsSwitchContext->numNonHvVports > 0) {
1977 /* inBucket: the bucket, used for lookup */
1978 UINT32 inBucket = instance->dumpState.index[0];
1979 /* inIndex: index within the given bucket, used for lookup */
1980 UINT32 inIndex = instance->dumpState.index[1];
1981 /* the bucket to be used for the next dump operation */
1982 UINT32 outBucket = 0;
1983 /* the index within the outBucket to be used for the next dump */
1984 UINT32 outIndex = 0;
1985
1986 for (i = inBucket; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
1987 PLIST_ENTRY head, link;
1988 head = &(gOvsSwitchContext->portNoHashArray[i]);
1989 POVS_VPORT_ENTRY vport = NULL;
1990
1991 outIndex = 0;
1992 LIST_FORALL(head, link) {
1993
1994 /*
1995 * if one or more dumps were previously done on this same bucket,
1996 * inIndex will be > 0, so we'll need to reply with the
1997 * inIndex + 1 vport from the bucket.
1998 */
1999 if (outIndex >= inIndex) {
2000 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
2001
2002 ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
2003 OvsCreateMsgFromVport(vport, msgIn,
2004 usrParamsCtx->outputBuffer,
2005 usrParamsCtx->outputLength,
2006 gOvsSwitchContext->dpNo);
2007 ++outIndex;
2008 break;
2009 }
2010
2011 ++outIndex;
2012 }
2013
2014 if (vport) {
2015 break;
2016 }
2017
2018 /*
2019 * if no vport was found above, check the next bucket, beginning
2020 * with the first (i.e. index 0) elem from within that bucket
2021 */
2022 inIndex = 0;
2023 }
2024
2025 outBucket = i;
2026
2027 /* XXX: what about NLMSG_DONE (as msg type)? */
2028 instance->dumpState.index[0] = outBucket;
2029 instance->dumpState.index[1] = outIndex;
2030 }
2031
2032 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2033
012b5d13
NR
2034 /* if i < OVS_MAX_VPORT_ARRAY_SIZE => vport was found */
2035 if (i < OVS_MAX_VPORT_ARRAY_SIZE) {
2036 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2037 *replyLen = msgOut->nlMsg.nlmsgLen;
2038 } else {
2039 /*
2040 * if i >= OVS_MAX_VPORT_ARRAY_SIZE => vport was not found =>
2041 * it's dump done
2042 */
2043 *replyLen = 0;
2044 /* Free up the dump state, since there's no more data to continue. */
2045 FreeUserDumpState(instance);
2046 }
2047
2048 return STATUS_SUCCESS;
2049}
2050
2051static NTSTATUS
2052OvsGetVport(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2053 UINT32 *replyLen)
2054{
2055 NTSTATUS status = STATUS_SUCCESS;
2056 LOCK_STATE_EX lockState;
2057
2058 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2059 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2060 POVS_VPORT_ENTRY vport = NULL;
2061 NL_ERROR nlError = NL_ERROR_SUCCESS;
2062 PCHAR portName = NULL;
2063 UINT32 portNameLen = 0;
2064 UINT32 portNumber = OVS_DPPORT_NUMBER_INVALID;
2065
2066 static const NL_POLICY ovsVportPolicy[] = {
2067 [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2068 [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING,
2069 .minLen = 2,
2070 .maxLen = IFNAMSIZ,
2071 .optional = TRUE},
2072 };
2073 PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2074
2075 /* input buffer has been validated while validating write dev op. */
2076 ASSERT(usrParamsCtx->inputBuffer != NULL);
2077
2078 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2079 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2080 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
b8b00f0c
SV
2081 ovsVportPolicy, ARRAY_SIZE(ovsVportPolicy),
2082 vportAttrs, ARRAY_SIZE(vportAttrs))) {
012b5d13
NR
2083 return STATUS_INVALID_PARAMETER;
2084 }
2085
2086 /* Output buffer has been validated while validating transact dev op. */
2087 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2088
2089 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
2090 if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
2091 portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2092 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2093
2094 /* the port name is expected to be null-terminated */
2095 ASSERT(portName[portNameLen - 1] == '\0');
2096
2097 vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2098 } else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2099 portNumber = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
2100
2101 vport = OvsFindVportByPortNo(gOvsSwitchContext, portNumber);
2102 } else {
2103 nlError = NL_ERROR_INVAL;
2104 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2105 goto Cleanup;
2106 }
2107
2108 if (!vport) {
2109 nlError = NL_ERROR_NODEV;
2110 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2111 goto Cleanup;
2112 }
2113
2114 status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2115 usrParamsCtx->outputLength,
2116 gOvsSwitchContext->dpNo);
2117 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2118
2119 *replyLen = msgOut->nlMsg.nlmsgLen;
2120
2121Cleanup:
2122 if (nlError != NL_ERROR_SUCCESS) {
2123 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2124 usrParamsCtx->outputBuffer;
2125
7e98ed23
NR
2126 ASSERT(msgError);
2127 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
2128 ASSERT(*replyLen != 0);
012b5d13
NR
2129 }
2130
2131 return STATUS_SUCCESS;
2132}
2133
2134/*
2135 * --------------------------------------------------------------------------
5e82ceef 2136 * Command Handler for 'OVS_VPORT_CMD_GET'.
fa8266a8
NR
2137 *
2138 * The function handles the initial call to setup the dump state, as well as
2139 * subsequent calls to continue dumping data.
012b5d13
NR
2140 * --------------------------------------------------------------------------
2141*/
2142NTSTATUS
2143OvsGetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2144 UINT32 *replyLen)
2145{
2146 *replyLen = 0;
2147
fa8266a8 2148 switch (usrParamsCtx->devOp) {
012b5d13
NR
2149 case OVS_WRITE_DEV_OP:
2150 return OvsSetupDumpStart(usrParamsCtx);
2151
2152 case OVS_READ_DEV_OP:
2153 return OvsGetVportDumpNext(usrParamsCtx, replyLen);
2154
2155 case OVS_TRANSACTION_DEV_OP:
2156 return OvsGetVport(usrParamsCtx, replyLen);
2157
2158 default:
2159 return STATUS_INVALID_DEVICE_REQUEST;
2160 }
2161
2162}
2163
2164static UINT32
2165OvsComputeVportNo(POVS_SWITCH_CONTEXT switchContext)
2166{
2167 /* we are not allowed to create the port OVS_DPPORT_NUMBER_LOCAL */
2168 for (ULONG i = OVS_DPPORT_NUMBER_LOCAL + 1; i < MAXUINT16; ++i) {
2169 POVS_VPORT_ENTRY vport;
2170
2171 vport = OvsFindVportByPortNo(switchContext, i);
2172 if (!vport) {
2173 return i;
2174 }
2175 }
2176
2177 return OVS_DPPORT_NUMBER_INVALID;
2178}
2179
2180/*
2181 * --------------------------------------------------------------------------
2182 * Command Handler for 'OVS_VPORT_CMD_NEW'.
2183 * --------------------------------------------------------------------------
2184 */
2185NTSTATUS
2186OvsNewVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2187 UINT32 *replyLen)
2188{
2189 NDIS_STATUS status = STATUS_SUCCESS;
2190 LOCK_STATE_EX lockState;
2191
2192 NL_ERROR nlError = NL_ERROR_SUCCESS;
2193 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2194 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2195 POVS_VPORT_ENTRY vport = NULL;
2196 PCHAR portName;
2197 ULONG portNameLen;
2198 UINT32 portType;
012b5d13 2199 BOOLEAN vportAllocated = FALSE, vportInitialized = FALSE;
012b5d13
NR
2200
2201 static const NL_POLICY ovsVportPolicy[] = {
2202 [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2203 [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = FALSE },
2204 [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2205 .optional = FALSE},
2206 [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
2207 .optional = FALSE },
2208 [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
2209 };
2210
2211 PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2212
2213 /* input buffer has been validated while validating write dev op. */
2214 ASSERT(usrParamsCtx->inputBuffer != NULL);
2215
2216 /* Output buffer has been validated while validating transact dev op. */
2217 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2218
2219 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2220 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2221 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
b8b00f0c
SV
2222 ovsVportPolicy, ARRAY_SIZE(ovsVportPolicy),
2223 vportAttrs, ARRAY_SIZE(vportAttrs))) {
012b5d13
NR
2224 return STATUS_INVALID_PARAMETER;
2225 }
2226
2227 portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2228 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2229 portType = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
2230
2231 /* we are expecting null terminated strings to be passed */
2232 ASSERT(portName[portNameLen - 1] == '\0');
2233
2234 NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
2235
2236 vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2237 if (vport) {
2238 nlError = NL_ERROR_EXIST;
2239 goto Cleanup;
2240 }
2241
7845b703 2242 if (portType == OVS_VPORT_TYPE_NETDEV) {
012b5d13
NR
2243 /* External ports can also be looked up like VIF ports. */
2244 vport = OvsFindVportByHvNameA(gOvsSwitchContext, portName);
2245 } else {
2246 ASSERT(OvsIsTunnelVportType(portType) ||
7845b703 2247 portType == OVS_VPORT_TYPE_INTERNAL);
012b5d13
NR
2248
2249 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
2250 if (vport == NULL) {
2251 nlError = NL_ERROR_NOMEM;
2252 goto Cleanup;
2253 }
2254 vportAllocated = TRUE;
2255
2256 if (OvsIsTunnelVportType(portType)) {
022c2040 2257 UINT16 transportPortDest = 0;
885b8265
NR
2258 UINT8 nwProto;
2259 POVS_VPORT_ENTRY dupVport;
022c2040 2260
bc651c85 2261 switch (portType) {
85571a3d 2262 case OVS_VPORT_TYPE_GRE:
885b8265 2263 nwProto = IPPROTO_GRE;
85571a3d 2264 break;
022c2040
EE
2265 case OVS_VPORT_TYPE_VXLAN:
2266 transportPortDest = VXLAN_UDP_PORT;
885b8265 2267 nwProto = IPPROTO_UDP;
022c2040
EE
2268 break;
2269 case OVS_VPORT_TYPE_STT:
2270 transportPortDest = STT_TCP_PORT;
885b8265 2271 nwProto = IPPROTO_TCP;
022c2040
EE
2272 break;
2273 default:
ec6f7ef3
AS
2274 nlError = NL_ERROR_INVAL;
2275 goto Cleanup;
022c2040
EE
2276 }
2277
c42d0da6
NR
2278 if (vportAttrs[OVS_VPORT_ATTR_OPTIONS]) {
2279 PNL_ATTR attr = NlAttrFindNested(vportAttrs[OVS_VPORT_ATTR_OPTIONS],
2280 OVS_TUNNEL_ATTR_DST_PORT);
2281 if (attr) {
2282 transportPortDest = NlAttrGetU16(attr);
2283 }
5e82ceef
SV
2284 }
2285
885b8265
NR
2286 /*
2287 * We don't allow two tunnel ports on identical N/W protocol and
2288 * L4 port number. This is applicable even if the two ports are of
2289 * different tunneling types.
2290 */
2291 dupVport =
2292 OvsFindTunnelVportByDstPortAndNWProto(gOvsSwitchContext,
2293 transportPortDest,
2294 nwProto);
2295 if (dupVport) {
2296 OVS_LOG_ERROR("Vport for N/W proto and port already exists,"
2297 " type: %u, dst port: %u, name: %s", dupVport->ovsType,
2298 transportPortDest, dupVport->ovsName);
2299 goto Cleanup;
2300 }
2301
5e82ceef
SV
2302 status = OvsInitTunnelVport(usrParamsCtx,
2303 vport,
2304 portType,
022c2040 2305 transportPortDest);
5e82ceef 2306
012b5d13
NR
2307 nlError = NlMapStatusToNlErr(status);
2308 } else {
2309 OvsInitBridgeInternalVport(vport);
2310 }
5e82ceef 2311
012b5d13
NR
2312 vportInitialized = TRUE;
2313
2314 if (nlError == NL_ERROR_SUCCESS) {
2315 vport->ovsState = OVS_STATE_CONNECTED;
2316 vport->nicState = NdisSwitchNicStateConnected;
2317
2318 /*
2319 * Allow the vport to be deleted, because there is no
2320 * corresponding hyper-v switch part.
2321 */
421e2422 2322 vport->isAbsentOnHv = TRUE;
5e82ceef
SV
2323 } else {
2324 goto Cleanup;
012b5d13
NR
2325 }
2326 }
2327
2328 if (!vport) {
2329 nlError = NL_ERROR_INVAL;
2330 goto Cleanup;
2331 }
2332 if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
2333 nlError = NL_ERROR_EXIST;
2334 goto Cleanup;
2335 }
2336
012b5d13
NR
2337 if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2338 /*
2339 * XXX: when we implement the limit for ovs port number to be
2340 * MAXUINT16, we'll need to check the port number received from the
2341 * userspace.
2342 */
2343 vport->portNo = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
2344 } else {
2345 vport->portNo = OvsComputeVportNo(gOvsSwitchContext);
2346 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
2347 nlError = NL_ERROR_NOMEM;
2348 goto Cleanup;
2349 }
2350 }
2351
2352 /* The ovs port name must be uninitialized. */
2353 ASSERT(vport->ovsName[0] == '\0');
2354 ASSERT(portNameLen <= OVS_MAX_PORT_NAME_LENGTH);
2355
2356 RtlCopyMemory(vport->ovsName, portName, portNameLen);
2357 /* if we don't have options, then vport->portOptions will be NULL */
2358 vport->portOptions = vportAttrs[OVS_VPORT_ATTR_OPTIONS];
2359
2360 /*
2361 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2362 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2363 * it means we have an array of pids, instead of a single pid.
2364 * ATM we assume we have one pid only.
2365 */
2366 vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
2367
2368 status = InitOvsVportCommon(gOvsSwitchContext, vport);
2369 ASSERT(status == STATUS_SUCCESS);
2370
2371 status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2372 usrParamsCtx->outputLength,
2373 gOvsSwitchContext->dpNo);
2374
2375 *replyLen = msgOut->nlMsg.nlmsgLen;
885b8265
NR
2376 OVS_LOG_INFO("Created new vport, name: %s, type: %u", vport->ovsName,
2377 vport->ovsType);
012b5d13
NR
2378
2379Cleanup:
2380 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2381
5e82ceef 2382 if ((nlError != NL_ERROR_SUCCESS) && (nlError != NL_ERROR_PENDING)) {
012b5d13
NR
2383 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2384 usrParamsCtx->outputBuffer;
2385
2386 if (vport && vportAllocated == TRUE) {
2387 if (vportInitialized == TRUE) {
2388 if (OvsIsTunnelVportType(portType)) {
022c2040
EE
2389 switch (vport->ovsType) {
2390 case OVS_VPORT_TYPE_VXLAN:
2391 OvsCleanupVxlanTunnel(NULL, vport, NULL, NULL);
2392 break;
2393 case OVS_VPORT_TYPE_STT:
3f11b876 2394 OvsCleanupSttTunnel(vport);
022c2040
EE
2395 break;
2396 default:
2397 ASSERT(!"Invalid tunnel port type");
2398 }
012b5d13
NR
2399 }
2400 }
2be9ec26 2401 OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
012b5d13
NR
2402 }
2403
7e98ed23
NR
2404 ASSERT(msgError);
2405 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
2406 ASSERT(*replyLen != 0);
012b5d13
NR
2407 }
2408
5e82ceef 2409 return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
012b5d13
NR
2410}
2411
2412
2413/*
2414 * --------------------------------------------------------------------------
2415 * Command Handler for 'OVS_VPORT_CMD_SET'.
2416 * --------------------------------------------------------------------------
2417 */
2418NTSTATUS
2419OvsSetVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2420 UINT32 *replyLen)
2421{
2422 NDIS_STATUS status = STATUS_SUCCESS;
2423 LOCK_STATE_EX lockState;
2424
2425 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2426 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2427 POVS_VPORT_ENTRY vport = NULL;
2428 NL_ERROR nlError = NL_ERROR_SUCCESS;
2429
2430 static const NL_POLICY ovsVportPolicy[] = {
2431 [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2432 [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = TRUE },
2433 [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2434 .optional = TRUE },
2435 [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
2436 .optional = TRUE },
2437 [OVS_VPORT_ATTR_STATS] = { .type = NL_A_UNSPEC,
2438 .minLen = sizeof(OVS_VPORT_FULL_STATS),
2439 .maxLen = sizeof(OVS_VPORT_FULL_STATS),
2440 .optional = TRUE },
2441 [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
2442 };
2443 PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2444
2445 ASSERT(usrParamsCtx->inputBuffer != NULL);
2446
2447 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2448 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2449 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
b8b00f0c
SV
2450 ovsVportPolicy, ARRAY_SIZE(ovsVportPolicy),
2451 vportAttrs, ARRAY_SIZE(vportAttrs))) {
012b5d13
NR
2452 return STATUS_INVALID_PARAMETER;
2453 }
2454
2455 /* Output buffer has been validated while validating transact dev op. */
2456 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2457
012b5d13
NR
2458 NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
2459 if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
2460 PSTR portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2461#ifdef DBG
2462 UINT32 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2463#endif
2464 /* the port name is expected to be null-terminated */
2465 ASSERT(portName[portNameLen - 1] == '\0');
2466
2467 vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2468 } else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2469 vport = OvsFindVportByPortNo(gOvsSwitchContext,
2470 NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]));
2471 }
2472
2473 if (!vport) {
2474 nlError = NL_ERROR_NODEV;
2475 goto Cleanup;
2476 }
2477
2478 /*
2479 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2480 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2481 * it means we have an array of pids, instead of a single pid.
2482 * Currently, we support only one pid.
2483 */
2484 if (vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]) {
2485 vport->upcallPid = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
2486 }
2487
2488 if (vportAttrs[OVS_VPORT_ATTR_TYPE]) {
2489 OVS_VPORT_TYPE type = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
2490 if (type != vport->ovsType) {
2491 nlError = NL_ERROR_INVAL;
2492 goto Cleanup;
2493 }
2494 }
2495
2496 if (vportAttrs[OVS_VPORT_ATTR_OPTIONS]) {
2497 OVS_LOG_ERROR("Vport options not supported");
2498 nlError = NL_ERROR_NOTSUPP;
2499 goto Cleanup;
2500 }
2501
2502 status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2503 usrParamsCtx->outputLength,
2504 gOvsSwitchContext->dpNo);
2505
2506 *replyLen = msgOut->nlMsg.nlmsgLen;
2507
2508Cleanup:
2509 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
012b5d13
NR
2510
2511 if (nlError != NL_ERROR_SUCCESS) {
2512 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2513 usrParamsCtx->outputBuffer;
2514
7e98ed23
NR
2515 ASSERT(msgError);
2516 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
2517 ASSERT(*replyLen != 0);
012b5d13
NR
2518 }
2519
2520 return STATUS_SUCCESS;
2521}
2522
2523/*
2524 * --------------------------------------------------------------------------
2525 * Command Handler for 'OVS_VPORT_CMD_DEL'.
2526 * --------------------------------------------------------------------------
2527 */
2528NTSTATUS
2529OvsDeleteVportCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
2530 UINT32 *replyLen)
2531{
2532 NDIS_STATUS status = STATUS_SUCCESS;
2533 LOCK_STATE_EX lockState;
2534
2535 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
2536 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
2537 POVS_VPORT_ENTRY vport = NULL;
2538 NL_ERROR nlError = NL_ERROR_SUCCESS;
2539 PSTR portName = NULL;
2540 UINT32 portNameLen = 0;
2541
2542 static const NL_POLICY ovsVportPolicy[] = {
2543 [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2544 [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2545 .optional = TRUE },
2546 };
2547 PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2548
2549 ASSERT(usrParamsCtx->inputBuffer != NULL);
2550
2551 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2552 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2553 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
b8b00f0c
SV
2554 ovsVportPolicy, ARRAY_SIZE(ovsVportPolicy),
2555 vportAttrs, ARRAY_SIZE(vportAttrs))) {
012b5d13
NR
2556 return STATUS_INVALID_PARAMETER;
2557 }
2558
2559 /* Output buffer has been validated while validating transact dev op. */
2560 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
2561
2562 NdisAcquireRWLockWrite(gOvsSwitchContext->dispatchLock, &lockState, 0);
2563 if (vportAttrs[OVS_VPORT_ATTR_NAME] != NULL) {
2564 portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2565 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2566
2567 /* the port name is expected to be null-terminated */
2568 ASSERT(portName[portNameLen - 1] == '\0');
2569
2570 vport = OvsFindVportByOvsName(gOvsSwitchContext, portName);
2571 }
2572 else if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2573 vport = OvsFindVportByPortNo(gOvsSwitchContext,
2574 NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]));
2575 }
2576
2577 if (!vport) {
2578 nlError = NL_ERROR_NODEV;
2579 goto Cleanup;
2580 }
2581
2582 status = OvsCreateMsgFromVport(vport, msgIn, usrParamsCtx->outputBuffer,
2583 usrParamsCtx->outputLength,
2584 gOvsSwitchContext->dpNo);
2585
5e82ceef
SV
2586 *replyLen = msgOut->nlMsg.nlmsgLen;
2587
012b5d13
NR
2588 /*
2589 * Mark the port as deleted from OVS userspace. If the port does not exist
2590 * on the Hyper-V switch, it gets deallocated. Otherwise, it stays.
2591 */
5e82ceef
SV
2592 status = OvsRemoveAndDeleteVport(usrParamsCtx,
2593 gOvsSwitchContext,
2594 vport,
2595 FALSE,
2596 TRUE);
2597 if (status) {
2598 nlError = NlMapStatusToNlErr(status);
2599 }
012b5d13
NR
2600
2601Cleanup:
2602 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
2603
5e82ceef 2604 if ((nlError != NL_ERROR_SUCCESS) && (nlError != NL_ERROR_PENDING)) {
012b5d13
NR
2605 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
2606 usrParamsCtx->outputBuffer;
2607
7e98ed23
NR
2608 ASSERT(msgError);
2609 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
2610 ASSERT(*replyLen != 0);
012b5d13
NR
2611 }
2612
5e82ceef
SV
2613 return (status == STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
2614}
2615
2616static VOID
b8155080 2617OvsTunnelVportPendingRemove(PVOID context,
5e82ceef
SV
2618 NTSTATUS status,
2619 UINT32 *replyLen)
2620{
2621 POVS_TUNFLT_INIT_CONTEXT tunnelContext =
2622 (POVS_TUNFLT_INIT_CONTEXT) context;
2623 POVS_SWITCH_CONTEXT switchContext = tunnelContext->switchContext;
2624 POVS_VPORT_ENTRY vport = tunnelContext->vport;
2625 POVS_MESSAGE msgIn = (POVS_MESSAGE)tunnelContext->inputBuffer;
2626 POVS_MESSAGE msgOut = (POVS_MESSAGE)tunnelContext->outputBuffer;
2627 NL_ERROR nlError = NlMapStatusToNlErr(status);
2628 LOCK_STATE_EX lockState;
2629
2630 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
2631
2632 if (msgIn && msgOut) {
2633 /* Check the received status to reply to the caller. */
2634 if (STATUS_SUCCESS == status) {
2635 OvsCreateMsgFromVport(vport,
2636 msgIn,
2637 msgOut,
2638 tunnelContext->outputLength,
2639 switchContext->dpNo);
2640
2641 *replyLen = msgOut->nlMsg.nlmsgLen;
2642 } else {
7e98ed23
NR
2643 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)msgOut;
2644 ASSERT(msgError);
2645 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
2646 ASSERT(*replyLen != 0);
5e82ceef
SV
2647 }
2648 }
2649
421e2422 2650 ASSERT(vport->isAbsentOnHv == TRUE);
b8155080
NR
2651 ASSERT(vport->portNo != OVS_DPPORT_NUMBER_INVALID);
2652
2653 /* Remove the port from the relevant lists. */
2654 switchContext->numNonHvVports--;
2655 RemoveEntryList(&vport->ovsNameLink);
2656 RemoveEntryList(&vport->portNoLink);
2657 RemoveEntryList(&vport->tunnelVportLink);
f18390b7
SV
2658
2659 if (vport->priv) {
2660 OvsFreeMemoryWithTag(vport->priv, OVS_VXLAN_POOL_TAG);
2661 vport->priv = NULL;
2662 }
2663
b8155080 2664 OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
5e82ceef
SV
2665
2666 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
2667}
2668
2669static VOID
2670OvsTunnelVportPendingInit(PVOID context,
2671 NTSTATUS status,
2672 UINT32 *replyLen)
2673{
2674 POVS_TUNFLT_INIT_CONTEXT tunnelContext =
2675 (POVS_TUNFLT_INIT_CONTEXT) context;
2676 POVS_VPORT_ENTRY vport = tunnelContext->vport;
2677 POVS_MESSAGE msgIn = (POVS_MESSAGE)tunnelContext->inputBuffer;
2678 POVS_MESSAGE msgOut = (POVS_MESSAGE)tunnelContext->outputBuffer;
2679 PCHAR portName;
2680 ULONG portNameLen = 0;
2681 UINT32 portType = 0;
2682 NL_ERROR nlError = NL_ERROR_SUCCESS;
2683 BOOLEAN error = TRUE;
2684
2685 do {
2686 if (!NT_SUCCESS(status)) {
2687 nlError = NlMapStatusToNlErr(status);
2688 break;
2689 }
2690
2691 static const NL_POLICY ovsVportPolicy[] = {
2692 [OVS_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32, .optional = TRUE },
2693 [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32, .optional = FALSE },
2694 [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .maxLen = IFNAMSIZ,
2695 .optional = FALSE },
2696 [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NL_A_UNSPEC,
2697 .optional = FALSE },
2698 [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = TRUE },
2699 };
2700
2701 PNL_ATTR vportAttrs[ARRAY_SIZE(ovsVportPolicy)];
2702
2703 /* input buffer has been validated while validating write dev op. */
2704 ASSERT(msgIn != NULL);
2705
2706 /* Output buffer has been validated while validating transact dev op. */
2707 ASSERT(msgOut != NULL && tunnelContext->outputLength >= sizeof *msgOut);
2708
2709 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
2710 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
2711 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
b8b00f0c
SV
2712 ovsVportPolicy, ARRAY_SIZE(ovsVportPolicy),
2713 vportAttrs, ARRAY_SIZE(vportAttrs))) {
5e82ceef
SV
2714 nlError = NL_ERROR_INVAL;
2715 break;
2716 }
2717
2718 portName = NlAttrGet(vportAttrs[OVS_VPORT_ATTR_NAME]);
2719 portNameLen = NlAttrGetSize(vportAttrs[OVS_VPORT_ATTR_NAME]);
2720 portType = NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_TYPE]);
2721
2722 if (vport->portNo != OVS_DPPORT_NUMBER_INVALID) {
2723 nlError = NL_ERROR_EXIST;
2724 break;
2725 }
2726
2727 vport->ovsState = OVS_STATE_CONNECTED;
2728 vport->nicState = NdisSwitchNicStateConnected;
2729
2730 /*
2731 * Allow the vport to be deleted, because there is no
2732 * corresponding hyper-v switch part.
2733 */
421e2422 2734 vport->isAbsentOnHv = TRUE;
5e82ceef
SV
2735
2736 if (vportAttrs[OVS_VPORT_ATTR_PORT_NO] != NULL) {
2737 /*
2738 * XXX: when we implement the limit for OVS port number to be
2739 * MAXUINT16, we'll need to check the port number received from the
2740 * userspace.
2741 */
2742 vport->portNo =
2743 NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_PORT_NO]);
2744 } else {
2745 vport->portNo =
2746 OvsComputeVportNo(gOvsSwitchContext);
2747 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
2748 nlError = NL_ERROR_NOMEM;
2749 break;
2750 }
2751 }
2752
2753 /* The ovs port name must be uninitialized. */
2754 ASSERT(vport->ovsName[0] == '\0');
2755 ASSERT(portNameLen <= OVS_MAX_PORT_NAME_LENGTH);
2756
2757 RtlCopyMemory(vport->ovsName, portName, portNameLen);
2758 /* if we don't have options, then vport->portOptions will be NULL */
2759 vport->portOptions = vportAttrs[OVS_VPORT_ATTR_OPTIONS];
2760
2761 /*
2762 * XXX: when we implement OVS_DP_ATTR_USER_FEATURES in datapath,
2763 * we'll need to check the OVS_DP_F_VPORT_PIDS flag: if it is set,
2764 * it means we have an array of pids, instead of a single pid.
2765 * ATM we assume we have one pid only.
2766 */
2767 vport->upcallPid =
2768 NlAttrGetU32(vportAttrs[OVS_VPORT_ATTR_UPCALL_PID]);
2769
2770 status = InitOvsVportCommon(gOvsSwitchContext, vport);
2771 ASSERT(status == STATUS_SUCCESS);
2772
2773 OvsCreateMsgFromVport(vport,
2774 msgIn,
2775 msgOut,
2776 tunnelContext->outputLength,
2777 gOvsSwitchContext->dpNo);
2778
2779 *replyLen = msgOut->nlMsg.nlmsgLen;
2780
2781 error = FALSE;
2782 } while (error);
2783
2784 if (error) {
7e98ed23 2785 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)msgOut;
5e82ceef
SV
2786
2787 OvsCleanupVxlanTunnel(NULL, vport, NULL, NULL);
2788 OvsFreeMemory(vport);
2789
7e98ed23
NR
2790 ASSERT(msgError);
2791 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
2792 ASSERT(*replyLen != 0);
5e82ceef 2793 }
012b5d13 2794}