]> git.proxmox.com Git - mirror_ovs.git/blame - datapath-windows/ovsext/Vport.c
datapath-windows: delete ports from portIdHashArray during cleanup
[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;
51extern PNDIS_SPIN_LOCK gOvsCtrlLock;
52
c803536e
SS
53static VOID OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
54 PNDIS_SWITCH_PORT_PARAMETERS portParam);
55static VOID OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
56 POVS_VPORT_ENTRY vport, PNDIS_SWITCH_NIC_PARAMETERS nicParam);
57static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, POVS_VPORT_ENTRY
58 virtVport, UINT32 nicIndex);
59static VOID OvsInitPhysNicVport(POVS_VPORT_ENTRY vport, POVS_VPORT_ENTRY
60 virtVport, UINT32 nicIndex);
c803536e
SS
61static __inline VOID OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext,
62 ULONG sleepMicroSec);
be581675
NR
63static NTSTATUS OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
64 POVS_VPORT_EXT_INFO extInfo);
65static NTSTATUS CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
66 POVS_MESSAGE msgIn,
67 PVOID outBuffer,
68 UINT32 outBufLen,
69 int dpIfIndex);
c803536e
SS
70
71/*
72 * Functions implemented in relaton to NDIS port manipulation.
73 */
74NDIS_STATUS
fa048323
AS
75HvCreatePort(POVS_SWITCH_CONTEXT switchContext,
76 PNDIS_SWITCH_PORT_PARAMETERS portParam)
c803536e
SS
77{
78 POVS_VPORT_ENTRY vport;
79 LOCK_STATE_EX lockState;
80 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
81
82 VPORT_PORT_ENTER(portParam);
83
84 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
85 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
86 portParam->PortId, 0);
8d9f1e0c 87 if (vport != NULL && !vport->hvDeleted) {
c803536e
SS
88 status = STATUS_DATA_NOT_ACCEPTED;
89 goto create_port_done;
8d9f1e0c
NR
90 } else if (!vport) {
91 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
92 if (vport == NULL) {
93 status = NDIS_STATUS_RESOURCES;
94 goto create_port_done;
95 }
c803536e 96 }
8d9f1e0c 97
c803536e
SS
98 OvsInitVportWithPortParam(vport, portParam);
99 OvsInitVportCommon(switchContext, vport);
100
101create_port_done:
102 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
103 VPORT_PORT_EXIT(portParam);
104 return status;
105}
106
107VOID
fa048323
AS
108HvTeardownPort(POVS_SWITCH_CONTEXT switchContext,
109 PNDIS_SWITCH_PORT_PARAMETERS portParam)
c803536e
SS
110{
111 POVS_VPORT_ENTRY vport;
112 LOCK_STATE_EX lockState;
113
114 VPORT_PORT_ENTER(portParam);
115
116 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
117 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
118 portParam->PortId, 0);
119 if (vport) {
120 /* add assertion here
121 */
122 vport->portState = NdisSwitchPortStateTeardown;
123 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
124 } else {
125 OVS_LOG_WARN("Vport not present.");
126 }
127 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
128
129 VPORT_PORT_EXIT(portParam);
130}
131
132
133
134VOID
fa048323 135HvDeletePort(POVS_SWITCH_CONTEXT switchContext,
611531c1 136 PNDIS_SWITCH_PORT_PARAMETERS portParams)
c803536e
SS
137{
138 POVS_VPORT_ENTRY vport;
139 LOCK_STATE_EX lockState;
140
611531c1 141 VPORT_PORT_ENTER(portParams);
c803536e
SS
142
143 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
144 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
611531c1
NR
145 portParams->PortId, 0);
146
147 /*
148 * XXX: we can only destroy and remove the port if its datapath port
149 * counterpart was deleted. If the datapath port counterpart is present,
150 * we only mark the vport for deletion, so that a netlink command vport
151 * delete will delete the vport.
152 */
c803536e 153 if (vport) {
611531c1
NR
154 if (vport->portNo == OVS_DPPORT_NUMBER_INVALID) {
155 OvsRemoveAndDeleteVport(switchContext, vport);
156 } else {
157 vport->hvDeleted = TRUE;
158 }
c803536e
SS
159 } else {
160 OVS_LOG_WARN("Vport not present.");
161 }
162 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
163
611531c1 164 VPORT_PORT_EXIT(portParams);
c803536e
SS
165}
166
167
168/*
169 * Functions implemented in relaton to NDIS NIC manipulation.
170 */
171NDIS_STATUS
fa048323
AS
172HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
173 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
c803536e
SS
174{
175 POVS_VPORT_ENTRY vport;
176 UINT32 portNo = 0;
177 UINT32 event = 0;
178 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
179
180 LOCK_STATE_EX lockState;
181
182 VPORT_NIC_ENTER(nicParam);
183
184 /* Wait for lists to be initialized. */
185 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
186
187 if (!switchContext->isActivated) {
188 OVS_LOG_WARN("Switch is not activated yet.");
189 /* Veto the creation of nic */
190 status = NDIS_STATUS_NOT_SUPPORTED;
191 goto done;
192 }
193
194 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
195 vport = OvsFindVportByPortIdAndNicIndex(switchContext, nicParam->PortId, 0);
196 if (vport == NULL) {
197 OVS_LOG_ERROR("Create NIC without Switch Port,"
198 " PortId: %x, NicIndex: %d",
199 nicParam->PortId, nicParam->NicIndex);
200 status = NDIS_STATUS_INVALID_PARAMETER;
201 goto add_nic_done;
202 }
203
204 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
205 nicParam->NicIndex != 0) {
206 POVS_VPORT_ENTRY virtVport =
207 (POVS_VPORT_ENTRY)switchContext->externalVport;
208 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
209 if (vport == NULL) {
210 status = NDIS_STATUS_RESOURCES;
211 goto add_nic_done;
212 }
213 OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex);
214 status = OvsInitVportCommon(switchContext, vport);
215 if (status != NDIS_STATUS_SUCCESS) {
216 OvsFreeMemory(vport);
217 goto add_nic_done;
218 }
219 }
220 OvsInitVportWithNicParam(switchContext, vport, nicParam);
221 portNo = vport->portNo;
222 if (vport->ovsState == OVS_STATE_CONNECTED) {
223 event = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
224 } else if (vport->ovsState == OVS_STATE_NIC_CREATED) {
225 event = OVS_EVENT_CONNECT;
226 }
227
228add_nic_done:
229 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
429d4556 230 if (portNo != OVS_DPPORT_NUMBER_INVALID && event) {
c803536e
SS
231 OvsPostEvent(portNo, event);
232 }
233
234done:
235 VPORT_NIC_EXIT(nicParam);
236 OVS_LOG_TRACE("Exit: status %8x.\n", status);
237
238 return status;
239}
240
241
242/* Mark already created NIC as connected. */
243VOID
fa048323
AS
244HvConnectNic(POVS_SWITCH_CONTEXT switchContext,
245 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
c803536e
SS
246{
247 LOCK_STATE_EX lockState;
248 POVS_VPORT_ENTRY vport;
249 UINT32 portNo = 0;
250
251 VPORT_NIC_ENTER(nicParam);
252
253 /* Wait for lists to be initialized. */
254 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
255
256 if (!switchContext->isActivated) {
257 OVS_LOG_WARN("Switch is not activated yet.");
258 goto done;
259 }
260
261 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
262 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
263 nicParam->PortId,
264 nicParam->NicIndex);
265
266 if (!vport) {
267 OVS_LOG_WARN("Vport not present.");
268 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
269 ASSERT(0);
270 goto done;
271 }
272
273 vport->ovsState = OVS_STATE_CONNECTED;
274 vport->nicState = NdisSwitchNicStateConnected;
275 portNo = vport->portNo;
276
277 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
278
429d4556 279 /* XXX only if portNo != INVALID or always? */
c803536e
SS
280 OvsPostEvent(portNo, OVS_EVENT_LINK_UP);
281
282 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
283 OvsInternalAdapterUp(portNo, &nicParam->NetCfgInstanceId);
284 }
285
286done:
287 VPORT_NIC_EXIT(nicParam);
288}
289
290VOID
fa048323
AS
291HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
292 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
c803536e
SS
293{
294 POVS_VPORT_ENTRY vport;
295 LOCK_STATE_EX lockState;
296
297 UINT32 status = 0, portNo = 0;
298
299 VPORT_NIC_ENTER(nicParam);
300
301 /* Wait for lists to be initialized. */
302 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
303
304 if (!switchContext->isActivated) {
305 OVS_LOG_WARN("Switch is not activated yet.");
306 goto update_nic_done;
307 }
308
309 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
310 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
311 nicParam->PortId,
312 nicParam->NicIndex);
313 if (vport == NULL) {
314 OVS_LOG_WARN("Vport search failed.");
315 goto update_nic_done;
316 }
317 switch (nicParam->NicType) {
318 case NdisSwitchNicTypeExternal:
319 case NdisSwitchNicTypeInternal:
320 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
321 sizeof (GUID));
322 break;
323 case NdisSwitchNicTypeSynthetic:
324 case NdisSwitchNicTypeEmulated:
325 if (!RtlEqualMemory(vport->vmMacAddress, nicParam->VMMacAddress,
326 sizeof (vport->vmMacAddress))) {
327 status |= OVS_EVENT_MAC_CHANGE;
328 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
329 sizeof (vport->vmMacAddress));
330 }
331 break;
332 default:
333 ASSERT(0);
334 }
335 if (!RtlEqualMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
336 sizeof (vport->permMacAddress))) {
337 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
338 sizeof (vport->permMacAddress));
339 status |= OVS_EVENT_MAC_CHANGE;
340 }
341 if (!RtlEqualMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
342 sizeof (vport->currMacAddress))) {
343 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
344 sizeof (vport->currMacAddress));
345 status |= OVS_EVENT_MAC_CHANGE;
346 }
347
348 if (vport->mtu != nicParam->MTU) {
349 vport->mtu = nicParam->MTU;
350 status |= OVS_EVENT_MTU_CHANGE;
351 }
352 vport->numaNodeId = nicParam->NumaNodeId;
353 portNo = vport->portNo;
354
355 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
356 if (status && portNo) {
357 OvsPostEvent(portNo, status);
358 }
359update_nic_done:
360 VPORT_NIC_EXIT(nicParam);
361}
362
363
364VOID
fa048323
AS
365HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
366 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
c803536e
SS
367{
368 POVS_VPORT_ENTRY vport;
369 UINT32 portNo = 0;
370 LOCK_STATE_EX lockState;
371 BOOLEAN isInternalPort = FALSE;
372
373 VPORT_NIC_ENTER(nicParam);
374
375 /* Wait for lists to be initialized. */
376 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
377
378 if (!switchContext->isActivated) {
379 OVS_LOG_WARN("Switch is not activated yet.");
380 goto done;
381 }
382
383 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
384 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
385 nicParam->PortId,
386 nicParam->NicIndex);
387
388 if (!vport) {
389 OVS_LOG_WARN("Vport not present.");
390 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
391 goto done;
392 }
393
394 vport->nicState = NdisSwitchNicStateDisconnected;
395 vport->ovsState = OVS_STATE_NIC_CREATED;
396 portNo = vport->portNo;
397
e00afcf6 398 if (vport->ovsType == OVS_VPORT_TYPE_INTERNAL) {
c803536e
SS
399 isInternalPort = TRUE;
400 }
401
402 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
403
429d4556 404 /* XXX if portNo != INVALID or always? */
c803536e
SS
405 OvsPostEvent(portNo, OVS_EVENT_LINK_DOWN);
406
407 if (isInternalPort) {
408 OvsInternalAdapterDown();
409 }
410
411done:
412 VPORT_NIC_EXIT(nicParam);
413}
414
415
416VOID
fa048323
AS
417HvDeleteNic(POVS_SWITCH_CONTEXT switchContext,
418 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
c803536e
SS
419{
420 LOCK_STATE_EX lockState;
421 POVS_VPORT_ENTRY vport;
422 UINT32 portNo = 0;
423
424 VPORT_NIC_ENTER(nicParam);
425 /* Wait for lists to be initialized. */
426 OvsWaitActivate(switchContext, OVS_VPORT_DEFAULT_WAIT_TIME_MICROSEC);
427
428 if (!switchContext->isActivated) {
429 OVS_LOG_WARN("Switch is not activated yet.");
430 goto done;
431 }
432
433 NdisAcquireRWLockWrite(switchContext->dispatchLock, &lockState, 0);
434 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
435 nicParam->PortId,
436 nicParam->NicIndex);
437
438 if (!vport) {
439 OVS_LOG_WARN("Vport not present.");
440 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
441 goto done;
442 }
443
444 portNo = vport->portNo;
445 if (vport->portType == NdisSwitchPortTypeExternal &&
446 vport->nicIndex != 0) {
447 OvsRemoveAndDeleteVport(switchContext, vport);
448 }
449 vport->nicState = NdisSwitchNicStateUnknown;
450 vport->ovsState = OVS_STATE_PORT_CREATED;
451
452 NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
429d4556 453 /* XXX if portNo != INVALID or always? */
c803536e
SS
454 OvsPostEvent(portNo, OVS_EVENT_DISCONNECT);
455
456done:
457 VPORT_NIC_EXIT(nicParam);
458}
459
460
461/*
462 * OVS Vport related functionality.
463 */
464POVS_VPORT_ENTRY
465OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
466 UINT32 portNo)
467{
429d4556
AS
468 POVS_VPORT_ENTRY vport;
469 PLIST_ENTRY head, link;
470 UINT32 hash = OvsJhashBytes((const VOID *)&portNo, sizeof(portNo),
471 OVS_HASH_BASIS);
472 head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
473 LIST_FORALL(head, link) {
474 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink);
475 if (vport->portNo == portNo) {
476 return vport;
c803536e
SS
477 }
478 }
479 return NULL;
480}
481
482
483POVS_VPORT_ENTRY
484OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
8d9f1e0c 485 PSTR name)
c803536e
SS
486{
487 POVS_VPORT_ENTRY vport;
488 PLIST_ENTRY head, link;
8d9f1e0c
NR
489 UINT32 hash;
490 SIZE_T length = strlen(name) + 1;
491
492 hash = OvsJhashBytes((const VOID *)name, length, OVS_HASH_BASIS);
147c91db 493 head = &(switchContext->ovsPortNameHashArray[hash & OVS_VPORT_MASK]);
8d9f1e0c 494
c803536e 495 LIST_FORALL(head, link) {
147c91db 496 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, ovsNameLink);
8d9f1e0c 497 if (!strcmp(name, vport->ovsName)) {
c803536e
SS
498 return vport;
499 }
500 }
8d9f1e0c 501
c803536e
SS
502 return NULL;
503}
504
1b859c58
AS
505/* OvsFindVportByHvName: "name" is assumed to be null-terminated */
506POVS_VPORT_ENTRY
507OvsFindVportByHvName(POVS_SWITCH_CONTEXT switchContext,
508 PSTR name)
509{
510 POVS_VPORT_ENTRY vport = NULL;
511 PLIST_ENTRY head, link;
512 /* 'portFriendlyName' is not NUL-terminated. */
513 SIZE_T length = strlen(name);
514 SIZE_T wstrSize = length * sizeof(WCHAR);
515
516 PWSTR wsName = OvsAllocateMemory(wstrSize);
517 if (!wsName) {
518 return NULL;
519 }
520 for (UINT i = 0; i < length; i) {
521 wsName[i] = name[i];
522 }
523
524 for (UINT32 i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i) {
525 head = &(switchContext->portIdHashArray[i]);
526 LIST_FORALL(head, link) {
527 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
528
529 /*
530 * NOTE about portFriendlyName:
531 * If the string is NULL-terminated, the Length member does not
532 * include the terminating NULL character.
533 */
534 if (vport->portFriendlyName.Length == wstrSize &&
535 RtlEqualMemory(wsName, vport->portFriendlyName.String,
536 vport->portFriendlyName.Length)) {
537 goto Cleanup;
538 }
539
540 vport = NULL;
541 }
542 }
543
544Cleanup:
545 OvsFreeMemory(wsName);
546
547 return vport;
548}
549
c803536e
SS
550POVS_VPORT_ENTRY
551OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
552 NDIS_SWITCH_PORT_ID portId,
553 NDIS_SWITCH_NIC_INDEX index)
554{
555 if (portId == switchContext->externalPortId) {
429d4556 556 return (POVS_VPORT_ENTRY)switchContext->externalVport;
c803536e
SS
557 } else if (switchContext->internalPortId == portId) {
558 return (POVS_VPORT_ENTRY)switchContext->internalVport;
559 } else {
560 PLIST_ENTRY head, link;
561 POVS_VPORT_ENTRY vport;
562 UINT32 hash;
563 hash = OvsJhashWords((UINT32 *)&portId, 1, OVS_HASH_BASIS);
91c261cd 564 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
c803536e 565 LIST_FORALL(head, link) {
91c261cd 566 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
c803536e
SS
567 if (portId == vport->portId && index == vport->nicIndex) {
568 return vport;
569 }
570 }
571 return NULL;
572 }
573}
574
8d9f1e0c 575POVS_VPORT_ENTRY
c803536e
SS
576OvsAllocateVport(VOID)
577{
578 POVS_VPORT_ENTRY vport;
579 vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY));
580 if (vport == NULL) {
581 return NULL;
582 }
583 RtlZeroMemory(vport, sizeof (OVS_VPORT_ENTRY));
584 vport->ovsState = OVS_STATE_UNKNOWN;
8d9f1e0c 585 vport->hvDeleted = FALSE;
429d4556
AS
586 vport->portNo = OVS_DPPORT_NUMBER_INVALID;
587
588 InitializeListHead(&vport->ovsNameLink);
589 InitializeListHead(&vport->portIdLink);
590 InitializeListHead(&vport->portNoLink);
591
c803536e
SS
592 return vport;
593}
594
595static VOID
596OvsInitVportWithPortParam(POVS_VPORT_ENTRY vport,
597 PNDIS_SWITCH_PORT_PARAMETERS portParam)
598{
c803536e
SS
599 vport->portType = portParam->PortType;
600 vport->portState = portParam->PortState;
601 vport->portId = portParam->PortId;
602 vport->nicState = NdisSwitchNicStateUnknown;
e00afcf6 603 vport->isExternal = FALSE;
c803536e
SS
604
605 switch (vport->portType) {
606 case NdisSwitchPortTypeExternal:
e00afcf6
SG
607 vport->isExternal = TRUE;
608 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
c803536e
SS
609 break;
610 case NdisSwitchPortTypeInternal:
e00afcf6 611 vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
c803536e
SS
612 break;
613 case NdisSwitchPortTypeSynthetic:
c803536e 614 case NdisSwitchPortTypeEmulated:
e00afcf6 615 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
c803536e
SS
616 break;
617 }
1b859c58 618 RtlCopyMemory(&vport->hvPortName, &portParam->PortName,
c803536e 619 sizeof (NDIS_SWITCH_PORT_NAME));
1b859c58
AS
620
621 RtlCopyMemory(&vport->portFriendlyName, &portParam->PortFriendlyName,
622 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
623
c803536e
SS
624 switch (vport->portState) {
625 case NdisSwitchPortStateCreated:
626 vport->ovsState = OVS_STATE_PORT_CREATED;
627 break;
628 case NdisSwitchPortStateTeardown:
629 vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
630 break;
631 case NdisSwitchPortStateDeleted:
632 vport->ovsState = OVS_STATE_PORT_DELETED;
633 break;
634 }
635}
636
637
638static VOID
639OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
640 POVS_VPORT_ENTRY vport,
641 PNDIS_SWITCH_NIC_PARAMETERS nicParam)
642{
643 ASSERT(vport->portId == nicParam->PortId);
644 ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
645
646 UNREFERENCED_PARAMETER(switchContext);
647
648 RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
649 sizeof (nicParam->PermanentMacAddress));
650 RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
651 sizeof (nicParam->CurrentMacAddress));
652
653 if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
654 nicParam->NicType == NdisSwitchNicTypeEmulated) {
655 RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
656 sizeof (nicParam->VMMacAddress));
657 RtlCopyMemory(&vport->vmName, &nicParam->VmName,
658 sizeof (nicParam->VmName));
659 } else {
660 RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
661 sizeof (nicParam->NetCfgInstanceId));
662 }
663 RtlCopyMemory(&vport->nicName, &nicParam->NicName,
664 sizeof (nicParam->NicName));
665 vport->mtu = nicParam->MTU;
666 vport->nicState = nicParam->NicState;
667 vport->nicIndex = nicParam->NicIndex;
668 vport->numaNodeId = nicParam->NumaNodeId;
669
670 switch (vport->nicState) {
671 case NdisSwitchNicStateCreated:
672 vport->ovsState = OVS_STATE_NIC_CREATED;
673 break;
674 case NdisSwitchNicStateConnected:
675 vport->ovsState = OVS_STATE_CONNECTED;
676 break;
677 case NdisSwitchNicStateDisconnected:
678 vport->ovsState = OVS_STATE_NIC_CREATED;
679 break;
680 case NdisSwitchNicStateDeleted:
681 vport->ovsState = OVS_STATE_PORT_CREATED;
682 break;
683 }
684}
685
686static VOID
687OvsInitPhysNicVport(POVS_VPORT_ENTRY vport,
688 POVS_VPORT_ENTRY virtVport,
689 UINT32 nicIndex)
690{
c803536e
SS
691 vport->portType = virtVport->portType;
692 vport->portState = virtVport->portState;
693 vport->portId = virtVport->portId;
694 vport->nicState = NdisSwitchNicStateUnknown;
e00afcf6
SG
695 vport->ovsType = OVS_VPORT_TYPE_NETDEV;
696 vport->isExternal = TRUE;
c803536e 697 vport->nicIndex = (NDIS_SWITCH_NIC_INDEX)nicIndex;
1b859c58
AS
698
699 RtlCopyMemory(&vport->hvPortName, &virtVport->hvPortName,
c803536e 700 sizeof (NDIS_SWITCH_PORT_NAME));
1b859c58
AS
701
702 RtlCopyMemory(&vport->portFriendlyName, &virtVport->portFriendlyName,
703 sizeof(NDIS_SWITCH_PORT_FRIENDLYNAME));
704
c803536e
SS
705 vport->ovsState = OVS_STATE_PORT_CREATED;
706}
8d9f1e0c
NR
707
708NDIS_STATUS
c803536e 709OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext,
429d4556 710 POVS_VPORT_ENTRY vport)
c803536e
SS
711{
712 UINT32 hash;
429d4556 713 ASSERT(vport->portNo == OVS_DPPORT_NUMBER_INVALID);
c803536e 714
c803536e
SS
715 switch (vport->portType) {
716 case NdisSwitchPortTypeExternal:
717 if (vport->nicIndex == 0) {
718 switchContext->externalPortId = vport->portId;
719 switchContext->externalVport = vport;
720 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
721 "external.virtualAdapter");
429d4556 722 } else {
c803536e
SS
723 switchContext->numPhysicalNics++;
724 RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
725 "external.%lu", (UINT32)vport->nicIndex);
726 }
727 break;
728 case NdisSwitchPortTypeInternal:
729 switchContext->internalPortId = vport->portId;
730 switchContext->internalVport = vport;
c803536e
SS
731 break;
732 case NdisSwitchPortTypeSynthetic:
c803536e
SS
733 break;
734 case NdisSwitchPortTypeEmulated:
c803536e
SS
735 break;
736 }
429d4556 737
c803536e
SS
738 if (vport->portType == NdisSwitchPortTypeExternal &&
739 vport->nicIndex == 0) {
740 return NDIS_STATUS_SUCCESS;
741 }
429d4556
AS
742
743 /*
744 * NOTE: OvsJhashWords has portId as "1" word. This should be ok, even
745 * though sizeof(NDIS_SWITCH_PORT_ID) = 4, not 2, because the
746 * hyper-v switch seems to use only 2 bytes out of 4.
747 */
c803536e 748 hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
91c261cd
AS
749 InsertHeadList(&switchContext->portIdHashArray[hash & OVS_VPORT_MASK],
750 &vport->portIdLink);
c803536e
SS
751 switchContext->numVports++;
752 return NDIS_STATUS_SUCCESS;
753}
754
8d9f1e0c 755VOID
c803536e
SS
756OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
757 POVS_VPORT_ENTRY vport)
758{
e00afcf6 759 if (vport->isExternal) {
c803536e
SS
760 if (vport->nicIndex == 0) {
761 ASSERT(switchContext->numPhysicalNics == 0);
762 switchContext->externalPortId = 0;
763 switchContext->externalVport = NULL;
764 OvsFreeMemory(vport);
765 return;
766 } else {
767 ASSERT(switchContext->numPhysicalNics);
768 switchContext->numPhysicalNics--;
769 }
e00afcf6
SG
770 }
771
772 switch (vport->ovsType) {
773 case OVS_VPORT_TYPE_INTERNAL:
c803536e
SS
774 switchContext->internalPortId = 0;
775 switchContext->internalVport = NULL;
776 OvsInternalAdapterDown();
777 break;
e00afcf6 778 case OVS_VPORT_TYPE_VXLAN:
c803536e
SS
779 OvsCleanupVxlanTunnel(vport);
780 break;
e00afcf6
SG
781 case OVS_VPORT_TYPE_GRE:
782 case OVS_VPORT_TYPE_GRE64:
c803536e 783 break;
e00afcf6 784 case OVS_VPORT_TYPE_NETDEV:
c803536e
SS
785 default:
786 break;
787 }
788
147c91db 789 RemoveEntryList(&vport->ovsNameLink);
91c261cd 790 RemoveEntryList(&vport->portIdLink);
429d4556 791 RemoveEntryList(&vport->portNoLink);
c803536e
SS
792 switchContext->numVports--;
793 OvsFreeMemory(vport);
794}
795
796
797NDIS_STATUS
798OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
799{
800 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
801 ULONG arrIndex;
802 PNDIS_SWITCH_PORT_PARAMETERS portParam;
803 PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
804 POVS_VPORT_ENTRY vport;
805
806 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
807
808 status = OvsGetPortsOnSwitch(switchContext, &portArray);
809 if (status != NDIS_STATUS_SUCCESS) {
810 goto cleanup;
811 }
812
813 for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
814 portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
c99e6500
AS
815
816 if (portParam->IsValidationPort) {
817 continue;
818 }
819
c803536e
SS
820 vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
821 if (vport == NULL) {
822 status = NDIS_STATUS_RESOURCES;
823 goto cleanup;
824 }
825 OvsInitVportWithPortParam(vport, portParam);
826 status = OvsInitVportCommon(switchContext, vport);
827 if (status != NDIS_STATUS_SUCCESS) {
828 OvsFreeMemory(vport);
829 goto cleanup;
830 }
831 }
832cleanup:
833 if (status != NDIS_STATUS_SUCCESS) {
834 OvsClearAllSwitchVports(switchContext);
835 }
836
837 if (portArray != NULL) {
838 OvsFreeMemory(portArray);
839 }
840 OVS_LOG_TRACE("Exit: status: %x", status);
841 return status;
842}
843
844
845NDIS_STATUS
846OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
847{
848 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
849 PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
850 ULONG arrIndex;
851 PNDIS_SWITCH_NIC_PARAMETERS nicParam;
852 POVS_VPORT_ENTRY vport;
853
854 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
855 /*
856 * Now, get NIC list.
857 */
858 status = OvsGetNicsOnSwitch(switchContext, &nicArray);
859 if (status != NDIS_STATUS_SUCCESS) {
860 goto cleanup;
861 }
862 for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex) {
863
864 nicParam = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
865
866 /*
867 * XXX: Check if the port is configured with a VLAN. Disallow such a
868 * configuration, since we don't support tag-in-tag.
869 */
870
871 /*
872 * XXX: Check if the port is connected to a VF. Disconnect the VF in
873 * such a case.
874 */
875
876 if (nicParam->NicType == NdisSwitchNicTypeExternal &&
877 nicParam->NicIndex != 0) {
878 POVS_VPORT_ENTRY virtVport =
879 (POVS_VPORT_ENTRY)switchContext->externalVport;
880 vport = OvsAllocateVport();
881 if (vport) {
882 OvsInitPhysNicVport(vport, virtVport, nicParam->NicIndex);
883 status = OvsInitVportCommon(switchContext, vport);
884 if (status != NDIS_STATUS_SUCCESS) {
885 OvsFreeMemory(vport);
886 vport = NULL;
887 }
888 }
889 } else {
890 vport = OvsFindVportByPortIdAndNicIndex(switchContext,
891 nicParam->PortId,
892 nicParam->NicIndex);
893 }
894 if (vport == NULL) {
895 OVS_LOG_ERROR("Fail to allocate vport");
896 continue;
897 }
898 OvsInitVportWithNicParam(switchContext, vport, nicParam);
899 if (nicParam->NicType == NdisSwitchNicTypeInternal) {
900 OvsInternalAdapterUp(vport->portNo, &nicParam->NetCfgInstanceId);
901 }
902 }
903cleanup:
904
905 if (nicArray != NULL) {
906 OvsFreeMemory(nicArray);
907 }
908 OVS_LOG_TRACE("Exit: status: %x", status);
909 return status;
910}
911
912VOID
913OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
914{
429d4556 915 for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash) {
53165234 916 PLIST_ENTRY head, link, next;
c803536e 917
53165234
NR
918 head = &(switchContext->portIdHashArray[hash & OVS_VPORT_MASK]);
919 LIST_FORALL_SAFE(head, link, next) {
429d4556 920 POVS_VPORT_ENTRY vport;
53165234 921 vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portIdLink);
429d4556 922 OvsRemoveAndDeleteVport(switchContext, vport);
c803536e
SS
923 }
924 }
429d4556 925
c803536e
SS
926 if (switchContext->externalVport) {
927 OvsRemoveAndDeleteVport(switchContext,
928 (POVS_VPORT_ENTRY)switchContext->externalVport);
929 }
930}
931
c803536e 932
c803536e
SS
933NTSTATUS
934OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
935 CHAR *str,
936 UINT16 maxStrLen)
937{
938 ANSI_STRING astr;
939 UNICODE_STRING ustr;
940 NTSTATUS status;
941 UINT32 size;
942
943 ustr.Buffer = wStr->String;
944 ustr.Length = wStr->Length;
945 ustr.MaximumLength = IF_MAX_STRING_SIZE;
946
947 astr.Buffer = str;
948 astr.MaximumLength = maxStrLen;
949 astr.Length = 0;
950
951 size = RtlUnicodeStringToAnsiSize(&ustr);
952 if (size > maxStrLen) {
953 return STATUS_BUFFER_OVERFLOW;
954 }
955
956 status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
957
958 ASSERT(status == STATUS_SUCCESS);
959 if (status != STATUS_SUCCESS) {
960 return status;
961 }
962 ASSERT(astr.Length <= maxStrLen);
963 str[astr.Length] = 0;
964 return STATUS_SUCCESS;
965}
966
967
d8cecf58
NR
968/*
969 * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for
970 * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1.
971 */
8d9f1e0c 972#define USE_NEW_VPORT_ADD_WORKFLOW 1
c803536e 973NTSTATUS
be581675
NR
974OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
975 POVS_VPORT_EXT_INFO extInfo)
c803536e 976{
c803536e
SS
977 POVS_VPORT_ENTRY vport;
978 size_t len;
979 LOCK_STATE_EX lockState;
980 NTSTATUS status = STATUS_SUCCESS;
c803536e
SS
981 BOOLEAN doConvert = FALSE;
982
be581675 983 RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
c803536e
SS
984 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
985 NDIS_RWL_AT_DISPATCH_LEVEL);
be581675
NR
986 if (vportGet->portNo == 0) {
987 StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
d8cecf58 988#if USE_NEW_VPORT_ADD_WORKFLOW == 0
be581675 989 vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name,
c803536e 990 (UINT32)len);
d8cecf58
NR
991#else
992 vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name);
993#endif
c803536e 994 } else {
be581675 995 vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
c803536e
SS
996 }
997 if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
998 vport->ovsState != OVS_STATE_NIC_CREATED)) {
999 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1000 NdisReleaseSpinLock(gOvsCtrlLock);
be581675
NR
1001 if (vportGet->portNo) {
1002 OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
c803536e 1003 } else {
be581675 1004 OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
c803536e
SS
1005 }
1006 status = STATUS_DEVICE_DOES_NOT_EXIST;
1007 goto ext_info_done;
1008 }
be581675
NR
1009 extInfo->dpNo = vportGet->dpNo;
1010 extInfo->portNo = vport->portNo;
1011 RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
c803536e 1012 sizeof (vport->currMacAddress));
be581675 1013 RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
c803536e 1014 sizeof (vport->permMacAddress));
e00afcf6 1015 if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
be581675 1016 RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
c803536e
SS
1017 sizeof (vport->vmMacAddress));
1018 }
be581675
NR
1019 extInfo->nicIndex = vport->nicIndex;
1020 extInfo->portId = vport->portId;
1021 extInfo->type = vport->ovsType;
1022 extInfo->mtu = vport->mtu;
c803536e
SS
1023 /*
1024 * TO be revisit XXX
1025 */
1026 if (vport->ovsState == OVS_STATE_NIC_CREATED) {
be581675 1027 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
c803536e 1028 } else if (vport->ovsState == OVS_STATE_CONNECTED) {
be581675 1029 extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
c803536e 1030 } else {
be581675 1031 extInfo->status = OVS_EVENT_DISCONNECT;
c803536e 1032 }
be581675 1033 if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
c803536e
SS
1034 (vport->ovsState == OVS_STATE_NIC_CREATED ||
1035 vport->ovsState == OVS_STATE_CONNECTED)) {
c803536e
SS
1036 doConvert = TRUE;
1037 } else {
be581675
NR
1038 extInfo->vmUUID[0] = 0;
1039 extInfo->vifUUID[0] = 0;
c803536e 1040 }
d8cecf58 1041#if USE_NEW_VPORT_ADD_WORKFLOW == 0
be581675 1042 RtlCopyMemory(extInfo->name, vport->ovsName, vport->ovsNameLen + 1);
d8cecf58 1043#endif
c803536e
SS
1044 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1045 NdisReleaseSpinLock(gOvsCtrlLock);
1046 if (doConvert) {
d8cecf58
NR
1047#if USE_NEW_VPORT_ADD_WORKFLOW == 1
1048 status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1049 extInfo->name,
1050 OVS_MAX_PORT_NAME_LENGTH);
1051 if (status != STATUS_SUCCESS) {
1052 OVS_LOG_INFO("Fail to convert NIC name.");
1053 extInfo->vmUUID[0] = 0;
1054 }
1055#endif
1056
1057 status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
be581675 1058 extInfo->vmUUID,
c803536e
SS
1059 OVS_MAX_VM_UUID_LEN);
1060 if (status != STATUS_SUCCESS) {
1061 OVS_LOG_INFO("Fail to convert VM name.");
be581675 1062 extInfo->vmUUID[0] = 0;
c803536e
SS
1063 }
1064
d8cecf58 1065 status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
be581675 1066 extInfo->vifUUID,
c803536e
SS
1067 OVS_MAX_VIF_UUID_LEN);
1068 if (status != STATUS_SUCCESS) {
d8cecf58 1069 OVS_LOG_INFO("Fail to convert nic UUID");
be581675 1070 extInfo->vifUUID[0] = 0;
c803536e
SS
1071 }
1072 /*
1073 * for now ignore status
1074 */
1075 status = STATUS_SUCCESS;
1076 }
c803536e
SS
1077
1078ext_info_done:
c803536e
SS
1079 return status;
1080}
be581675 1081
2b144cbb
NR
1082/*
1083 * --------------------------------------------------------------------------
1084 * Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1085 * --------------------------------------------------------------------------
1086 */
1087NTSTATUS
1088OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1089 UINT32 *replyLen)
1090{
be581675
NR
1091 NTSTATUS status = STATUS_SUCCESS;
1092 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1093 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1094 NL_ERROR nlError = NL_ERROR_SUCCESS;
1095 OVS_VPORT_GET vportGet;
1096 OVS_VPORT_EXT_INFO info;
1097 LOCK_STATE_EX lockState;
1098
1099 static const NL_POLICY ovsNetdevPolicy[] = {
1100 [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1101 .minLen = 2,
1102 .maxLen = IFNAMSIZ },
1103 };
1104 PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1105
1106 /* input buffer has been validated while validating transaction dev op. */
1107 ASSERT(usrParamsCtx->inputBuffer != NULL &&
1108 usrParamsCtx->inputLength > sizeof *msgIn);
1109
1110 if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1111 return STATUS_INVALID_BUFFER_SIZE;
1112 }
1113
1114 if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1115 NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1116 NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1117 ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1118 return STATUS_INVALID_PARAMETER;
1119 }
1120
1121 OvsAcquireCtrlLock();
1122 if (!gOvsSwitchContext) {
1123 OvsReleaseCtrlLock();
1124 return STATUS_INVALID_PARAMETER;
1125 }
1126
1127 vportGet.portNo = 0;
1128 RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1129 NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1130
1131 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1132 status = OvsGetExtInfoIoctl(&vportGet, &info);
1133 if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1134 nlError = NL_ERROR_NODEV;
1135 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1136 OvsReleaseCtrlLock();
1137 goto cleanup;
1138 }
1139 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1140
1141 status = CreateNetlinkMesgForNetdev(&info, msgIn,
1142 usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1143 gOvsSwitchContext->dpNo);
1144 if (status == STATUS_SUCCESS) {
1145 *replyLen = msgOut->nlMsg.nlmsgLen;
1146 }
1147 OvsReleaseCtrlLock();
1148
1149cleanup:
1150 if (nlError != NL_ERROR_SUCCESS) {
1151 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1152 usrParamsCtx->outputBuffer;
1153
1154 BuildErrorMsg(msgIn, msgError, nlError);
1155 *replyLen = msgError->nlMsg.nlmsgLen;
1156 }
1157
1158 return STATUS_SUCCESS;
2b144cbb 1159}
c803536e
SS
1160
1161
be581675
NR
1162/*
1163 * --------------------------------------------------------------------------
1164 * Utility function to construct an OVS_MESSAGE for the specified vport. The
1165 * OVS_MESSAGE contains the output of a netdev command.
1166 * --------------------------------------------------------------------------
1167 */
1168static NTSTATUS
1169CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1170 POVS_MESSAGE msgIn,
1171 PVOID outBuffer,
1172 UINT32 outBufLen,
1173 int dpIfIndex)
1174{
1175 NL_BUFFER nlBuffer;
1176 BOOLEAN ok;
1177 OVS_MESSAGE msgOut;
1178 PNL_MSG_HDR nlMsg;
1179 UINT32 netdevFlags = 0;
1180
1181 NlBufInit(&nlBuffer, outBuffer, outBufLen);
1182
1183 BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1184 msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1185
1186 ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1187 if (!ok) {
1188 return STATUS_INSUFFICIENT_RESOURCES;
1189 }
1190
1191 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1192 info->portNo);
1193 if (!ok) {
1194 return STATUS_INSUFFICIENT_RESOURCES;
1195 }
1196
1197 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1198 if (!ok) {
1199 return STATUS_INSUFFICIENT_RESOURCES;
1200 }
1201
1202 ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1203 info->name);
1204 if (!ok) {
1205 return STATUS_INSUFFICIENT_RESOURCES;
1206 }
1207
1208 ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1209 (PCHAR)info->macAddress, sizeof (info->macAddress));
1210 if (!ok) {
1211 return STATUS_INSUFFICIENT_RESOURCES;
1212 }
1213
1214 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1215 if (!ok) {
1216 return STATUS_INSUFFICIENT_RESOURCES;
1217 }
1218
1219 if (info->status != OVS_EVENT_CONNECT) {
1220 netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1221 }
1222 ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1223 netdevFlags);
1224 if (!ok) {
1225 return STATUS_INSUFFICIENT_RESOURCES;
1226 }
1227
1228 /*
1229 * XXX: add netdev_stats when we have the definition available in the
1230 * kernel.
1231 */
1232
1233 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1234 nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1235
1236 return STATUS_SUCCESS;
1237}
1238
c803536e
SS
1239static __inline VOID
1240OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1241{
1242 while ((!switchContext->isActivated) &&
1243 (!switchContext->isActivateFailed)) {
1244 /* Wait for the switch to be active and
1245 * the list of ports in OVS to be initialized. */
1246 NdisMSleep(sleepMicroSec);
1247 }
1248}