]> git.proxmox.com Git - mirror_ovs.git/blob - datapath-windows/ovsext/Recirc.c
datapath-windows: Fix conntrack event handler
[mirror_ovs.git] / datapath-windows / ovsext / Recirc.c
1 /*
2 * Copyright (c) 2016 Cloudbase Solutions Srl
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 "Recirc.h"
18 #include "Flow.h"
19 #include "Jhash.h"
20
21 /*
22 * --------------------------------------------------------------------------
23 * '_OVS_DEFERRED_ACTION_QUEUE' structure is responsible for keeping track of
24 * all deferred actions. The maximum number of deferred actions should not
25 * exceed 'DEFERRED_ACTION_QUEUE_SIZE'.
26 * --------------------------------------------------------------------------
27 */
28 typedef struct _OVS_DEFERRED_ACTION_QUEUE {
29 UINT32 head;
30 UINT32 tail;
31 OVS_DEFERRED_ACTION deferredActions[DEFERRED_ACTION_QUEUE_SIZE];
32 } OVS_DEFERRED_ACTION_QUEUE, *POVS_DEFERRED_ACTION_QUEUE;
33
34 typedef struct _OVS_DEFERRED_ACTION_DATA {
35 OVS_DEFERRED_ACTION_QUEUE queue;
36 UINT32 level;
37 } OVS_DEFERRED_ACTION_DATA, *POVS_DEFERRED_ACTION_DATA;
38
39 static POVS_DEFERRED_ACTION_DATA deferredData = NULL;
40
41 /*
42 * --------------------------------------------------------------------------
43 * OvsDeferredActionsInit --
44 * The function allocates all necessary deferred actions resources.
45 * --------------------------------------------------------------------------
46 */
47 NTSTATUS
48 OvsDeferredActionsInit()
49 {
50 NTSTATUS status = STATUS_SUCCESS;
51 ULONG count = KeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS);
52
53 deferredData = OvsAllocateMemoryPerCpu(sizeof(*deferredData),
54 count,
55 OVS_RECIRC_POOL_TAG);
56 if (!deferredData) {
57 status = NDIS_STATUS_RESOURCES;
58 }
59
60 return status;
61 }
62
63 /*
64 * --------------------------------------------------------------------------
65 * OvsDeferredActionsCleanup --
66 * The function frees all deferred actions resources.
67 * --------------------------------------------------------------------------
68 */
69 VOID
70 OvsDeferredActionsCleanup()
71 {
72 if (deferredData) {
73 OvsFreeMemoryWithTag(deferredData, OVS_RECIRC_POOL_TAG);
74 deferredData = NULL;
75 }
76 }
77
78 /*
79 * --------------------------------------------------------------------------
80 * OvsDeferredActionsQueueGet --
81 * The function returns the deferred action queue corresponding to the
82 * current processor.
83 * --------------------------------------------------------------------------
84 */
85 POVS_DEFERRED_ACTION_QUEUE
86 OvsDeferredActionsQueueGet()
87 {
88 POVS_DEFERRED_ACTION_QUEUE queue = NULL;
89 ULONG index = 0;
90 KIRQL oldIrql = KeGetCurrentIrql();
91
92 if (oldIrql < DISPATCH_LEVEL) {
93 KeRaiseIrqlToDpcLevel();
94 }
95
96 index = KeGetCurrentProcessorNumberEx(NULL);
97 queue = &deferredData[index].queue;
98
99 if (oldIrql < DISPATCH_LEVEL) {
100 KeLowerIrql(oldIrql);
101 }
102
103 return queue;
104 }
105
106 /*
107 * --------------------------------------------------------------------------
108 * OvsDeferredActionsLevelGet --
109 * The function returns the deferred action execution level corresponding
110 * to the current processor.
111 * --------------------------------------------------------------------------
112 */
113 UINT32
114 OvsDeferredActionsLevelGet()
115 {
116 UINT32 level = 0;
117 ULONG index = 0;
118 KIRQL oldIrql = KeGetCurrentIrql();
119
120 if (oldIrql < DISPATCH_LEVEL) {
121 KeRaiseIrqlToDpcLevel();
122 }
123
124 index = KeGetCurrentProcessorNumberEx(NULL);
125 level = deferredData[index].level;
126
127 if (oldIrql < DISPATCH_LEVEL) {
128 KeLowerIrql(oldIrql);
129 }
130
131 return level;
132 }
133
134 /*
135 * --------------------------------------------------------------------------
136 * OvsDeferredActionsLevelInc --
137 * The function increments the deferred action execution level
138 * corresponding to the current processor.
139 * --------------------------------------------------------------------------
140 */
141 VOID
142 OvsDeferredActionsLevelInc()
143 {
144 ULONG index = 0;
145 KIRQL oldIrql = KeGetCurrentIrql();
146
147 if (oldIrql < DISPATCH_LEVEL) {
148 KeRaiseIrqlToDpcLevel();
149 }
150
151 index = KeGetCurrentProcessorNumberEx(NULL);
152 deferredData[index].level++;
153
154 if (oldIrql < DISPATCH_LEVEL) {
155 KeLowerIrql(oldIrql);
156 }
157 }
158
159 /*
160 * --------------------------------------------------------------------------
161 * OvsDeferredActionsLevelDec --
162 * The function decrements the deferred action execution level
163 * corresponding to the current processor.
164 * --------------------------------------------------------------------------
165 */
166 VOID
167 OvsDeferredActionsLevelDec()
168 {
169 ULONG index = 0;
170 KIRQL oldIrql = KeGetCurrentIrql();
171
172 if (oldIrql < DISPATCH_LEVEL) {
173 KeRaiseIrqlToDpcLevel();
174 }
175
176 index = KeGetCurrentProcessorNumberEx(NULL);
177 deferredData[index].level--;
178
179 if (oldIrql < DISPATCH_LEVEL) {
180 KeLowerIrql(oldIrql);
181 }
182 }
183
184 /*
185 * --------------------------------------------------------------------------
186 * OvsDeferredActionsQueueInit --
187 * The function resets the queue to be ready for the next packet.
188 * --------------------------------------------------------------------------
189 */
190 static
191 VOID
192 OvsDeferredActionsQueueInit(POVS_DEFERRED_ACTION_QUEUE queue)
193 {
194 queue->head = 0;
195 queue->tail = 0;
196 }
197
198 /*
199 * --------------------------------------------------------------------------
200 * OvsDeferredActionsQueueIsEmpty --
201 * The function verifies if the queue is empty.
202 * --------------------------------------------------------------------------
203 */
204 static
205 BOOLEAN
206 OvsDeferredActionsQueueIsEmpty(const POVS_DEFERRED_ACTION_QUEUE queue)
207 {
208 return (queue->head == queue->tail);
209 }
210
211 /*
212 * --------------------------------------------------------------------------
213 * OvsDeferredActionsQueuePop --
214 * The function pops the next queue element.
215 * --------------------------------------------------------------------------
216 */
217 static
218 POVS_DEFERRED_ACTION
219 OvsDeferredActionsQueuePop(POVS_DEFERRED_ACTION_QUEUE queue)
220 {
221 POVS_DEFERRED_ACTION deferredAction = NULL;
222 KIRQL oldIrql = KeGetCurrentIrql();
223
224 if (oldIrql < DISPATCH_LEVEL) {
225 KeRaiseIrqlToDpcLevel();
226 }
227
228 if (OvsDeferredActionsQueueIsEmpty(queue)) {
229 /* Reset the queue for the next packet. */
230 OvsDeferredActionsQueueInit(queue);
231 } else {
232 deferredAction = &queue->deferredActions[queue->tail++];
233 }
234
235 if (oldIrql < DISPATCH_LEVEL) {
236 KeLowerIrql(oldIrql);
237 }
238
239 return deferredAction;
240 }
241
242 /*
243 * --------------------------------------------------------------------------
244 * OvsDeferredActionsQueuePush --
245 * The function pushes the current element in the deferred actions queue.
246 * --------------------------------------------------------------------------
247 */
248 static
249 POVS_DEFERRED_ACTION
250 OvsDeferredActionsQueuePush(POVS_DEFERRED_ACTION_QUEUE queue)
251 {
252 POVS_DEFERRED_ACTION deferredAction = NULL;
253 KIRQL oldIrql = KeGetCurrentIrql();
254
255 if (oldIrql < DISPATCH_LEVEL) {
256 KeRaiseIrqlToDpcLevel();
257 }
258
259 if (queue->head < DEFERRED_ACTION_QUEUE_SIZE) {
260 deferredAction = &queue->deferredActions[queue->head++];
261 }
262
263 if (oldIrql < DISPATCH_LEVEL) {
264 KeLowerIrql(oldIrql);
265 }
266
267 return deferredAction;
268 }
269
270 /*
271 * --------------------------------------------------------------------------
272 * OvsAddDeferredActions --
273 * This function adds the deferred action to the current CPU queue and
274 * returns the new queue entry if the queue is not already full.
275 * --------------------------------------------------------------------------
276 */
277 POVS_DEFERRED_ACTION
278 OvsAddDeferredActions(PNET_BUFFER_LIST nbl,
279 OvsFlowKey *key,
280 const PNL_ATTR actions)
281 {
282 POVS_DEFERRED_ACTION_QUEUE queue = OvsDeferredActionsQueueGet();
283 POVS_DEFERRED_ACTION deferredAction = NULL;
284
285 deferredAction = OvsDeferredActionsQueuePush(queue);
286 if (deferredAction) {
287 deferredAction->nbl = nbl;
288 deferredAction->actions = actions;
289 deferredAction->key = *key;
290 }
291
292 return deferredAction;
293 }
294
295 /*
296 * --------------------------------------------------------------------------
297 * OvsProcessDeferredActions --
298 * This function processes all deferred actions contained in the queue
299 * corresponding to the current CPU.
300 * --------------------------------------------------------------------------
301 */
302 NDIS_STATUS
303 OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext,
304 OvsCompletionList *completionList,
305 UINT32 portNo,
306 ULONG sendFlags,
307 OVS_PACKET_HDR_INFO *layers)
308 {
309 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
310 POVS_DEFERRED_ACTION_QUEUE queue = OvsDeferredActionsQueueGet();
311 POVS_DEFERRED_ACTION deferredAction = NULL;
312
313 /* Process all deferred actions. */
314 while ((deferredAction = OvsDeferredActionsQueuePop(queue)) != NULL) {
315 if (deferredAction->actions) {
316 status = OvsDoExecuteActions(switchContext,
317 completionList,
318 deferredAction->nbl,
319 portNo,
320 sendFlags,
321 &deferredAction->key, NULL,
322 layers, deferredAction->actions,
323 NlAttrGetSize(deferredAction->actions));
324 } else {
325 status = OvsDoRecirc(switchContext,
326 completionList,
327 deferredAction->nbl,
328 &deferredAction->key,
329 portNo,
330 layers);
331 }
332 }
333
334 return status;
335 }