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