]> git.proxmox.com Git - mirror_ovs.git/blame - datapath-windows/ovsext/OvsSwitch.c
datapath-windows: Add Datapath.[ch] and OVS_USE_NL_INTERFACE CPP
[mirror_ovs.git] / datapath-windows / ovsext / OvsSwitch.c
CommitLineData
c803536e
SS
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
c803536e
SS
24#include "OvsSwitch.h"
25#include "OvsVport.h"
26#include "OvsEvent.h"
27#include "OvsFlow.h"
28#include "OvsIpHelper.h"
29#include "OvsTunnelIntf.h"
30#include "OvsOid.h"
31
32#ifdef OVS_DBG_MOD
33#undef OVS_DBG_MOD
34#endif
35#define OVS_DBG_MOD OVS_DBG_SWITCH
36#include "OvsDebug.h"
37
38POVS_SWITCH_CONTEXT gOvsSwitchContext;
39BOOLEAN gOvsInAttach;
4f3988e0
NR
40UINT64 ovsTimeIncrementPerTick;
41
c803536e
SS
42extern PNDIS_SPIN_LOCK gOvsCtrlLock;
43extern NDIS_HANDLE gOvsExtDriverHandle;
44extern NDIS_HANDLE gOvsExtDriverObject;
45
46static NDIS_STATUS OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
47 POVS_SWITCH_CONTEXT *switchContextOut);
48static NDIS_STATUS OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext);
49static VOID OvsDeleteSwitch(POVS_SWITCH_CONTEXT switchContext);
50static VOID OvsCleanupSwitchContext(POVS_SWITCH_CONTEXT switchContext);
51static NDIS_STATUS OvsActivateSwitch(POVS_SWITCH_CONTEXT switchContext);
52
53
54/*
55 * --------------------------------------------------------------------------
56 * Implements filter driver's FilterAttach function.
57 *
58 * This function allocates the switch context, and initializes its necessary
59 * members.
60 * --------------------------------------------------------------------------
61 */
62NDIS_STATUS
63OvsExtAttach(NDIS_HANDLE ndisFilterHandle,
64 NDIS_HANDLE filterDriverContext,
65 PNDIS_FILTER_ATTACH_PARAMETERS attachParameters)
66{
67 NDIS_STATUS status = NDIS_STATUS_FAILURE;
68 NDIS_FILTER_ATTRIBUTES ovsExtAttributes;
69 POVS_SWITCH_CONTEXT switchContext = NULL;
70
71 UNREFERENCED_PARAMETER(filterDriverContext);
72
73 OVS_LOG_TRACE("Enter: ndisFilterHandle %p", ndisFilterHandle);
74
75 ASSERT(filterDriverContext == (NDIS_HANDLE)gOvsExtDriverObject);
76 if (attachParameters->MiniportMediaType != NdisMedium802_3) {
77 status = NDIS_STATUS_INVALID_PARAMETER;
78 goto cleanup;
79 }
80
81 if (gOvsExtDriverHandle == NULL) {
82 OVS_LOG_TRACE("Exit: OVSEXT driver is not loaded.");
83 ASSERT(FALSE);
84 goto cleanup;
85 }
86
87 NdisAcquireSpinLock(gOvsCtrlLock);
88 if (gOvsSwitchContext) {
89 NdisReleaseSpinLock(gOvsCtrlLock);
90 OVS_LOG_TRACE("Exit: Failed to create OVS Switch, only one datapath is"
91 "supported, %p.", gOvsSwitchContext);
92 goto cleanup;
93 }
94 if (gOvsInAttach) {
95 NdisReleaseSpinLock(gOvsCtrlLock);
96 /* Just fail the request. */
97 OVS_LOG_TRACE("Exit: Failed to create OVS Switch, since another attach"
98 "instance is in attach process.");
99 goto cleanup;
100 }
101 gOvsInAttach = TRUE;
102 NdisReleaseSpinLock(gOvsCtrlLock);
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
142cleanup:
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 */
161NDIS_STATUS
162OvsCreateSwitch(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 =
173 (POVS_SWITCH_CONTEXT) OvsAllocateMemory(sizeof(OVS_SWITCH_CONTEXT));
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 OvsFreeMemory(switchContext);
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 OvsFreeMemory(switchContext);
203 goto create_switch_done;
204 }
205
206 status = OvsTunnelFilterInitialize(gOvsExtDriverObject);
207 if (status != NDIS_STATUS_SUCCESS) {
208 OvsFreeMemory(switchContext);
209 goto create_switch_done;
210 }
211 *switchContextOut = switchContext;
212
213create_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_
226VOID
227OvsExtDetach(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 */
254VOID
255OvsDeleteSwitch(POVS_SWITCH_CONTEXT switchContext)
256{
257 UINT32 dpNo = switchContext->dpNo;
258
259 OVS_LOG_TRACE("Enter: switchContext:%p", switchContext);
260
261 OvsTunnelFilterUninitialize(gOvsExtDriverObject);
262 OvsClearAllSwitchVports(switchContext);
263 OvsCleanupSwitchContext(switchContext);
264 OvsFreeMemory(switchContext);
265 OVS_LOG_TRACE("Exit: deleted switch %p dpNo: %d", switchContext, dpNo);
266}
267
268
269/*
270 * --------------------------------------------------------------------------
271 * Implements filter driver's FilterRestart function.
272 * --------------------------------------------------------------------------
273 */
274_Use_decl_annotations_
275NDIS_STATUS
276OvsExtRestart(NDIS_HANDLE filterModuleContext,
277 PNDIS_FILTER_RESTART_PARAMETERS filterRestartParameters)
278{
279 POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)filterModuleContext;
280 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
281 BOOLEAN switchActive;
282
283 UNREFERENCED_PARAMETER(filterRestartParameters);
284
285 OVS_LOG_TRACE("Enter: filterModuleContext %p",
286 filterModuleContext);
287
288 /* Activate the switch if this is the first restart. */
289 if (!switchContext->isActivated && !switchContext->isActivateFailed) {
290 status = OvsQuerySwitchActivationComplete(switchContext,
291 &switchActive);
292 if (status != NDIS_STATUS_SUCCESS) {
293 switchContext->isActivateFailed = TRUE;
294 status = NDIS_STATUS_RESOURCES;
295 goto cleanup;
296 }
297
298 if (switchActive) {
299 status = OvsActivateSwitch(switchContext);
300
301 if (status != NDIS_STATUS_SUCCESS) {
302 OVS_LOG_WARN("Failed to activate switch, dpNo:%d",
303 switchContext->dpNo);
304 status = NDIS_STATUS_RESOURCES;
305 goto cleanup;
306 }
307 }
308 }
309
310 ASSERT(switchContext->dataFlowState == OvsSwitchPaused);
311 switchContext->dataFlowState = OvsSwitchRunning;
312
313cleanup:
314 OVS_LOG_TRACE("Exit: Restart switch:%p, dpNo: %d, status: %#x",
315 switchContext, switchContext->dpNo, status);
316 return status;
317}
318
319
320/*
321 * --------------------------------------------------------------------------
322 * Implements filter driver's FilterPause function
323 * --------------------------------------------------------------------------
324 */
325NDIS_STATUS
326OvsExtPause(NDIS_HANDLE filterModuleContext,
327 PNDIS_FILTER_PAUSE_PARAMETERS pauseParameters)
328{
329 POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)filterModuleContext;
330
331 UNREFERENCED_PARAMETER(pauseParameters);
332 OVS_LOG_TRACE("Enter: filterModuleContext %p",
333 filterModuleContext);
334
335 ASSERT(switchContext->dataFlowState == OvsSwitchRunning);
336 switchContext->dataFlowState = OvsSwitchPaused;
337 KeMemoryBarrier();
338 while(switchContext->pendingOidCount > 0) {
339 NdisMSleep(1000);
340 }
341
342 OVS_LOG_TRACE("Exit: OvsDetach Successfully");
343 return NDIS_STATUS_SUCCESS;
344}
345
346static NDIS_STATUS
347OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
348{
349 int i;
350 NTSTATUS status;
351
352 OVS_LOG_TRACE("Enter: switchContext: %p", switchContext);
353
354 switchContext->dispatchLock =
355 NdisAllocateRWLock(switchContext->NdisFilterHandle);
356
357 switchContext->vportArray =
358 (PVOID *)OvsAllocateMemory(sizeof (PVOID) * OVS_MAX_VPORT_ARRAY_SIZE);
359 switchContext->nameHashArray = (PLIST_ENTRY)
360 OvsAllocateMemory(sizeof (LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE);
361 switchContext->portHashArray = (PLIST_ENTRY)
362 OvsAllocateMemory(sizeof (LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE);
363 status = OvsAllocateFlowTable(&switchContext->datapath, switchContext);
364
365 if (status == NDIS_STATUS_SUCCESS) {
366 status = OvsInitBufferPool(switchContext);
367 }
368 if (status != NDIS_STATUS_SUCCESS ||
369 switchContext->dispatchLock == NULL ||
370 switchContext->vportArray == NULL ||
371 switchContext->nameHashArray == NULL ||
372 switchContext->portHashArray == NULL) {
373 if (switchContext->dispatchLock) {
374 NdisFreeRWLock(switchContext->dispatchLock);
375 }
376 if (switchContext->vportArray) {
377 OvsFreeMemory(switchContext->vportArray);
378 }
379 if (switchContext->nameHashArray) {
380 OvsFreeMemory(switchContext->nameHashArray);
381 }
382 if (switchContext->portHashArray) {
383 OvsFreeMemory(switchContext->portHashArray);
384 }
385 OvsDeleteFlowTable(&switchContext->datapath);
386 OvsCleanupBufferPool(switchContext);
387
388 OVS_LOG_TRACE("Exit: Failed to init switchContext");
389 return NDIS_STATUS_RESOURCES;
390 }
391
392 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
393 InitializeListHead(&switchContext->nameHashArray[i]);
394 }
395 for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
396 InitializeListHead(&switchContext->portHashArray[i]);
397 }
398 RtlZeroMemory(switchContext->vportArray,
399 sizeof (PVOID) * OVS_MAX_VPORT_ARRAY_SIZE);
400
401 switchContext->isActivated = FALSE;
402 switchContext->isActivateFailed = FALSE;
403 switchContext->dpNo = OVS_DP_NUMBER;
404 switchContext->lastPortIndex = OVS_MAX_VPORT_ARRAY_SIZE -1;
405 ovsTimeIncrementPerTick = KeQueryTimeIncrement() / 10000;
406 OVS_LOG_TRACE("Exit: Succesfully initialized switchContext: %p",
407 switchContext);
408 return NDIS_STATUS_SUCCESS;
409}
410
411static VOID
412OvsCleanupSwitchContext(POVS_SWITCH_CONTEXT switchContext)
413{
414 OVS_LOG_TRACE("Enter: Delete switchContext:%p", switchContext);
415
416 /* We need to do cleanup for tunnel port here. */
417 ASSERT(switchContext->numVports == 0);
418
419 NdisFreeRWLock(switchContext->dispatchLock);
420 OvsFreeMemory(switchContext->nameHashArray);
421 OvsFreeMemory(switchContext->portHashArray);
422 OvsFreeMemory(switchContext->vportArray);
423 OvsDeleteFlowTable(&switchContext->datapath);
424 OvsCleanupBufferPool(switchContext);
425 OVS_LOG_TRACE("Exit: Delete switchContext: %p", switchContext);
426}
427
428/*
429 * --------------------------------------------------------------------------
430 * This function activates the switch by initializing it with all the runtime
431 * state. First it queries all of the MAC addresses set as custom switch policy
432 * to allow sends from, and adds tme to the property list. Then it queries the
433 * NIC list and verifies it can support all of the NICs currently connected to
434 * the switch, and adds the NICs to the NIC list.
435 * --------------------------------------------------------------------------
436 */
437static NDIS_STATUS
438OvsActivateSwitch(POVS_SWITCH_CONTEXT switchContext)
439{
440 NDIS_STATUS status;
441
442 ASSERT(!switchContext->isActivated);
443
444 OVS_LOG_TRACE("Enter: activate switch %p, dpNo: %ld",
445 switchContext, switchContext->dpNo);
446
447 status = OvsAddConfiguredSwitchPorts(switchContext);
448
449 if (status != NDIS_STATUS_SUCCESS) {
450 OVS_LOG_WARN("Failed to add configured switch ports");
451 goto cleanup;
452
453 }
454 status = OvsInitConfiguredSwitchNics(switchContext);
455
456 if (status != NDIS_STATUS_SUCCESS) {
457 OVS_LOG_WARN("Failed to add configured vports");
458 OvsClearAllSwitchVports(switchContext);
459 goto cleanup;
460 }
461 switchContext->isActivated = TRUE;
462 OvsPostEvent(OVS_DEFAULT_PORT_NO, OVS_DEFAULT_EVENT_STATUS);
463
464cleanup:
465 OVS_LOG_TRACE("Exit: activate switch:%p, isActivated: %s, status = %lx",
466 switchContext,
467 (switchContext->isActivated ? "TRUE" : "FALSE"), status);
468 return status;
469}
470
471PVOID
472OvsGetVportFromIndex(UINT16 index)
473{
474 if (index < OVS_MAX_VPORT_ARRAY_SIZE &&
475 !OVS_IS_VPORT_ENTRY_NULL(gOvsSwitchContext, index)) {
476 return gOvsSwitchContext->vportArray[index];
477 }
478 return NULL;
479}
480
481PVOID
482OvsGetExternalVport()
483{
484 return gOvsSwitchContext->externalVport;
485}
486
487
488/*
489 * --------------------------------------------------------------------------
490 * Implements filter driver's FilterNetPnPEvent function.
491 * --------------------------------------------------------------------------
492 */
493NDIS_STATUS
494OvsExtNetPnPEvent(NDIS_HANDLE filterModuleContext,
495 PNET_PNP_EVENT_NOTIFICATION netPnPEvent)
496{
497 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
498 POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)filterModuleContext;
499 BOOLEAN switchActive;
500
501 OVS_LOG_TRACE("Enter: filterModuleContext: %p, NetEvent: %d",
502 filterModuleContext, (netPnPEvent->NetPnPEvent).NetEvent);
503 /*
504 * The only interesting event is the NetEventSwitchActivate. It provides
505 * an asynchronous notification of the switch completing activation.
506 */
507 if (netPnPEvent->NetPnPEvent.NetEvent == NetEventSwitchActivate) {
508 status = OvsQuerySwitchActivationComplete(switchContext, &switchActive);
509 if (status != NDIS_STATUS_SUCCESS) {
510 switchContext->isActivateFailed = TRUE;
511 } else {
512 ASSERT(switchContext->isActivated == FALSE);
513 ASSERT(switchActive == TRUE);
514 if (switchContext->isActivated == FALSE && switchActive == TRUE) {
515 status = OvsActivateSwitch(switchContext);
516 OVS_LOG_TRACE("OvsExtNetPnPEvent: activated switch: %p "
517 "status: %s", switchContext,
518 status ? "TRUE" : "FALSE");
519 }
520 }
521 }
522
523 if (status == NDIS_STATUS_SUCCESS) {
524 status = NdisFNetPnPEvent(switchContext->NdisFilterHandle,
525 netPnPEvent);
526 }
527 OVS_LOG_TRACE("Exit: OvsExtNetPnPEvent");
528
529 return status;
530}