ovn-controller: Drop unknown datapath log message.
[cascardo/ovs.git] / datapath-windows / ovsext / TunnelFilter.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
19 #pragma warning(push)
20 #pragma warning(disable:4201)       // unnamed struct/union
21 #ifdef OVS_DBG_MOD
22 #undef OVS_DBG_MOD
23 #endif
24 #define OVS_DBG_MOD OVS_DBG_TUNFLT
25 #include "Debug.h"
26
27
28 #include <fwpsk.h>
29
30 #pragma warning(pop)
31
32 #include <fwpmk.h>
33 #include <ws2ipdef.h>
34 #include <in6addr.h>
35 #include <ip2string.h>
36
37 #include "Tunnel.h"
38 #include "Switch.h"
39 #include "Vport.h"
40 #include "Event.h"
41 #include "User.h"
42 #include "Vxlan.h"
43
44
45 #define INITGUID
46 #include <guiddef.h>
47
48 /* Infinite timeout */
49 #define INFINITE                        0xFFFFFFFF
50
51 /*
52  * The provider name should always match the provider string from the install
53  * file.
54  */
55 #define OVS_TUNNEL_PROVIDER_NAME        L"Open vSwitch"
56
57 /*
58  * The provider description should always contain the OVS service description
59  * string from the install file.
60  */
61 #define OVS_TUNNEL_PROVIDER_DESC        L"Open vSwitch Extension tunnel provider"
62
63 /* The session name isn't required but it's useful for diagnostics. */
64 #define OVS_TUNNEL_SESSION_NAME         L"OVS tunnel session"
65
66 /* Configurable parameters (addresses and ports are in host order) */
67 UINT16   configNewDestPort = VXLAN_UDP_PORT;
68
69 /*
70  * Callout and sublayer GUIDs
71  */
72 // b16b0a6e-2b2a-41a3-8b39-bd3ffc855ff8
73 DEFINE_GUID(
74     OVS_TUNNEL_CALLOUT_V4,
75     0xb16b0a6e,
76     0x2b2a,
77     0x41a3,
78     0x8b, 0x39, 0xbd, 0x3f, 0xfc, 0x85, 0x5f, 0xf8
79     );
80
81 /* 0104fd7e-c825-414e-94c9-f0d525bbc169 */
82 DEFINE_GUID(
83     OVS_TUNNEL_SUBLAYER,
84     0x0104fd7e,
85     0xc825,
86     0x414e,
87     0x94, 0xc9, 0xf0, 0xd5, 0x25, 0xbb, 0xc1, 0x69
88     );
89
90 /* 6fc957d7-14e7-47c7-812b-4668be994ba1 */
91 DEFINE_GUID(
92     OVS_TUNNEL_PROVIDER_KEY,
93     0x6fc957d7,
94     0x14e7,
95     0x47c7,
96     0x81, 0x2b, 0x46, 0x68, 0xbe, 0x99, 0x4b, 0xa1
97     );
98
99 /* bfd4814c-9650-4de3-a536-1eedb9e9ba6a */
100 DEFINE_GUID(
101     OVS_TUNNEL_FILTER_KEY,
102     0xbfd4814c,
103     0x9650,
104     0x4de3,
105     0xa5, 0x36, 0x1e, 0xed, 0xb9, 0xe9, 0xba, 0x6a
106     );
107
108 /*
109  * Callout driver global variables
110  */
111 PDEVICE_OBJECT gDeviceObject;
112
113 HANDLE gEngineHandle = NULL;
114 HANDLE gTunnelProviderBfeHandle = NULL;
115 HANDLE gTunnelInitBfeHandle = NULL;
116 UINT32 gCalloutIdV4;
117
118
119 /* Callout driver implementation */
120
121 NTSTATUS
122 OvsTunnelEngineOpen(HANDLE *handle)
123 {
124     NTSTATUS status = STATUS_SUCCESS;
125     FWPM_SESSION session = { 0 };
126
127     /* The session name isn't required but may be useful for diagnostics. */
128     session.displayData.name = OVS_TUNNEL_SESSION_NAME;
129     /*
130     * Set an infinite wait timeout, so we don't have to handle FWP_E_TIMEOUT
131     * errors while waiting to acquire the transaction lock.
132     */
133     session.txnWaitTimeoutInMSec = INFINITE;
134     session.flags = FWPM_SESSION_FLAG_DYNAMIC;
135
136     /* The authentication service should always be RPC_C_AUTHN_DEFAULT. */
137     status = FwpmEngineOpen(NULL,
138                             RPC_C_AUTHN_DEFAULT,
139                             NULL,
140                             &session,
141                             handle);
142     if (!NT_SUCCESS(status)) {
143         OVS_LOG_ERROR("Fail to open filtering engine session, status: %x.",
144                       status);
145     }
146
147     return status;
148 }
149
150 VOID
151 OvsTunnelEngineClose(HANDLE *handle)
152 {
153     if (*handle) {
154         FwpmEngineClose(*handle);
155         *handle = NULL;
156     }
157 }
158
159 VOID
160 OvsTunnelAddSystemProvider(HANDLE handle)
161 {
162     NTSTATUS status = STATUS_SUCCESS;
163     BOOLEAN inTransaction = FALSE;
164     FWPM_PROVIDER provider = { 0 };
165
166     do {
167         status = FwpmTransactionBegin(handle, 0);
168         if (!NT_SUCCESS(status)) {
169             break;
170         }
171         inTransaction = TRUE;
172
173         memset(&provider, 0, sizeof(provider));
174         provider.providerKey = OVS_TUNNEL_PROVIDER_KEY;
175         provider.displayData.name = OVS_TUNNEL_PROVIDER_NAME;
176         provider.displayData.description = OVS_TUNNEL_PROVIDER_DESC;
177         /*
178          * Since we always want the provider to be present, it's easiest to add
179          * it as persistent object during driver load.
180          */
181         provider.flags = FWPM_PROVIDER_FLAG_PERSISTENT;
182
183         status = FwpmProviderAdd(handle,
184                                  &provider,
185                                  NULL);
186         if (!NT_SUCCESS(status)) {
187             if (STATUS_FWP_ALREADY_EXISTS != status) {
188                 OVS_LOG_ERROR("Failed to add WFP provider, status: %x.",
189                               status);
190                 break;
191             }
192         }
193
194         status = FwpmTransactionCommit(handle);
195         if (!NT_SUCCESS(status)) {
196             break;
197         }
198
199         inTransaction = FALSE;
200     } while (inTransaction);
201
202     if (inTransaction){
203         FwpmTransactionAbort(handle);
204     }
205 }
206
207 VOID
208 OvsTunnelRemoveSystemProvider(HANDLE handle)
209 {
210     NTSTATUS status = STATUS_SUCCESS;
211     BOOLEAN inTransaction = FALSE;
212
213     do {
214         status = FwpmTransactionBegin(handle, 0);
215         if (!NT_SUCCESS(status)) {
216             break;
217         }
218         inTransaction = TRUE;
219
220         status = FwpmProviderDeleteByKey(handle,
221                                          &OVS_TUNNEL_PROVIDER_KEY);
222         if (!NT_SUCCESS(status)) {
223             break;
224         }
225
226         status = FwpmTransactionCommit(handle);
227         if (!NT_SUCCESS(status)) {
228             break;
229         }
230
231         inTransaction = FALSE;
232     } while (inTransaction);
233
234     if (inTransaction){
235         FwpmTransactionAbort(handle);
236     }
237 }
238
239 NTSTATUS
240 OvsTunnelAddFilter(PWSTR filterName,
241                    const PWSTR filterDesc,
242                    USHORT remotePort,
243                    FWP_DIRECTION direction,
244                    UINT64 context,
245                    const GUID *filterKey,
246                    const GUID *layerKey,
247                    const GUID *calloutKey)
248 {
249     NTSTATUS status = STATUS_SUCCESS;
250     FWPM_FILTER filter = {0};
251     FWPM_FILTER_CONDITION filterConditions[3] = {0};
252     UINT conditionIndex;
253
254     UNREFERENCED_PARAMETER(remotePort);
255     UNREFERENCED_PARAMETER(direction);
256
257     filter.filterKey = *filterKey;
258     filter.layerKey = *layerKey;
259     filter.displayData.name = (wchar_t*)filterName;
260     filter.displayData.description = (wchar_t*)filterDesc;
261
262     filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;
263     filter.action.calloutKey = *calloutKey;
264     filter.filterCondition = filterConditions;
265     filter.subLayerKey = OVS_TUNNEL_SUBLAYER;
266     filter.weight.type = FWP_EMPTY; // auto-weight.
267     filter.rawContext = context;
268
269     conditionIndex = 0;
270
271     filterConditions[conditionIndex].fieldKey = FWPM_CONDITION_DIRECTION;
272     filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL;
273     filterConditions[conditionIndex].conditionValue.type = FWP_UINT32;
274     filterConditions[conditionIndex].conditionValue.uint32 = direction;
275
276     conditionIndex++;
277
278     filterConditions[conditionIndex].fieldKey = FWPM_CONDITION_IP_LOCAL_PORT;
279     filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL;
280     filterConditions[conditionIndex].conditionValue.type = FWP_UINT16;
281     filterConditions[conditionIndex].conditionValue.uint16 = remotePort;
282
283     conditionIndex++;
284
285     filter.numFilterConditions = conditionIndex;
286
287     status = FwpmFilterAdd(gEngineHandle,
288                            &filter,
289                            NULL,
290                            NULL);
291
292     return status;
293 }
294
295 NTSTATUS
296 OvsTunnelRemoveFilter(const GUID *filterKey,
297                       const GUID *sublayerKey)
298 {
299     NTSTATUS status = STATUS_SUCCESS;
300     BOOLEAN inTransaction = FALSE;
301
302     do {
303         status = FwpmTransactionBegin(gEngineHandle, 0);
304         if (!NT_SUCCESS(status)) {
305             break;
306         }
307
308         inTransaction = TRUE;
309
310         /*
311          * We have to delete the filter first since it references the
312          * sublayer. If we tried to delete the sublayer first, it would fail
313          * with FWP_ERR_IN_USE.
314          */
315         status = FwpmFilterDeleteByKey(gEngineHandle,
316                                        filterKey);
317         if (!NT_SUCCESS(status)) {
318             break;
319         }
320
321         status = FwpmSubLayerDeleteByKey(gEngineHandle,
322                                          sublayerKey);
323         if (!NT_SUCCESS(status)) {
324             break;
325         }
326
327         status = FwpmTransactionCommit(gEngineHandle);
328         if (!NT_SUCCESS(status)){
329             break;
330         }
331
332         inTransaction = FALSE;
333     } while (inTransaction);
334
335     if (inTransaction) {
336         FwpmTransactionAbort(gEngineHandle);
337     }
338     return status;
339 }
340
341 /*
342  * --------------------------------------------------------------------------
343  * This function registers callouts and filters that intercept UDP traffic at
344  * WFP FWPM_LAYER_DATAGRAM_DATA_V4
345  * --------------------------------------------------------------------------
346  */
347 NTSTATUS
348 OvsTunnelRegisterDatagramDataCallouts(const GUID *layerKey,
349                                       const GUID *calloutKey,
350                                       VOID *deviceObject,
351                                       UINT32 *calloutId)
352 {
353     NTSTATUS status = STATUS_SUCCESS;
354
355     FWPS_CALLOUT sCallout = {0};
356     FWPM_CALLOUT mCallout = {0};
357
358     FWPM_DISPLAY_DATA displayData = {0};
359
360     BOOLEAN calloutRegistered = FALSE;
361
362     sCallout.calloutKey = *calloutKey;
363     sCallout.classifyFn = OvsTunnelClassify;
364     sCallout.notifyFn = OvsTunnelNotify;
365 #if FLOW_CONTEXT
366     /* Currently we don't associate a context with the flow */
367     sCallout.flowDeleteFn = OvsTunnelFlowDelete;
368     sCallout.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW;
369 #endif
370
371     status = FwpsCalloutRegister(deviceObject,
372                                  &sCallout,
373                                  calloutId);
374
375     if (!NT_SUCCESS(status)) {
376         goto Exit;
377     }
378     calloutRegistered = TRUE;
379
380     displayData.name = L"Datagram-Data OVS Callout";
381     displayData.description = L"Proxies destination address/port for UDP";
382
383     mCallout.calloutKey = *calloutKey;
384     mCallout.displayData = displayData;
385     mCallout.applicableLayer = *layerKey;
386
387     status = FwpmCalloutAdd(gEngineHandle,
388                             &mCallout,
389                             NULL,
390                             NULL);
391
392     if (!NT_SUCCESS(status)) {
393         goto Exit;
394     }
395
396     status = OvsTunnelAddFilter(L"Datagram-Data OVS Filter (Inbound)",
397                                 L"address/port for UDP",
398                                 configNewDestPort,
399                                 FWP_DIRECTION_INBOUND,
400                                 0,
401                                 &OVS_TUNNEL_FILTER_KEY,
402                                 layerKey,
403                                 calloutKey);
404
405 Exit:
406
407     if (!NT_SUCCESS(status)){
408         if (calloutRegistered) {
409             FwpsCalloutUnregisterById(*calloutId);
410             *calloutId = 0;
411         }
412     }
413
414     return status;
415 }
416
417 /*
418  * --------------------------------------------------------------------------
419  * This function registers dynamic callouts and filters that intercept UDP
420  * Callouts and filters will be removed during De-Initialize.
421  * --------------------------------------------------------------------------
422  */
423 NTSTATUS
424 OvsTunnelRegisterCallouts(VOID *deviceObject)
425 {
426     NTSTATUS status = STATUS_SUCCESS;
427     FWPM_SUBLAYER OvsTunnelSubLayer;
428
429     BOOLEAN engineOpened = FALSE;
430     BOOLEAN inTransaction = FALSE;
431
432     status = OvsTunnelEngineOpen(&gEngineHandle);
433     if (!NT_SUCCESS(status)) {
434         goto Exit;
435     }
436     engineOpened = TRUE;
437
438     status = FwpmTransactionBegin(gEngineHandle, 0);
439     if (!NT_SUCCESS(status)) {
440         goto Exit;
441     }
442     inTransaction = TRUE;
443
444     RtlZeroMemory(&OvsTunnelSubLayer, sizeof(FWPM_SUBLAYER));
445
446     OvsTunnelSubLayer.subLayerKey = OVS_TUNNEL_SUBLAYER;
447     OvsTunnelSubLayer.displayData.name = L"Datagram-Data OVS Sub-Layer";
448     OvsTunnelSubLayer.displayData.description =
449         L"Sub-Layer for use by Datagram-Data OVS callouts";
450     OvsTunnelSubLayer.flags = 0;
451     OvsTunnelSubLayer.weight = FWP_EMPTY; /* auto-weight */
452
453     status = FwpmSubLayerAdd(gEngineHandle, &OvsTunnelSubLayer, NULL);
454     if (!NT_SUCCESS(status)) {
455         goto Exit;
456     }
457
458     /* In order to use this callout a socket must be opened. */
459     status = OvsTunnelRegisterDatagramDataCallouts(&FWPM_LAYER_DATAGRAM_DATA_V4,
460                                                    &OVS_TUNNEL_CALLOUT_V4,
461                                                    deviceObject,
462                                                    &gCalloutIdV4);
463     if (!NT_SUCCESS(status)) {
464         goto Exit;
465     }
466
467     status = FwpmTransactionCommit(gEngineHandle);
468     if (!NT_SUCCESS(status)){
469         goto Exit;
470     }
471     inTransaction = FALSE;
472
473 Exit:
474
475     if (!NT_SUCCESS(status)) {
476         if (inTransaction) {
477             FwpmTransactionAbort(gEngineHandle);
478         }
479         if (engineOpened) {
480             OvsTunnelEngineClose(&gEngineHandle);
481         }
482     }
483
484     return status;
485 }
486
487 VOID
488 OvsTunnelUnregisterCallouts(VOID)
489 {
490     OvsTunnelRemoveFilter(&OVS_TUNNEL_FILTER_KEY,
491                           &OVS_TUNNEL_SUBLAYER);
492     FwpsCalloutUnregisterById(gCalloutIdV4);
493     FwpmCalloutDeleteById(gEngineHandle, gCalloutIdV4);
494     OvsTunnelEngineClose(&gEngineHandle);
495 }
496
497 VOID
498 OvsTunnelFilterUninitialize(PDRIVER_OBJECT driverObject)
499 {
500     UNREFERENCED_PARAMETER(driverObject);
501
502     OvsTunnelUnregisterCallouts();
503     IoDeleteDevice(gDeviceObject);
504 }
505
506
507 NTSTATUS
508 OvsTunnelFilterInitialize(PDRIVER_OBJECT driverObject)
509 {
510     NTSTATUS status = STATUS_SUCCESS;
511     UNICODE_STRING deviceName;
512
513     RtlInitUnicodeString(&deviceName,
514                          L"\\Device\\OvsTunnelFilter");
515
516     status = IoCreateDevice(driverObject,
517                             0,
518                             &deviceName,
519                             FILE_DEVICE_NETWORK,
520                             0,
521                             FALSE,
522                             &gDeviceObject);
523
524     if (!NT_SUCCESS(status)){
525         goto Exit;
526     }
527
528     status = OvsTunnelRegisterCallouts(gDeviceObject);
529
530 Exit:
531
532     if (!NT_SUCCESS(status)){
533         if (gEngineHandle != NULL) {
534             OvsTunnelUnregisterCallouts();
535         }
536
537         if (gDeviceObject) {
538             IoDeleteDevice(gDeviceObject);
539         }
540     }
541
542     return status;
543 }
544
545 VOID NTAPI
546 OvsTunnelProviderBfeCallback(PVOID context,
547                              FWPM_SERVICE_STATE bfeState)
548 {
549     HANDLE handle = NULL;
550
551     DBG_UNREFERENCED_PARAMETER(context);
552
553     if (FWPM_SERVICE_RUNNING == bfeState) {
554         OvsTunnelEngineOpen(&handle);
555         if (handle) {
556             OvsTunnelAddSystemProvider(handle);
557         }
558         OvsTunnelEngineClose(&handle);
559     }
560 }
561
562 NTSTATUS
563 OvsSubscribeTunnelProviderBfeStateChanges(PVOID deviceObject)
564 {
565     NTSTATUS status = STATUS_SUCCESS;
566
567     if (!gTunnelProviderBfeHandle) {
568         status = FwpmBfeStateSubscribeChanges(deviceObject,
569                                               OvsTunnelProviderBfeCallback,
570                                               NULL,
571                                               &gTunnelProviderBfeHandle);
572         if (!NT_SUCCESS(status)) {
573             OVS_LOG_ERROR(
574                 "Failed to subscribe BFE tunnel provider callback, status: %x.",
575                 status);
576         }
577     }
578
579     return status;
580 }
581
582 VOID
583 OvsUnsubscribeTunnelProviderBfeStateChanges()
584 {
585     NTSTATUS status = STATUS_SUCCESS;
586
587     if (gTunnelProviderBfeHandle) {
588         status = FwpmBfeStateUnsubscribeChanges(gTunnelProviderBfeHandle);
589         if (!NT_SUCCESS(status)) {
590             OVS_LOG_ERROR(
591                 "Failed to unsubscribe BFE tunnel provider callback, status: %x.",
592                 status);
593         }
594         gTunnelProviderBfeHandle = NULL;
595     }
596 }
597
598 VOID
599 OvsRegisterSystemProvider(PVOID deviceObject)
600 {
601     NTSTATUS status = STATUS_SUCCESS;
602     HANDLE handle = NULL;
603
604     status = OvsSubscribeTunnelProviderBfeStateChanges(deviceObject);
605     if (NT_SUCCESS(status)) {
606         if (FWPM_SERVICE_RUNNING == FwpmBfeStateGet()) {
607             OvsTunnelEngineOpen(&handle);
608             if (handle) {
609                 OvsTunnelAddSystemProvider(handle);
610             }
611             OvsTunnelEngineClose(&handle);
612
613             OvsUnsubscribeTunnelProviderBfeStateChanges();
614         }
615     }
616 }
617
618 VOID OvsUnregisterSystemProvider()
619 {
620     HANDLE handle = NULL;
621
622     OvsTunnelEngineOpen(&handle);
623     if (handle) {
624         OvsTunnelRemoveSystemProvider(handle);
625     }
626     OvsTunnelEngineClose(&handle);
627
628     OvsUnsubscribeTunnelProviderBfeStateChanges();
629 }
630
631 VOID NTAPI
632 OvsTunnelInitBfeCallback(PVOID context,
633                          FWPM_SERVICE_STATE bfeState)
634 {
635     NTSTATUS status = STATUS_SUCCESS;
636     PDRIVER_OBJECT driverObject = (PDRIVER_OBJECT) context;
637
638     if (FWPM_SERVICE_RUNNING == bfeState) {
639         status = OvsTunnelFilterInitialize(driverObject);
640         if (!NT_SUCCESS(status)) {
641             OVS_LOG_ERROR(
642                 "Failed to initialize tunnel filter, status: %x.",
643                 status);
644         }
645     }
646 }
647
648 NTSTATUS
649 OvsSubscribeTunnelInitBfeStateChanges(PDRIVER_OBJECT driverObject,
650                                       PVOID deviceObject)
651 {
652     NTSTATUS status = STATUS_SUCCESS;
653
654     if (!gTunnelInitBfeHandle) {
655         status = FwpmBfeStateSubscribeChanges(deviceObject,
656                                               OvsTunnelInitBfeCallback,
657                                               driverObject,
658                                               &gTunnelInitBfeHandle);
659         if (!NT_SUCCESS(status)) {
660             OVS_LOG_ERROR(
661                 "Failed to subscribe BFE tunnel init callback, status: %x.",
662                 status);
663         }
664     }
665
666     return status;
667 }
668
669 VOID
670 OvsUnsubscribeTunnelInitBfeStateChanges()
671 {
672     NTSTATUS status = STATUS_SUCCESS;
673
674     if (gTunnelInitBfeHandle) {
675         status = FwpmBfeStateUnsubscribeChanges(gTunnelInitBfeHandle);
676         if (!NT_SUCCESS(status)) {
677             OVS_LOG_ERROR(
678                 "Failed to unsubscribe BFE tunnel init callback, status: %x.",
679                 status);
680         }
681         gTunnelInitBfeHandle = NULL;
682     }
683 }
684
685 NTSTATUS
686 OvsInitTunnelFilter(PDRIVER_OBJECT driverObject, PVOID deviceObject)
687 {
688     NTSTATUS status = STATUS_SUCCESS;
689
690     status = OvsSubscribeTunnelInitBfeStateChanges(driverObject, deviceObject);
691     if (NT_SUCCESS(status)) {
692         if (FWPM_SERVICE_RUNNING == FwpmBfeStateGet()) {
693             status = OvsTunnelFilterInitialize(driverObject);
694             if (!NT_SUCCESS(status)) {
695                 /* XXX: We need to decide what actions to take in case of
696                  * failure to initialize tunnel filter. */
697                 ASSERT(status == NDIS_STATUS_SUCCESS);
698                 OVS_LOG_ERROR(
699                     "Failed to initialize tunnel filter, status: %x.",
700                     status);
701             }
702             OvsUnsubscribeTunnelInitBfeStateChanges();
703         }
704     }
705
706     return status;
707 }
708
709 VOID OvsUninitTunnelFilter(PDRIVER_OBJECT driverObject)
710 {
711     OvsTunnelFilterUninitialize(driverObject);
712     OvsUnsubscribeTunnelInitBfeStateChanges();
713 }