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