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