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