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