datapath-windows: Rename hyper-v switch port and nic handlers
[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->isValidationPort = portParam->IsValidationPort;
613     vport->portType = portParam->PortType;
614     vport->portState = portParam->PortState;
615     vport->portId = portParam->PortId;
616     vport->nicState = NdisSwitchNicStateUnknown;
617     vport->isExternal = FALSE;
618
619     switch (vport->portType) {
620     case NdisSwitchPortTypeExternal:
621         vport->isExternal = TRUE;
622         vport->ovsType = OVS_VPORT_TYPE_NETDEV;
623         break;
624     case NdisSwitchPortTypeInternal:
625         vport->ovsType = OVS_VPORT_TYPE_INTERNAL;
626         break;
627     case NdisSwitchPortTypeSynthetic:
628     case NdisSwitchPortTypeEmulated:
629         vport->ovsType = OVS_VPORT_TYPE_NETDEV;
630         break;
631     }
632     RtlCopyMemory(&vport->portName, &portParam->PortName,
633                   sizeof (NDIS_SWITCH_PORT_NAME));
634     switch (vport->portState) {
635     case NdisSwitchPortStateCreated:
636         vport->ovsState = OVS_STATE_PORT_CREATED;
637         break;
638     case NdisSwitchPortStateTeardown:
639         vport->ovsState = OVS_STATE_PORT_TEAR_DOWN;
640         break;
641     case NdisSwitchPortStateDeleted:
642         vport->ovsState = OVS_STATE_PORT_DELETED;
643         break;
644     }
645 }
646
647
648 static VOID
649 OvsInitVportWithNicParam(POVS_SWITCH_CONTEXT switchContext,
650                          POVS_VPORT_ENTRY vport,
651                          PNDIS_SWITCH_NIC_PARAMETERS nicParam)
652 {
653     ASSERT(vport->portId == nicParam->PortId);
654     ASSERT(vport->ovsState == OVS_STATE_PORT_CREATED);
655
656     UNREFERENCED_PARAMETER(switchContext);
657
658     RtlCopyMemory(vport->permMacAddress, nicParam->PermanentMacAddress,
659                   sizeof (nicParam->PermanentMacAddress));
660     RtlCopyMemory(vport->currMacAddress, nicParam->CurrentMacAddress,
661                   sizeof (nicParam->CurrentMacAddress));
662
663     if (nicParam->NicType == NdisSwitchNicTypeSynthetic ||
664         nicParam->NicType == NdisSwitchNicTypeEmulated) {
665         RtlCopyMemory(vport->vmMacAddress, nicParam->VMMacAddress,
666                       sizeof (nicParam->VMMacAddress));
667         RtlCopyMemory(&vport->vmName, &nicParam->VmName,
668                       sizeof (nicParam->VmName));
669     } else {
670         RtlCopyMemory(&vport->netCfgInstanceId, &nicParam->NetCfgInstanceId,
671                       sizeof (nicParam->NetCfgInstanceId));
672     }
673     RtlCopyMemory(&vport->nicName, &nicParam->NicName,
674                   sizeof (nicParam->NicName));
675     vport->mtu = nicParam->MTU;
676     vport->nicState = nicParam->NicState;
677     vport->nicIndex = nicParam->NicIndex;
678     vport->numaNodeId = nicParam->NumaNodeId;
679
680     switch (vport->nicState) {
681     case NdisSwitchNicStateCreated:
682         vport->ovsState = OVS_STATE_NIC_CREATED;
683         break;
684     case NdisSwitchNicStateConnected:
685         vport->ovsState = OVS_STATE_CONNECTED;
686         break;
687     case NdisSwitchNicStateDisconnected:
688         vport->ovsState = OVS_STATE_NIC_CREATED;
689         break;
690     case NdisSwitchNicStateDeleted:
691         vport->ovsState = OVS_STATE_PORT_CREATED;
692         break;
693     }
694 }
695
696 static VOID
697 OvsInitPhysNicVport(POVS_VPORT_ENTRY vport,
698                     POVS_VPORT_ENTRY virtVport,
699                     UINT32 nicIndex)
700 {
701     vport->isValidationPort = virtVport->isValidationPort;
702     vport->portType = virtVport->portType;
703     vport->portState = virtVport->portState;
704     vport->portId = virtVport->portId;
705     vport->nicState = NdisSwitchNicStateUnknown;
706     vport->ovsType = OVS_VPORT_TYPE_NETDEV;
707     vport->isExternal = TRUE;
708     vport->nicIndex = (NDIS_SWITCH_NIC_INDEX)nicIndex;
709     RtlCopyMemory(&vport->portName, &virtVport->portName,
710                   sizeof (NDIS_SWITCH_PORT_NAME));
711     vport->ovsState = OVS_STATE_PORT_CREATED;
712 }
713 static NDIS_STATUS
714 OvsInitVportCommon(POVS_SWITCH_CONTEXT switchContext,
715 POVS_VPORT_ENTRY vport)
716 {
717     UINT32 hash;
718     size_t len;
719     if (vport->portType != NdisSwitchPortTypeExternal ||
720         vport->nicIndex != 0) {
721         vport->portNo = OvsGetVportNo(switchContext, vport->nicIndex,
722             vport->ovsType, vport->portType == NdisSwitchPortTypeExternal);
723         if (vport->portNo == 0) {
724             return NDIS_STATUS_RESOURCES;
725         }
726         ASSERT(OVS_IS_VPORT_ENTRY_NULL(switchContext,
727             OVS_VPORT_INDEX(vport->portNo)));
728
729         switchContext->vportArray[OVS_VPORT_INDEX(vport->portNo)] = vport;
730     }
731     switch (vport->portType) {
732     case NdisSwitchPortTypeExternal:
733         if (vport->nicIndex == 0) {
734             switchContext->externalPortId = vport->portId;
735             switchContext->externalVport = vport;
736             RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
737                 "external.virtualAdapter");
738         }
739         else {
740             switchContext->numPhysicalNics++;
741             RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
742                 "external.%lu", (UINT32)vport->nicIndex);
743         }
744         break;
745     case NdisSwitchPortTypeInternal:
746         switchContext->internalPortId = vport->portId;
747         switchContext->internalVport = vport;
748         RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
749             "internal");
750         break;
751     case NdisSwitchPortTypeSynthetic:
752         RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
753             "vmNICSyn.%lx", vport->portNo);
754         break;
755     case NdisSwitchPortTypeEmulated:
756         RtlStringCbPrintfA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1,
757             "vmNICEmu.%lx", vport->portNo);
758         break;
759     }
760     StringCbLengthA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
761     vport->ovsNameLen = (UINT32)len;
762     if (vport->portType == NdisSwitchPortTypeExternal &&
763         vport->nicIndex == 0) {
764         return NDIS_STATUS_SUCCESS;
765     }
766     hash = OvsJhashBytes(vport->ovsName, vport->ovsNameLen, OVS_HASH_BASIS);
767     InsertHeadList(&switchContext->nameHashArray[hash & OVS_VPORT_MASK],
768         &vport->nameLink);
769     hash = OvsJhashWords(&vport->portId, 1, OVS_HASH_BASIS);
770     InsertHeadList(&switchContext->portHashArray[hash & OVS_VPORT_MASK],
771         &vport->portLink);
772     switchContext->numVports++;
773     return NDIS_STATUS_SUCCESS;
774 }
775
776
777 static VOID
778 OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
779                         POVS_VPORT_ENTRY vport)
780 {
781     UINT64 gen = vport->portNo >> 24;
782
783     if (vport->isExternal) {
784         if (vport->nicIndex == 0) {
785             ASSERT(switchContext->numPhysicalNics == 0);
786             switchContext->externalPortId = 0;
787             switchContext->externalVport = NULL;
788             OvsFreeMemory(vport);
789             return;
790         } else {
791             ASSERT(switchContext->numPhysicalNics);
792             switchContext->numPhysicalNics--;
793         }
794     }
795
796     switch (vport->ovsType) {
797     case OVS_VPORT_TYPE_INTERNAL:
798         switchContext->internalPortId = 0;
799         switchContext->internalVport = NULL;
800         OvsInternalAdapterDown();
801         break;
802     case OVS_VPORT_TYPE_VXLAN:
803         OvsCleanupVxlanTunnel(vport);
804         break;
805     case OVS_VPORT_TYPE_GRE:
806     case OVS_VPORT_TYPE_GRE64:
807         break;
808     case OVS_VPORT_TYPE_NETDEV:
809     default:
810         break;
811     }
812
813     RemoveEntryList(&vport->nameLink);
814     RemoveEntryList(&vport->portLink);
815     gen = (gen + 1) & 0xff;
816     switchContext->vportArray[OVS_VPORT_INDEX(vport->portNo)] =
817                      (PVOID)(UINT64)gen;
818     switchContext->numVports--;
819     OvsFreeMemory(vport);
820 }
821
822
823 NDIS_STATUS
824 OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
825 {
826     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
827     ULONG arrIndex;
828     PNDIS_SWITCH_PORT_PARAMETERS portParam;
829     PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
830     POVS_VPORT_ENTRY vport;
831
832     OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
833
834     status = OvsGetPortsOnSwitch(switchContext, &portArray);
835     if (status != NDIS_STATUS_SUCCESS) {
836         goto cleanup;
837     }
838
839     for (arrIndex = 0; arrIndex < portArray->NumElements; arrIndex++) {
840          portParam = NDIS_SWITCH_PORT_AT_ARRAY_INDEX(portArray, arrIndex);
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->isValidationPort = FALSE;
958     vport->ovsType = addReq->type;
959     vport->ovsState = OVS_STATE_PORT_CREATED;
960     RtlCopyMemory(vport->ovsName, addReq->name, OVS_MAX_PORT_NAME_LENGTH);
961     vport->ovsName[OVS_MAX_PORT_NAME_LENGTH - 1] = 0;
962     StringCbLengthA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
963     vport->ovsNameLen = (UINT32)len;
964     switch (addReq->type) {
965     case OVS_VPORT_TYPE_GRE:
966         break;
967     case OVS_VPORT_TYPE_GRE64:
968         break;
969     case OVS_VPORT_TYPE_VXLAN:
970         status = OvsInitVxlanTunnel(vport, addReq);
971         break;
972     default:
973         ASSERT(0);
974     }
975     return status;
976 }
977
978 NTSTATUS
979 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
980                                 CHAR *str,
981                                 UINT16 maxStrLen)
982 {
983     ANSI_STRING astr;
984     UNICODE_STRING ustr;
985     NTSTATUS status;
986     UINT32 size;
987
988     ustr.Buffer = wStr->String;
989     ustr.Length = wStr->Length;
990     ustr.MaximumLength = IF_MAX_STRING_SIZE;
991
992     astr.Buffer = str;
993     astr.MaximumLength = maxStrLen;
994     astr.Length = 0;
995
996     size = RtlUnicodeStringToAnsiSize(&ustr);
997     if (size > maxStrLen) {
998         return STATUS_BUFFER_OVERFLOW;
999     }
1000
1001     status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
1002
1003     ASSERT(status == STATUS_SUCCESS);
1004     if (status != STATUS_SUCCESS) {
1005         return status;
1006     }
1007     ASSERT(astr.Length <= maxStrLen);
1008     str[astr.Length] = 0;
1009     return STATUS_SUCCESS;
1010 }
1011
1012
1013 /*
1014  * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for
1015  * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1.
1016  */
1017 #define USE_NEW_VPORT_ADD_WORKFLOW 0
1018 NTSTATUS
1019 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
1020                    POVS_VPORT_EXT_INFO extInfo)
1021 {
1022     POVS_VPORT_ENTRY vport;
1023     size_t len;
1024     LOCK_STATE_EX lockState;
1025     NTSTATUS status = STATUS_SUCCESS;
1026     BOOLEAN doConvert = FALSE;
1027
1028     RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
1029     NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1030                           NDIS_RWL_AT_DISPATCH_LEVEL);
1031     if (vportGet->portNo == 0) {
1032         StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1033 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1034         vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name,
1035                                       (UINT32)len);
1036 #else
1037         vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name);
1038 #endif
1039     } else {
1040         vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
1041     }
1042     if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1043                           vport->ovsState != OVS_STATE_NIC_CREATED)) {
1044         NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1045         NdisReleaseSpinLock(gOvsCtrlLock);
1046         if (vportGet->portNo) {
1047             OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
1048         } else {
1049             OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
1050         }
1051         status = STATUS_DEVICE_DOES_NOT_EXIST;
1052         goto ext_info_done;
1053     }
1054     extInfo->dpNo = vportGet->dpNo;
1055     extInfo->portNo = vport->portNo;
1056     RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1057                   sizeof (vport->currMacAddress));
1058     RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1059                   sizeof (vport->permMacAddress));
1060     if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1061         RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1062                       sizeof (vport->vmMacAddress));
1063     }
1064     extInfo->nicIndex = vport->nicIndex;
1065     extInfo->portId = vport->portId;
1066     extInfo->type = vport->ovsType;
1067     extInfo->mtu = vport->mtu;
1068     /*
1069      * TO be revisit XXX
1070      */
1071     if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1072        extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1073     } else if (vport->ovsState == OVS_STATE_CONNECTED) {
1074        extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1075     } else {
1076        extInfo->status = OVS_EVENT_DISCONNECT;
1077     }
1078     if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1079         (vport->ovsState == OVS_STATE_NIC_CREATED  ||
1080          vport->ovsState == OVS_STATE_CONNECTED)) {
1081         doConvert = TRUE;
1082     } else {
1083         extInfo->vmUUID[0] = 0;
1084         extInfo->vifUUID[0] = 0;
1085     }
1086 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1087     RtlCopyMemory(extInfo->name, vport->ovsName, vport->ovsNameLen + 1);
1088 #endif
1089     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1090     NdisReleaseSpinLock(gOvsCtrlLock);
1091     if (doConvert) {
1092 #if USE_NEW_VPORT_ADD_WORKFLOW == 1
1093         status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1094                                                  extInfo->name,
1095                                                  OVS_MAX_PORT_NAME_LENGTH);
1096         if (status != STATUS_SUCCESS) {
1097             OVS_LOG_INFO("Fail to convert NIC name.");
1098             extInfo->vmUUID[0] = 0;
1099         }
1100 #endif
1101
1102         status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1103                                                  extInfo->vmUUID,
1104                                                  OVS_MAX_VM_UUID_LEN);
1105         if (status != STATUS_SUCCESS) {
1106             OVS_LOG_INFO("Fail to convert VM name.");
1107             extInfo->vmUUID[0] = 0;
1108         }
1109
1110         status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1111                                                  extInfo->vifUUID,
1112                                                  OVS_MAX_VIF_UUID_LEN);
1113         if (status != STATUS_SUCCESS) {
1114             OVS_LOG_INFO("Fail to convert nic UUID");
1115             extInfo->vifUUID[0] = 0;
1116         }
1117         /*
1118          * for now ignore status
1119          */
1120         status = STATUS_SUCCESS;
1121     }
1122
1123 ext_info_done:
1124     return status;
1125 }
1126
1127 /*
1128  * --------------------------------------------------------------------------
1129  *  Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1130  * --------------------------------------------------------------------------
1131  */
1132 NTSTATUS
1133 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1134                        UINT32 *replyLen)
1135 {
1136     NTSTATUS status = STATUS_SUCCESS;
1137     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1138     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1139     NL_ERROR nlError = NL_ERROR_SUCCESS;
1140     OVS_VPORT_GET vportGet;
1141     OVS_VPORT_EXT_INFO info;
1142     LOCK_STATE_EX lockState;
1143
1144     static const NL_POLICY ovsNetdevPolicy[] = {
1145         [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1146                                        .minLen = 2,
1147                                        .maxLen = IFNAMSIZ },
1148     };
1149     PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1150
1151     /* input buffer has been validated while validating transaction dev op. */
1152     ASSERT(usrParamsCtx->inputBuffer != NULL &&
1153            usrParamsCtx->inputLength > sizeof *msgIn);
1154
1155     if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1156         return STATUS_INVALID_BUFFER_SIZE;
1157     }
1158
1159     if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1160         NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1161         NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1162         ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1163         return STATUS_INVALID_PARAMETER;
1164     }
1165
1166     OvsAcquireCtrlLock();
1167     if (!gOvsSwitchContext) {
1168         OvsReleaseCtrlLock();
1169         return STATUS_INVALID_PARAMETER;
1170     }
1171
1172     vportGet.portNo = 0;
1173     RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1174                   NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1175
1176     NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1177     status = OvsGetExtInfoIoctl(&vportGet, &info);
1178     if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1179         nlError = NL_ERROR_NODEV;
1180         NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1181         OvsReleaseCtrlLock();
1182         goto cleanup;
1183     }
1184     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1185
1186     status = CreateNetlinkMesgForNetdev(&info, msgIn,
1187                  usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1188                  gOvsSwitchContext->dpNo);
1189     if (status == STATUS_SUCCESS) {
1190         *replyLen = msgOut->nlMsg.nlmsgLen;
1191     }
1192     OvsReleaseCtrlLock();
1193
1194 cleanup:
1195     if (nlError != NL_ERROR_SUCCESS) {
1196         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1197             usrParamsCtx->outputBuffer;
1198
1199         BuildErrorMsg(msgIn, msgError, nlError);
1200         *replyLen = msgError->nlMsg.nlmsgLen;
1201     }
1202
1203     return STATUS_SUCCESS;
1204 }
1205
1206
1207 /*
1208  * --------------------------------------------------------------------------
1209  *  Utility function to construct an OVS_MESSAGE for the specified vport. The
1210  *  OVS_MESSAGE contains the output of a netdev command.
1211  * --------------------------------------------------------------------------
1212  */
1213 static NTSTATUS
1214 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1215                            POVS_MESSAGE msgIn,
1216                            PVOID outBuffer,
1217                            UINT32 outBufLen,
1218                            int dpIfIndex)
1219 {
1220     NL_BUFFER nlBuffer;
1221     BOOLEAN ok;
1222     OVS_MESSAGE msgOut;
1223     PNL_MSG_HDR nlMsg;
1224     UINT32 netdevFlags = 0;
1225
1226     NlBufInit(&nlBuffer, outBuffer, outBufLen);
1227
1228     BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1229     msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1230
1231     ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1232     if (!ok) {
1233         return STATUS_INSUFFICIENT_RESOURCES;
1234     }
1235
1236     ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1237                          info->portNo);
1238     if (!ok) {
1239         return STATUS_INSUFFICIENT_RESOURCES;
1240     }
1241
1242     ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1243     if (!ok) {
1244         return STATUS_INSUFFICIENT_RESOURCES;
1245     }
1246
1247     ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1248                             info->name);
1249     if (!ok) {
1250         return STATUS_INSUFFICIENT_RESOURCES;
1251     }
1252
1253     ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1254              (PCHAR)info->macAddress, sizeof (info->macAddress));
1255     if (!ok) {
1256         return STATUS_INSUFFICIENT_RESOURCES;
1257     }
1258
1259     ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1260     if (!ok) {
1261         return STATUS_INSUFFICIENT_RESOURCES;
1262     }
1263
1264     if (info->status != OVS_EVENT_CONNECT) {
1265         netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1266     }
1267     ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1268                          netdevFlags);
1269     if (!ok) {
1270         return STATUS_INSUFFICIENT_RESOURCES;
1271     }
1272
1273     /*
1274      * XXX: add netdev_stats when we have the definition available in the
1275      * kernel.
1276      */
1277
1278     nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1279     nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1280
1281     return STATUS_SUCCESS;
1282 }
1283
1284 static __inline VOID
1285 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1286 {
1287     while ((!switchContext->isActivated) &&
1288           (!switchContext->isActivateFailed)) {
1289         /* Wait for the switch to be active and
1290          * the list of ports in OVS to be initialized. */
1291         NdisMSleep(sleepMicroSec);
1292     }
1293 }