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