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