datapath-windows: Removed gOvsCtrlLock global spinlock
[cascardo/ovs.git] / datapath-windows / ovsext / Switch.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 /*
18  * This file contains the implementation of the management functionality of the
19  * OVS.
20  */
21
22 #include "precomp.h"
23
24 #include "Switch.h"
25 #include "Vport.h"
26 #include "Event.h"
27 #include "Flow.h"
28 #include "IpHelper.h"
29 #include "Oid.h"
30
31 #ifdef OVS_DBG_MOD
32 #undef OVS_DBG_MOD
33 #endif
34 #define OVS_DBG_MOD OVS_DBG_SWITCH
35 #include "Debug.h"
36
37 POVS_SWITCH_CONTEXT gOvsSwitchContext;
38 LONG volatile gOvsInAttach;
39 UINT64 ovsTimeIncrementPerTick;
40
41 extern NDIS_HANDLE gOvsExtDriverHandle;
42 extern NDIS_HANDLE gOvsExtDriverObject;
43
44 /*
45  * Reference count used to prevent premature deallocation of the global switch
46  * context structure, gOvsSwitchContext.
47  */
48 volatile LONG      gOvsSwitchContextRefCount = 1;
49
50 static NDIS_STATUS OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
51                                    POVS_SWITCH_CONTEXT *switchContextOut);
52 static NDIS_STATUS OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext);
53 static VOID OvsDeleteSwitch(POVS_SWITCH_CONTEXT switchContext);
54 static VOID OvsUninitSwitchContext(POVS_SWITCH_CONTEXT switchContext);
55 static NDIS_STATUS OvsActivateSwitch(POVS_SWITCH_CONTEXT switchContext);
56
57
58 /*
59  * --------------------------------------------------------------------------
60  *  Implements filter driver's FilterAttach function.
61  *
62  *  This function allocates the switch context, and initializes its necessary
63  *  members.
64  * --------------------------------------------------------------------------
65  */
66 NDIS_STATUS
67 OvsExtAttach(NDIS_HANDLE ndisFilterHandle,
68              NDIS_HANDLE filterDriverContext,
69              PNDIS_FILTER_ATTACH_PARAMETERS attachParameters)
70 {
71     NDIS_STATUS status = NDIS_STATUS_FAILURE;
72     NDIS_FILTER_ATTRIBUTES ovsExtAttributes;
73     POVS_SWITCH_CONTEXT switchContext = NULL;
74
75     UNREFERENCED_PARAMETER(filterDriverContext);
76
77     OVS_LOG_TRACE("Enter: ndisFilterHandle %p", ndisFilterHandle);
78
79     ASSERT(filterDriverContext == (NDIS_HANDLE)gOvsExtDriverObject);
80     if (attachParameters->MiniportMediaType != NdisMedium802_3) {
81         status = NDIS_STATUS_INVALID_PARAMETER;
82         goto cleanup;
83     }
84
85     if (gOvsExtDriverHandle == NULL) {
86         OVS_LOG_TRACE("Exit: OVSEXT driver is not loaded.");
87         ASSERT(FALSE);
88         goto cleanup;
89     }
90
91     if (gOvsSwitchContext) {
92         OVS_LOG_TRACE("Exit: Failed to create OVS Switch, only one datapath is"
93                       "supported, %p.", gOvsSwitchContext);
94         goto cleanup;
95     }
96
97     if (InterlockedCompareExchange(&gOvsInAttach, 1, 0)) {
98         /* Just fail the request. */
99         OVS_LOG_TRACE("Exit: Failed to create OVS Switch, since another attach"
100                       "instance is in attach process.");
101         goto cleanup;
102     }
103
104     status = OvsInitIpHelper(ndisFilterHandle);
105     if (status != STATUS_SUCCESS) {
106         OVS_LOG_ERROR("Exit: Failed to initialize IP helper.");
107         goto cleanup;
108     }
109
110     status = OvsCreateSwitch(ndisFilterHandle, &switchContext);
111     if (status != NDIS_STATUS_SUCCESS) {
112         OvsCleanupIpHelper();
113         goto cleanup;
114     }
115     ASSERT(switchContext);
116
117     /*
118      * Register the switch context with NDIS so NDIS can pass it back to the
119      * FilterXXX callback functions as the 'FilterModuleContext' parameter.
120      */
121     RtlZeroMemory(&ovsExtAttributes, sizeof(NDIS_FILTER_ATTRIBUTES));
122     ovsExtAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
123     ovsExtAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES);
124     ovsExtAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
125     ovsExtAttributes.Flags = 0;
126
127     NDIS_DECLARE_FILTER_MODULE_CONTEXT(OVS_SWITCH_CONTEXT);
128     status = NdisFSetAttributes(ndisFilterHandle, switchContext, &ovsExtAttributes);
129     if (status != NDIS_STATUS_SUCCESS) {
130         OVS_LOG_ERROR("Failed to set attributes.");
131         OvsCleanupIpHelper();
132         goto cleanup;
133     }
134
135     /* Setup the state machine. */
136     switchContext->controlFlowState = OvsSwitchAttached;
137     switchContext->dataFlowState = OvsSwitchPaused;
138
139     gOvsSwitchContext = switchContext;
140     KeMemoryBarrier();
141
142 cleanup:
143     gOvsInAttach = FALSE;
144     if (status != NDIS_STATUS_SUCCESS) {
145         if (switchContext != NULL) {
146             OvsDeleteSwitch(switchContext);
147         }
148     }
149     OVS_LOG_TRACE("Exit: status %x", status);
150
151     return status;
152 }
153
154
155 /*
156  * --------------------------------------------------------------------------
157  *  This function allocated the switch context, and initializes its necessary
158  *  members.
159  * --------------------------------------------------------------------------
160  */
161 NDIS_STATUS
162 OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
163                 POVS_SWITCH_CONTEXT *switchContextOut)
164 {
165     NDIS_STATUS status;
166     POVS_SWITCH_CONTEXT switchContext;
167     NDIS_SWITCH_CONTEXT hostSwitchContext;
168     NDIS_SWITCH_OPTIONAL_HANDLERS hostSwitchHandler;
169
170     OVS_LOG_TRACE("Enter: Create switch object");
171
172     switchContext = (POVS_SWITCH_CONTEXT) OvsAllocateMemoryWithTag(
173         sizeof(OVS_SWITCH_CONTEXT), OVS_SWITCH_POOL_TAG);
174     if (switchContext == NULL) {
175         status = NDIS_STATUS_RESOURCES;
176         goto create_switch_done;
177     }
178     RtlZeroMemory(switchContext, sizeof(OVS_SWITCH_CONTEXT));
179
180     /* Initialize the switch. */
181     hostSwitchHandler.Header.Type = NDIS_OBJECT_TYPE_SWITCH_OPTIONAL_HANDLERS;
182     hostSwitchHandler.Header.Size = NDIS_SIZEOF_SWITCH_OPTIONAL_HANDLERS_REVISION_1;
183     hostSwitchHandler.Header.Revision = NDIS_SWITCH_OPTIONAL_HANDLERS_REVISION_1;
184
185     status = NdisFGetOptionalSwitchHandlers(ndisFilterHandle,
186                                             &hostSwitchContext,
187                                             &hostSwitchHandler);
188     if (status != NDIS_STATUS_SUCCESS) {
189         OVS_LOG_ERROR("OvsExtAttach: Extension is running in "
190                       "non-switch environment.");
191         OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG);
192         goto create_switch_done;
193     }
194
195     switchContext->NdisFilterHandle = ndisFilterHandle;
196     switchContext->NdisSwitchContext = hostSwitchContext;
197     RtlCopyMemory(&switchContext->NdisSwitchHandlers, &hostSwitchHandler,
198                   sizeof(NDIS_SWITCH_OPTIONAL_HANDLERS));
199
200     status = OvsInitSwitchContext(switchContext);
201     if (status != NDIS_STATUS_SUCCESS) {
202         OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG);
203         goto create_switch_done;
204     }
205
206     status = OvsTunnelFilterInitialize(gOvsExtDriverObject);
207     if (status != NDIS_STATUS_SUCCESS) {
208         OvsUninitSwitchContext(switchContext);
209         goto create_switch_done;
210     }
211     *switchContextOut = switchContext;
212
213 create_switch_done:
214     OVS_LOG_TRACE("Exit: switchContext: %p status: %#lx",
215                   switchContext, status);
216     return status;
217 }
218
219
220 /*
221  * --------------------------------------------------------------------------
222  *  Implements filter driver's FilterDetach function.
223  * --------------------------------------------------------------------------
224  */
225 _Use_decl_annotations_
226 VOID
227 OvsExtDetach(NDIS_HANDLE filterModuleContext)
228 {
229     POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)filterModuleContext;
230
231     OVS_LOG_TRACE("Enter: filterModuleContext %p", filterModuleContext);
232
233     ASSERT(switchContext->dataFlowState == OvsSwitchPaused);
234     switchContext->controlFlowState = OvsSwitchDetached;
235     KeMemoryBarrier();
236     while(switchContext->pendingOidCount > 0) {
237         NdisMSleep(1000);
238     }
239     OvsDeleteSwitch(switchContext);
240     OvsCleanupIpHelper();
241     gOvsSwitchContext = NULL;
242     /* This completes the cleanup, and a new attach can be handled now. */
243
244     OVS_LOG_TRACE("Exit: OvsDetach Successfully");
245 }
246
247
248 /*
249  * --------------------------------------------------------------------------
250  *  This function deletes the switch by freeing all memory previously allocated.
251  *  XXX need synchronization with other path.
252  * --------------------------------------------------------------------------
253  */
254 VOID
255 OvsDeleteSwitch(POVS_SWITCH_CONTEXT switchContext)
256 {
257     UINT32 dpNo = (UINT32) -1;
258
259     OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
260
261     if (switchContext)
262     {
263         dpNo = switchContext->dpNo;
264         OvsTunnelFilterUninitialize(gOvsExtDriverObject);
265         OvsClearAllSwitchVports(switchContext);
266         OvsUninitSwitchContext(switchContext);
267     }
268     OVS_LOG_TRACE("Exit: deleted switch %p  dpNo: %d", switchContext, dpNo);
269 }
270
271
272 /*
273  * --------------------------------------------------------------------------
274  *  Implements filter driver's FilterRestart function.
275  * --------------------------------------------------------------------------
276  */
277 _Use_decl_annotations_
278 NDIS_STATUS
279 OvsExtRestart(NDIS_HANDLE filterModuleContext,
280               PNDIS_FILTER_RESTART_PARAMETERS filterRestartParameters)
281 {
282     POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)filterModuleContext;
283     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
284     BOOLEAN switchActive;
285
286     UNREFERENCED_PARAMETER(filterRestartParameters);
287
288     OVS_LOG_TRACE("Enter: filterModuleContext %p",
289                   filterModuleContext);
290
291     /* Activate the switch if this is the first restart. */
292     if (!switchContext->isActivated && !switchContext->isActivateFailed) {
293         status = OvsQuerySwitchActivationComplete(switchContext,
294                                                   &switchActive);
295         if (status != NDIS_STATUS_SUCCESS) {
296             switchContext->isActivateFailed = TRUE;
297             status = NDIS_STATUS_RESOURCES;
298             goto cleanup;
299         }
300
301         if (switchActive) {
302             status = OvsActivateSwitch(switchContext);
303
304             if (status != NDIS_STATUS_SUCCESS) {
305                 OVS_LOG_WARN("Failed to activate switch, dpNo:%d",
306                              switchContext->dpNo);
307                 status = NDIS_STATUS_RESOURCES;
308                 goto cleanup;
309             }
310         }
311     }
312
313     ASSERT(switchContext->dataFlowState == OvsSwitchPaused);
314     switchContext->dataFlowState = OvsSwitchRunning;
315
316 cleanup:
317     OVS_LOG_TRACE("Exit: Restart switch:%p, dpNo: %d, status: %#x",
318                   switchContext, switchContext->dpNo, status);
319     return status;
320 }
321
322
323 /*
324  * --------------------------------------------------------------------------
325  *  Implements filter driver's FilterPause function
326  * --------------------------------------------------------------------------
327  */
328 NDIS_STATUS
329 OvsExtPause(NDIS_HANDLE filterModuleContext,
330             PNDIS_FILTER_PAUSE_PARAMETERS pauseParameters)
331 {
332     POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)filterModuleContext;
333
334     UNREFERENCED_PARAMETER(pauseParameters);
335     OVS_LOG_TRACE("Enter: filterModuleContext %p",
336                   filterModuleContext);
337
338     ASSERT(switchContext->dataFlowState == OvsSwitchRunning);
339     switchContext->dataFlowState = OvsSwitchPaused;
340     KeMemoryBarrier();
341     while(switchContext->pendingOidCount > 0) {
342         NdisMSleep(1000);
343     }
344
345     OVS_LOG_TRACE("Exit: OvsDetach Successfully");
346     return NDIS_STATUS_SUCCESS;
347 }
348
349 static NDIS_STATUS
350 OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
351 {
352     int i;
353     NTSTATUS status;
354
355     OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
356
357     switchContext->dispatchLock =
358         NdisAllocateRWLock(switchContext->NdisFilterHandle);
359
360     switchContext->portNoHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
361         sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
362     switchContext->ovsPortNameHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
363         sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
364     switchContext->portIdHashArray= (PLIST_ENTRY)OvsAllocateMemoryWithTag(
365         sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
366     switchContext->pidHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
367         sizeof(LIST_ENTRY) * OVS_MAX_PID_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
368     status = OvsAllocateFlowTable(&switchContext->datapath, switchContext);
369
370     if (status == NDIS_STATUS_SUCCESS) {
371         status = OvsInitBufferPool(switchContext);
372     }
373     if (status != NDIS_STATUS_SUCCESS ||
374         switchContext->dispatchLock == NULL ||
375         switchContext->portNoHashArray == NULL ||
376         switchContext->ovsPortNameHashArray == NULL ||
377         switchContext->portIdHashArray== NULL ||
378         switchContext->pidHashArray == NULL) {
379         if (switchContext->dispatchLock) {
380             NdisFreeRWLock(switchContext->dispatchLock);
381         }
382         if (switchContext->portNoHashArray) {
383             OvsFreeMemoryWithTag(switchContext->portNoHashArray,
384                                  OVS_SWITCH_POOL_TAG);
385         }
386         if (switchContext->ovsPortNameHashArray) {
387             OvsFreeMemoryWithTag(switchContext->ovsPortNameHashArray,
388                                  OVS_SWITCH_POOL_TAG);
389         }
390         if (switchContext->portIdHashArray) {
391             OvsFreeMemoryWithTag(switchContext->portIdHashArray,
392                                  OVS_SWITCH_POOL_TAG);
393         }
394         if (switchContext->pidHashArray) {
395             OvsFreeMemoryWithTag(switchContext->pidHashArray,
396                                  OVS_SWITCH_POOL_TAG);
397         }
398
399         OvsDeleteFlowTable(&switchContext->datapath);
400         OvsCleanupBufferPool(switchContext);
401
402         OVS_LOG_TRACE("Exit: Failed to init switchContext");
403         return NDIS_STATUS_RESOURCES;
404     }
405
406     for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
407         InitializeListHead(&switchContext->ovsPortNameHashArray[i]);
408     }
409     for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
410         InitializeListHead(&switchContext->portIdHashArray[i]);
411     }
412     for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
413         InitializeListHead(&switchContext->portNoHashArray[i]);
414     }
415
416     for (i = 0; i < OVS_MAX_PID_ARRAY_SIZE; i++) {
417         InitializeListHead(&switchContext->pidHashArray[i]);
418     }
419
420     NdisAllocateSpinLock(&(switchContext->pidHashLock));
421     switchContext->isActivated = FALSE;
422     switchContext->isActivateFailed = FALSE;
423     switchContext->dpNo = OVS_DP_NUMBER;
424     ovsTimeIncrementPerTick = KeQueryTimeIncrement() / 10000;
425
426     OVS_LOG_TRACE("Exit: Succesfully initialized switchContext: %p",
427                   switchContext);
428     return NDIS_STATUS_SUCCESS;
429 }
430
431 static VOID
432 OvsUninitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
433 {
434     OvsReleaseSwitchContext(switchContext);
435 }
436
437 /*
438  * --------------------------------------------------------------------------
439  *  Frees up the contents of and also the switch context.
440  * --------------------------------------------------------------------------
441  */
442 static VOID
443 OvsDeleteSwitchContext(POVS_SWITCH_CONTEXT switchContext)
444 {
445     OVS_LOG_TRACE("Enter: Delete switchContext:%p", switchContext);
446
447     /* We need to do cleanup for tunnel port here. */
448     ASSERT(switchContext->numHvVports == 0);
449     ASSERT(switchContext->numNonHvVports == 0);
450
451     NdisFreeRWLock(switchContext->dispatchLock);
452     switchContext->dispatchLock = NULL;
453     NdisFreeSpinLock(&(switchContext->pidHashLock));
454     OvsFreeMemoryWithTag(switchContext->ovsPortNameHashArray,
455                          OVS_SWITCH_POOL_TAG);
456     switchContext->ovsPortNameHashArray = NULL;
457     OvsFreeMemoryWithTag(switchContext->portIdHashArray,
458                          OVS_SWITCH_POOL_TAG);
459     switchContext->portIdHashArray = NULL;
460     OvsFreeMemoryWithTag(switchContext->portNoHashArray,
461                          OVS_SWITCH_POOL_TAG);
462     switchContext->portNoHashArray = NULL;
463     OvsFreeMemoryWithTag(switchContext->pidHashArray,
464                          OVS_SWITCH_POOL_TAG);
465     switchContext->pidHashArray = NULL;
466     OvsDeleteFlowTable(&switchContext->datapath);
467     OvsCleanupBufferPool(switchContext);
468
469     OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG);
470     OVS_LOG_TRACE("Exit: Delete switchContext: %p", switchContext);
471 }
472
473 VOID
474 OvsReleaseSwitchContext(POVS_SWITCH_CONTEXT switchContext)
475 {
476     LONG ref = 0;
477     LONG newRef = 0;
478     LONG icxRef = 0;
479
480     do {
481         ref = gOvsSwitchContextRefCount;
482         newRef = (0 == ref) ? 0 : ref - 1;
483         icxRef = InterlockedCompareExchange(&gOvsSwitchContextRefCount,
484                                             newRef,
485                                             ref);
486     } while (icxRef != ref);
487
488     if (ref == 1) {
489         OvsDeleteSwitchContext(switchContext);
490     }
491 }
492
493 BOOLEAN
494 OvsAcquireSwitchContext(VOID)
495 {
496     LONG ref = 0;
497     LONG newRef = 0;
498     LONG icxRef = 0;
499     BOOLEAN ret = FALSE;
500
501     do {
502         ref = gOvsSwitchContextRefCount;
503         newRef = (0 == ref) ? 0 : ref + 1;
504         icxRef = InterlockedCompareExchange(&gOvsSwitchContextRefCount,
505                                             newRef,
506                                             ref);
507     } while (icxRef != ref);
508
509     if (ref != 0) {
510         ret = TRUE;
511     }
512
513     return ret;
514 }
515
516 /*
517  * --------------------------------------------------------------------------
518  *  This function activates the switch by initializing it with all the runtime
519  *  state. First it queries all of the MAC addresses set as custom switch policy
520  *  to allow sends from, and adds tme to the property list. Then it queries the
521  *  NIC list and verifies it can support all of the NICs currently connected to
522  *  the switch, and adds the NICs to the NIC list.
523  * --------------------------------------------------------------------------
524  */
525 static NDIS_STATUS
526 OvsActivateSwitch(POVS_SWITCH_CONTEXT switchContext)
527 {
528     NDIS_STATUS status;
529
530     ASSERT(!switchContext->isActivated);
531
532     OVS_LOG_TRACE("Enter: activate switch %p, dpNo: %ld",
533                   switchContext, switchContext->dpNo);
534
535     status = OvsAddConfiguredSwitchPorts(switchContext);
536
537     if (status != NDIS_STATUS_SUCCESS) {
538         OVS_LOG_WARN("Failed to add configured switch ports");
539         goto cleanup;
540
541     }
542     status = OvsInitConfiguredSwitchNics(switchContext);
543
544     if (status != NDIS_STATUS_SUCCESS) {
545         OVS_LOG_WARN("Failed to add configured vports");
546         OvsClearAllSwitchVports(switchContext);
547         goto cleanup;
548     }
549     switchContext->isActivated = TRUE;
550     OvsPostEvent(OVS_DEFAULT_PORT_NO, OVS_DEFAULT_EVENT_STATUS);
551
552 cleanup:
553     OVS_LOG_TRACE("Exit: activate switch:%p, isActivated: %s, status = %lx",
554                   switchContext,
555                   (switchContext->isActivated ? "TRUE" : "FALSE"), status);
556     return status;
557 }
558
559
560 /*
561  * --------------------------------------------------------------------------
562  * Implements filter driver's FilterNetPnPEvent function.
563  * --------------------------------------------------------------------------
564  */
565 NDIS_STATUS
566 OvsExtNetPnPEvent(NDIS_HANDLE filterModuleContext,
567                   PNET_PNP_EVENT_NOTIFICATION netPnPEvent)
568 {
569     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
570     POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)filterModuleContext;
571     BOOLEAN switchActive;
572
573     OVS_LOG_TRACE("Enter: filterModuleContext: %p, NetEvent: %d",
574                   filterModuleContext, (netPnPEvent->NetPnPEvent).NetEvent);
575     /*
576      * The only interesting event is the NetEventSwitchActivate. It provides
577      * an asynchronous notification of the switch completing activation.
578      */
579     if (netPnPEvent->NetPnPEvent.NetEvent == NetEventSwitchActivate) {
580         status = OvsQuerySwitchActivationComplete(switchContext, &switchActive);
581         if (status != NDIS_STATUS_SUCCESS) {
582             switchContext->isActivateFailed = TRUE;
583         } else {
584             ASSERT(switchContext->isActivated == FALSE);
585             if (switchContext->isActivated == FALSE && switchActive == TRUE) {
586                 status = OvsActivateSwitch(switchContext);
587                 OVS_LOG_TRACE("OvsExtNetPnPEvent: activated switch: %p "
588                               "status: %s", switchContext,
589                               status ? "TRUE" : "FALSE");
590             }
591         }
592     }
593
594     if (status == NDIS_STATUS_SUCCESS) {
595         status = NdisFNetPnPEvent(switchContext->NdisFilterHandle,
596                                   netPnPEvent);
597     }
598     OVS_LOG_TRACE("Exit: OvsExtNetPnPEvent");
599
600     return status;
601 }