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