datapath-windows: Update OvsGetExtInfoIoctl() to the new vport add workflow
[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 OvsCreatePort(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 OvsTeardownPort(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 OvsDeletePort(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 OvsCreateNic(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 OvsConnectNic(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 OvsUpdateNic(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 OvsDisconnectNic(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 OvsDeleteNic(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 OvsDumpVportIoctl(PVOID inputBuffer,
952                   UINT32 inputLength,
953                   PVOID outputBuffer,
954                   UINT32 outputLength,
955                   UINT32 *replyLen)
956 {
957     UINT32 numVports, count;
958     UINT32 dpNo, i;
959     UINT32 *outPtr;
960     POVS_VPORT_ENTRY vport;
961     LOCK_STATE_EX lockState;
962
963     if (inputLength < sizeof (UINT32)) {
964         return STATUS_INVALID_PARAMETER;
965     }
966     dpNo = *(UINT32 *)inputBuffer;
967
968     NdisAcquireSpinLock(gOvsCtrlLock);
969     if (gOvsSwitchContext == NULL ||
970         gOvsSwitchContext->dpNo != dpNo) {
971         NdisReleaseSpinLock(gOvsCtrlLock);
972         return STATUS_INVALID_PARAMETER;
973     }
974     /*
975      * We should hold SwitchContext RW lock
976      */
977
978     NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
979                           NDIS_RWL_AT_DISPATCH_LEVEL);
980     numVports = outputLength/sizeof (UINT32);
981     numVports = MIN(gOvsSwitchContext->numVports, numVports);
982     outPtr = (UINT32 *)outputBuffer;
983     for (i = 0, count = 0;
984          i < OVS_MAX_VPORT_ARRAY_SIZE && count < numVports; i++) {
985         vport = (POVS_VPORT_ENTRY)gOvsSwitchContext->vportArray[i];
986         if (OVS_IS_VPORT_ENTRY_NULL(gOvsSwitchContext, i)) {
987             continue;
988         }
989         if (vport->ovsState == OVS_STATE_CONNECTED ||
990             vport->ovsState == OVS_STATE_NIC_CREATED) {
991             *outPtr = vport->portNo;
992             outPtr++;
993             count++;
994         }
995     }
996     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
997     NdisReleaseSpinLock(gOvsCtrlLock);
998     *replyLen = count * sizeof (UINT32);
999     return STATUS_SUCCESS;
1000 }
1001
1002
1003 NTSTATUS
1004 OvsGetVportIoctl(PVOID inputBuffer,
1005                  UINT32 inputLength,
1006                  PVOID outputBuffer,
1007                  UINT32 outputLength,
1008                  UINT32 *replyLen)
1009 {
1010     UINT32 dpNo;
1011     POVS_VPORT_GET get;
1012     POVS_VPORT_INFO info;
1013     POVS_VPORT_ENTRY vport;
1014     size_t len;
1015     LOCK_STATE_EX lockState;
1016
1017     if (inputLength < sizeof (OVS_VPORT_GET) ||
1018         outputLength < sizeof (OVS_VPORT_INFO)) {
1019         return STATUS_INVALID_PARAMETER;
1020     }
1021     get = (POVS_VPORT_GET)inputBuffer;
1022     dpNo = get->dpNo;
1023     info = (POVS_VPORT_INFO)outputBuffer;
1024     RtlZeroMemory(info, sizeof (POVS_VPORT_INFO));
1025
1026     NdisAcquireSpinLock(gOvsCtrlLock);
1027     if (gOvsSwitchContext == NULL ||
1028         gOvsSwitchContext->dpNo != dpNo) {
1029         NdisReleaseSpinLock(gOvsCtrlLock);
1030         return STATUS_INVALID_PARAMETER;
1031     }
1032
1033     NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1034                           NDIS_RWL_AT_DISPATCH_LEVEL);
1035     if (get->portNo == 0) {
1036         StringCbLengthA(get->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1037         vport = OvsFindVportByOvsName(gOvsSwitchContext, get->name, (UINT32)len);
1038     } else {
1039         vport = OvsFindVportByPortNo(gOvsSwitchContext, get->portNo);
1040     }
1041     if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1042                           vport->ovsState != OVS_STATE_NIC_CREATED)) {
1043         NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1044         NdisReleaseSpinLock(gOvsCtrlLock);
1045         /*
1046          * XXX Change to NO DEVICE
1047          */
1048         return STATUS_DEVICE_DOES_NOT_EXIST;
1049     }
1050     info->dpNo = dpNo;
1051     info->portNo = vport->portNo;
1052     info->type = vport->ovsType;
1053     RtlCopyMemory(info->macAddress, vport->permMacAddress,
1054                   sizeof (vport->permMacAddress));
1055     RtlCopyMemory(info->name, vport->ovsName, vport->ovsNameLen + 1);
1056
1057     info->rxPackets = vport->stats.rxPackets;
1058     info->rxBytes = vport->stats.rxBytes;
1059     info->txPackets = vport->stats.txPackets;
1060     info->txBytes = vport->stats.txBytes;
1061     info->rxErrors = vport->errStats.rxErrors;
1062     info->txErrors = vport->errStats.txErrors;
1063     info->rxDropped = vport->errStats.rxDropped;
1064     info->txDropped = vport->errStats.txDropped;
1065
1066     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1067     NdisReleaseSpinLock(gOvsCtrlLock);
1068     *replyLen = sizeof (OVS_VPORT_INFO);
1069     return STATUS_SUCCESS;
1070 }
1071
1072
1073 NTSTATUS
1074 OvsInitTunnelVport(POVS_VPORT_ENTRY vport,
1075                    POVS_VPORT_ADD_REQUEST addReq)
1076 {
1077     size_t len;
1078     NTSTATUS status = STATUS_SUCCESS;
1079
1080     vport->isValidationPort = FALSE;
1081     vport->ovsType = addReq->type;
1082     vport->ovsState = OVS_STATE_PORT_CREATED;
1083     RtlCopyMemory(vport->ovsName, addReq->name, OVS_MAX_PORT_NAME_LENGTH);
1084     vport->ovsName[OVS_MAX_PORT_NAME_LENGTH - 1] = 0;
1085     StringCbLengthA(vport->ovsName, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1086     vport->ovsNameLen = (UINT32)len;
1087     switch (addReq->type) {
1088     case OVS_VPORT_TYPE_GRE:
1089         break;
1090     case OVS_VPORT_TYPE_GRE64:
1091         break;
1092     case OVS_VPORT_TYPE_VXLAN:
1093         status = OvsInitVxlanTunnel(vport, addReq);
1094         break;
1095     default:
1096         ASSERT(0);
1097     }
1098     return status;
1099 }
1100
1101 NTSTATUS
1102 OvsAddVportIoctl(PVOID inputBuffer,
1103                  UINT32 inputLength,
1104                  PVOID outputBuffer,
1105                  UINT32 outputLength,
1106                  UINT32 *replyLen)
1107 {
1108     NTSTATUS status = STATUS_SUCCESS;
1109     POVS_VPORT_INFO vportInfo;
1110     POVS_VPORT_ADD_REQUEST addReq;
1111     POVS_VPORT_ENTRY vport;
1112     LOCK_STATE_EX lockState;
1113     UINT32 index;
1114     UINT32 portNo;
1115
1116     OVS_LOG_TRACE("Enter: inputLength: %u, outputLength: %u",
1117                   inputLength, outputLength);
1118     if (inputLength < sizeof (OVS_VPORT_ADD_REQUEST) ||
1119         outputLength < sizeof (OVS_VPORT_INFO)) {
1120         status = STATUS_INVALID_PARAMETER;
1121         goto vport_add_done;
1122     }
1123     addReq = (POVS_VPORT_ADD_REQUEST)inputBuffer;
1124     addReq->name[OVS_MAX_PORT_NAME_LENGTH - 1] = 0;
1125
1126     switch (addReq->type) {
1127     case OVS_VPORT_TYPE_GRE:
1128         index = OVS_GRE_VPORT_INDEX;
1129         break;
1130     case OVS_VPORT_TYPE_GRE64:
1131         index = OVS_GRE64_VPORT_INDEX;
1132         break;
1133     case OVS_VPORT_TYPE_VXLAN:
1134         index = OVS_VXLAN_VPORT_INDEX;
1135         break;
1136     default:
1137         status = STATUS_NOT_SUPPORTED;
1138         goto vport_add_done;
1139     }
1140
1141     vport = (POVS_VPORT_ENTRY)OvsAllocateVport();
1142     if (vport == NULL) {
1143         status = STATUS_INSUFFICIENT_RESOURCES;
1144         goto vport_add_done;
1145     }
1146
1147     NdisAcquireSpinLock(gOvsCtrlLock);
1148     if (gOvsSwitchContext == NULL ||
1149         gOvsSwitchContext->dpNo != addReq->dpNo) {
1150         NdisReleaseSpinLock(gOvsCtrlLock);
1151         status = STATUS_INVALID_PARAMETER;
1152         OvsFreeMemory(vport);
1153         goto vport_add_done;
1154     }
1155     NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1156                           NDIS_RWL_AT_DISPATCH_LEVEL);
1157     if (!OVS_IS_VPORT_ENTRY_NULL(gOvsSwitchContext, index)) {
1158         status = STATUS_DEVICE_BUSY;
1159         NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1160         NdisReleaseSpinLock(gOvsCtrlLock);
1161         OvsFreeMemory(vport);
1162         goto vport_add_done;
1163     }
1164
1165     status = OvsInitTunnelVport(vport, addReq);
1166     if (status != STATUS_SUCCESS) {
1167         NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1168         NdisReleaseSpinLock(gOvsCtrlLock);
1169         OvsFreeMemory(vport);
1170         goto vport_add_done;
1171     }
1172
1173     status = OvsInitVportCommon(gOvsSwitchContext, vport);
1174     ASSERT(status == NDIS_STATUS_SUCCESS);
1175
1176     vport->ovsState = OVS_STATE_CONNECTED;
1177     vport->nicState = NdisSwitchNicStateConnected;
1178
1179     vportInfo = (POVS_VPORT_INFO)outputBuffer;
1180
1181     RtlZeroMemory(vportInfo, sizeof (POVS_VPORT_INFO));
1182     vportInfo->dpNo = gOvsSwitchContext->dpNo;
1183     vportInfo->portNo = vport->portNo;
1184     vportInfo->type = vport->ovsType;
1185     RtlCopyMemory(vportInfo->name, vport->ovsName, vport->ovsNameLen + 1);
1186     portNo = vport->portNo;
1187
1188     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1189     NdisReleaseSpinLock(gOvsCtrlLock);
1190     OvsPostEvent(portNo, OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP);
1191     *replyLen = sizeof (OVS_VPORT_INFO);
1192     status = STATUS_SUCCESS;
1193 vport_add_done:
1194     OVS_LOG_TRACE("Exit: byteReturned: %u, status: %x",
1195                   *replyLen, status);
1196     return status;
1197 }
1198
1199 NTSTATUS
1200 OvsDelVportIoctl(PVOID inputBuffer,
1201                  UINT32 inputLength,
1202                  UINT32 *replyLen)
1203 {
1204     NTSTATUS status = STATUS_SUCCESS;
1205     POVS_VPORT_DELETE_REQUEST delReq;
1206     LOCK_STATE_EX lockState;
1207     POVS_VPORT_ENTRY vport;
1208     size_t len;
1209     UINT32 portNo = 0;
1210
1211     OVS_LOG_TRACE("Enter: inputLength: %u", inputLength);
1212
1213     if (inputLength < sizeof (OVS_VPORT_DELETE_REQUEST)) {
1214         status = STATUS_INVALID_PARAMETER;
1215         goto vport_del_done;
1216     }
1217     delReq = (POVS_VPORT_DELETE_REQUEST)inputBuffer;
1218
1219     NdisAcquireSpinLock(gOvsCtrlLock);
1220     if (gOvsSwitchContext == NULL ||
1221         gOvsSwitchContext->dpNo != delReq->dpNo) {
1222         NdisReleaseSpinLock(gOvsCtrlLock);
1223         status = STATUS_INVALID_PARAMETER;
1224         goto vport_del_done;
1225     }
1226     NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1227                           NDIS_RWL_AT_DISPATCH_LEVEL);
1228     if (delReq->portNo == 0) {
1229         StringCbLengthA(delReq->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1230         vport = OvsFindVportByOvsName(gOvsSwitchContext, delReq->name,
1231                                       (UINT32)len);
1232     } else {
1233         vport = OvsFindVportByPortNo(gOvsSwitchContext, delReq->portNo);
1234     }
1235     if (vport) {
1236         OVS_LOG_INFO("delete vport: %s, portNo: %x", vport->ovsName,
1237                      vport->portNo);
1238         portNo = vport->portNo;
1239         OvsRemoveAndDeleteVport(gOvsSwitchContext, vport);
1240     } else {
1241         status = STATUS_DEVICE_DOES_NOT_EXIST;
1242     }
1243     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1244     NdisReleaseSpinLock(gOvsCtrlLock);
1245     if (vport) {
1246         OvsPostEvent(portNo, OVS_EVENT_DISCONNECT | OVS_EVENT_LINK_DOWN);
1247     }
1248 vport_del_done:
1249     OVS_LOG_TRACE("Exit: byteReturned: %u, status: %x",
1250                   *replyLen, status);
1251     return status;
1252 }
1253
1254 NTSTATUS
1255 OvsConvertIfCountedStrToAnsiStr(PIF_COUNTED_STRING wStr,
1256                                 CHAR *str,
1257                                 UINT16 maxStrLen)
1258 {
1259     ANSI_STRING astr;
1260     UNICODE_STRING ustr;
1261     NTSTATUS status;
1262     UINT32 size;
1263
1264     ustr.Buffer = wStr->String;
1265     ustr.Length = wStr->Length;
1266     ustr.MaximumLength = IF_MAX_STRING_SIZE;
1267
1268     astr.Buffer = str;
1269     astr.MaximumLength = maxStrLen;
1270     astr.Length = 0;
1271
1272     size = RtlUnicodeStringToAnsiSize(&ustr);
1273     if (size > maxStrLen) {
1274         return STATUS_BUFFER_OVERFLOW;
1275     }
1276
1277     status = RtlUnicodeStringToAnsiString(&astr, &ustr, FALSE);
1278
1279     ASSERT(status == STATUS_SUCCESS);
1280     if (status != STATUS_SUCCESS) {
1281         return status;
1282     }
1283     ASSERT(astr.Length <= maxStrLen);
1284     str[astr.Length] = 0;
1285     return STATUS_SUCCESS;
1286 }
1287
1288
1289 /*
1290  * XXX: Get rid of USE_NEW_VPORT_ADD_WORKFLOW while checking in the code for
1291  * new vport add workflow, or set USE_NEW_VPORT_ADD_WORKFLOW to 1.
1292  */
1293 #define USE_NEW_VPORT_ADD_WORKFLOW 0
1294 NTSTATUS
1295 OvsGetExtInfoIoctl(POVS_VPORT_GET vportGet,
1296                    POVS_VPORT_EXT_INFO extInfo)
1297 {
1298     POVS_VPORT_ENTRY vport;
1299     size_t len;
1300     LOCK_STATE_EX lockState;
1301     NTSTATUS status = STATUS_SUCCESS;
1302     BOOLEAN doConvert = FALSE;
1303
1304     RtlZeroMemory(extInfo, sizeof (POVS_VPORT_EXT_INFO));
1305     NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState,
1306                           NDIS_RWL_AT_DISPATCH_LEVEL);
1307     if (vportGet->portNo == 0) {
1308         StringCbLengthA(vportGet->name, OVS_MAX_PORT_NAME_LENGTH - 1, &len);
1309 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1310         vport = OvsFindVportByOvsName(gOvsSwitchContext, vportGet->name,
1311                                       (UINT32)len);
1312 #else
1313         vport = OvsFindVportByHvName(gOvsSwitchContext, vportGet->name);
1314 #endif
1315     } else {
1316         vport = OvsFindVportByPortNo(gOvsSwitchContext, vportGet->portNo);
1317     }
1318     if (vport == NULL || (vport->ovsState != OVS_STATE_CONNECTED &&
1319                           vport->ovsState != OVS_STATE_NIC_CREATED)) {
1320         NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1321         NdisReleaseSpinLock(gOvsCtrlLock);
1322         if (vportGet->portNo) {
1323             OVS_LOG_WARN("vport %u does not exist any more", vportGet->portNo);
1324         } else {
1325             OVS_LOG_WARN("vport %s does not exist any more", vportGet->name);
1326         }
1327         status = STATUS_DEVICE_DOES_NOT_EXIST;
1328         goto ext_info_done;
1329     }
1330     extInfo->dpNo = vportGet->dpNo;
1331     extInfo->portNo = vport->portNo;
1332     RtlCopyMemory(extInfo->macAddress, vport->currMacAddress,
1333                   sizeof (vport->currMacAddress));
1334     RtlCopyMemory(extInfo->permMACAddress, vport->permMacAddress,
1335                   sizeof (vport->permMacAddress));
1336     if (vport->ovsType == OVS_VPORT_TYPE_NETDEV) {
1337         RtlCopyMemory(extInfo->vmMACAddress, vport->vmMacAddress,
1338                       sizeof (vport->vmMacAddress));
1339     }
1340     extInfo->nicIndex = vport->nicIndex;
1341     extInfo->portId = vport->portId;
1342     extInfo->type = vport->ovsType;
1343     extInfo->mtu = vport->mtu;
1344     /*
1345      * TO be revisit XXX
1346      */
1347     if (vport->ovsState == OVS_STATE_NIC_CREATED) {
1348        extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_DOWN;
1349     } else if (vport->ovsState == OVS_STATE_CONNECTED) {
1350        extInfo->status = OVS_EVENT_CONNECT | OVS_EVENT_LINK_UP;
1351     } else {
1352        extInfo->status = OVS_EVENT_DISCONNECT;
1353     }
1354     if (extInfo->type == OVS_VPORT_TYPE_NETDEV &&
1355         (vport->ovsState == OVS_STATE_NIC_CREATED  ||
1356          vport->ovsState == OVS_STATE_CONNECTED)) {
1357         doConvert = TRUE;
1358     } else {
1359         extInfo->vmUUID[0] = 0;
1360         extInfo->vifUUID[0] = 0;
1361     }
1362 #if USE_NEW_VPORT_ADD_WORKFLOW == 0
1363     RtlCopyMemory(extInfo->name, vport->ovsName, vport->ovsNameLen + 1);
1364 #endif
1365     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1366     NdisReleaseSpinLock(gOvsCtrlLock);
1367     if (doConvert) {
1368 #if USE_NEW_VPORT_ADD_WORKFLOW == 1
1369         status = OvsConvertIfCountedStrToAnsiStr(&vport->portFriendlyName,
1370                                                  extInfo->name,
1371                                                  OVS_MAX_PORT_NAME_LENGTH);
1372         if (status != STATUS_SUCCESS) {
1373             OVS_LOG_INFO("Fail to convert NIC name.");
1374             extInfo->vmUUID[0] = 0;
1375         }
1376 #endif
1377
1378         status = OvsConvertIfCountedStrToAnsiStr(&vport->vmName,
1379                                                  extInfo->vmUUID,
1380                                                  OVS_MAX_VM_UUID_LEN);
1381         if (status != STATUS_SUCCESS) {
1382             OVS_LOG_INFO("Fail to convert VM name.");
1383             extInfo->vmUUID[0] = 0;
1384         }
1385
1386         status = OvsConvertIfCountedStrToAnsiStr(&vport->nicName,
1387                                                  extInfo->vifUUID,
1388                                                  OVS_MAX_VIF_UUID_LEN);
1389         if (status != STATUS_SUCCESS) {
1390             OVS_LOG_INFO("Fail to convert nic UUID");
1391             extInfo->vifUUID[0] = 0;
1392         }
1393         /*
1394          * for now ignore status
1395          */
1396         status = STATUS_SUCCESS;
1397     }
1398
1399 ext_info_done:
1400     return status;
1401 }
1402
1403 /*
1404  * --------------------------------------------------------------------------
1405  *  Command Handler for 'OVS_WIN_NETDEV_CMD_GET'.
1406  * --------------------------------------------------------------------------
1407  */
1408 NTSTATUS
1409 OvsGetNetdevCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1410                        UINT32 *replyLen)
1411 {
1412     NTSTATUS status = STATUS_SUCCESS;
1413     POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1414     POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1415     NL_ERROR nlError = NL_ERROR_SUCCESS;
1416     OVS_VPORT_GET vportGet;
1417     OVS_VPORT_EXT_INFO info;
1418     LOCK_STATE_EX lockState;
1419
1420     static const NL_POLICY ovsNetdevPolicy[] = {
1421         [OVS_WIN_NETDEV_ATTR_NAME] = { .type = NL_A_STRING,
1422                                        .minLen = 2,
1423                                        .maxLen = IFNAMSIZ },
1424     };
1425     PNL_ATTR netdevAttrs[ARRAY_SIZE(ovsNetdevPolicy)];
1426
1427     /* input buffer has been validated while validating transaction dev op. */
1428     ASSERT(usrParamsCtx->inputBuffer != NULL &&
1429            usrParamsCtx->inputLength > sizeof *msgIn);
1430
1431     if (msgOut == NULL || usrParamsCtx->outputLength < sizeof *msgOut) {
1432         return STATUS_INVALID_BUFFER_SIZE;
1433     }
1434
1435     if (!NlAttrParse((PNL_MSG_HDR)msgIn,
1436         NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
1437         NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
1438         ovsNetdevPolicy, netdevAttrs, ARRAY_SIZE(netdevAttrs))) {
1439         return STATUS_INVALID_PARAMETER;
1440     }
1441
1442     OvsAcquireCtrlLock();
1443     if (!gOvsSwitchContext) {
1444         OvsReleaseCtrlLock();
1445         return STATUS_INVALID_PARAMETER;
1446     }
1447
1448     vportGet.portNo = 0;
1449     RtlCopyMemory(&vportGet.name, NlAttrGet(netdevAttrs[OVS_VPORT_ATTR_NAME]),
1450                   NlAttrGetSize(netdevAttrs[OVS_VPORT_ATTR_NAME]));
1451
1452     NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
1453     status = OvsGetExtInfoIoctl(&vportGet, &info);
1454     if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
1455         nlError = NL_ERROR_NODEV;
1456         NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1457         OvsReleaseCtrlLock();
1458         goto cleanup;
1459     }
1460     NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
1461
1462     status = CreateNetlinkMesgForNetdev(&info, msgIn,
1463                  usrParamsCtx->outputBuffer, usrParamsCtx->outputLength,
1464                  gOvsSwitchContext->dpNo);
1465     if (status == STATUS_SUCCESS) {
1466         *replyLen = msgOut->nlMsg.nlmsgLen;
1467     }
1468     OvsReleaseCtrlLock();
1469
1470 cleanup:
1471     if (nlError != NL_ERROR_SUCCESS) {
1472         POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
1473             usrParamsCtx->outputBuffer;
1474
1475         BuildErrorMsg(msgIn, msgError, nlError);
1476         *replyLen = msgError->nlMsg.nlmsgLen;
1477     }
1478
1479     return STATUS_SUCCESS;
1480 }
1481
1482
1483 /*
1484  * --------------------------------------------------------------------------
1485  *  Utility function to construct an OVS_MESSAGE for the specified vport. The
1486  *  OVS_MESSAGE contains the output of a netdev command.
1487  * --------------------------------------------------------------------------
1488  */
1489 static NTSTATUS
1490 CreateNetlinkMesgForNetdev(POVS_VPORT_EXT_INFO info,
1491                            POVS_MESSAGE msgIn,
1492                            PVOID outBuffer,
1493                            UINT32 outBufLen,
1494                            int dpIfIndex)
1495 {
1496     NL_BUFFER nlBuffer;
1497     BOOLEAN ok;
1498     OVS_MESSAGE msgOut;
1499     PNL_MSG_HDR nlMsg;
1500     UINT32 netdevFlags = 0;
1501
1502     NlBufInit(&nlBuffer, outBuffer, outBufLen);
1503
1504     BuildReplyMsgFromMsgIn(msgIn, &msgOut, 0);
1505     msgOut.ovsHdr.dp_ifindex = dpIfIndex;
1506
1507     ok = NlMsgPutHead(&nlBuffer, (PCHAR)&msgOut, sizeof msgOut);
1508     if (!ok) {
1509         return STATUS_INSUFFICIENT_RESOURCES;
1510     }
1511
1512     ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_PORT_NO,
1513                          info->portNo);
1514     if (!ok) {
1515         return STATUS_INSUFFICIENT_RESOURCES;
1516     }
1517
1518     ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_TYPE, info->type);
1519     if (!ok) {
1520         return STATUS_INSUFFICIENT_RESOURCES;
1521     }
1522
1523     ok = NlMsgPutTailString(&nlBuffer, OVS_WIN_NETDEV_ATTR_NAME,
1524                             info->name);
1525     if (!ok) {
1526         return STATUS_INSUFFICIENT_RESOURCES;
1527     }
1528
1529     ok = NlMsgPutTailUnspec(&nlBuffer, OVS_WIN_NETDEV_ATTR_MAC_ADDR,
1530              (PCHAR)info->macAddress, sizeof (info->macAddress));
1531     if (!ok) {
1532         return STATUS_INSUFFICIENT_RESOURCES;
1533     }
1534
1535     ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_MTU, info->mtu);
1536     if (!ok) {
1537         return STATUS_INSUFFICIENT_RESOURCES;
1538     }
1539
1540     if (info->status != OVS_EVENT_CONNECT) {
1541         netdevFlags = OVS_WIN_NETDEV_IFF_UP;
1542     }
1543     ok = NlMsgPutTailU32(&nlBuffer, OVS_WIN_NETDEV_ATTR_IF_FLAGS,
1544                          netdevFlags);
1545     if (!ok) {
1546         return STATUS_INSUFFICIENT_RESOURCES;
1547     }
1548
1549     /*
1550      * XXX: add netdev_stats when we have the definition available in the
1551      * kernel.
1552      */
1553
1554     nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0);
1555     nlMsg->nlmsgLen = NlBufSize(&nlBuffer);
1556
1557     return STATUS_SUCCESS;
1558 }
1559
1560 static __inline VOID
1561 OvsWaitActivate(POVS_SWITCH_CONTEXT switchContext, ULONG sleepMicroSec)
1562 {
1563     while ((!switchContext->isActivated) &&
1564           (!switchContext->isActivateFailed)) {
1565         /* Wait for the switch to be active and
1566          * the list of ports in OVS to be initialized. */
1567         NdisMSleep(sleepMicroSec);
1568     }
1569 }