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