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