2 * Copyright (c) 2016 Cloudbase Solutions Srl
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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 * --------------------------------------------------------------------------
28 typedef struct _OVS_DEFERRED_ACTION_QUEUE
{
31 OVS_DEFERRED_ACTION deferredActions
[DEFERRED_ACTION_QUEUE_SIZE
];
32 } OVS_DEFERRED_ACTION_QUEUE
, *POVS_DEFERRED_ACTION_QUEUE
;
34 typedef struct _OVS_DEFERRED_ACTION_DATA
{
35 OVS_DEFERRED_ACTION_QUEUE queue
;
37 } OVS_DEFERRED_ACTION_DATA
, *POVS_DEFERRED_ACTION_DATA
;
39 static POVS_DEFERRED_ACTION_DATA deferredData
= NULL
;
42 * --------------------------------------------------------------------------
43 * OvsDeferredActionsInit --
44 * The function allocates all necessary deferred actions resources.
45 * --------------------------------------------------------------------------
48 OvsDeferredActionsInit()
50 NTSTATUS status
= STATUS_SUCCESS
;
51 ULONG count
= KeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS
);
53 deferredData
= OvsAllocateMemoryPerCpu(sizeof(*deferredData
),
57 status
= NDIS_STATUS_RESOURCES
;
64 * --------------------------------------------------------------------------
65 * OvsDeferredActionsCleanup --
66 * The function frees all deferred actions resources.
67 * --------------------------------------------------------------------------
70 OvsDeferredActionsCleanup()
73 OvsFreeMemoryWithTag(deferredData
, OVS_RECIRC_POOL_TAG
);
79 * --------------------------------------------------------------------------
80 * OvsDeferredActionsQueueGet --
81 * The function returns the deferred action queue corresponding to the
83 * --------------------------------------------------------------------------
85 POVS_DEFERRED_ACTION_QUEUE
86 OvsDeferredActionsQueueGet()
88 POVS_DEFERRED_ACTION_QUEUE queue
= NULL
;
90 KIRQL oldIrql
= KeGetCurrentIrql();
92 if (oldIrql
< DISPATCH_LEVEL
) {
93 KeRaiseIrqlToDpcLevel();
96 index
= KeGetCurrentProcessorNumberEx(NULL
);
97 queue
= &deferredData
[index
].queue
;
99 if (oldIrql
< DISPATCH_LEVEL
) {
100 KeLowerIrql(oldIrql
);
107 * --------------------------------------------------------------------------
108 * OvsDeferredActionsLevelGet --
109 * The function returns the deferred action execution level corresponding
110 * to the current processor.
111 * --------------------------------------------------------------------------
114 OvsDeferredActionsLevelGet()
118 KIRQL oldIrql
= KeGetCurrentIrql();
120 if (oldIrql
< DISPATCH_LEVEL
) {
121 KeRaiseIrqlToDpcLevel();
124 index
= KeGetCurrentProcessorNumberEx(NULL
);
125 level
= deferredData
[index
].level
;
127 if (oldIrql
< DISPATCH_LEVEL
) {
128 KeLowerIrql(oldIrql
);
135 * --------------------------------------------------------------------------
136 * OvsDeferredActionsLevelInc --
137 * The function increments the deferred action execution level
138 * corresponding to the current processor.
139 * --------------------------------------------------------------------------
142 OvsDeferredActionsLevelInc()
145 KIRQL oldIrql
= KeGetCurrentIrql();
147 if (oldIrql
< DISPATCH_LEVEL
) {
148 KeRaiseIrqlToDpcLevel();
151 index
= KeGetCurrentProcessorNumberEx(NULL
);
152 deferredData
[index
].level
++;
154 if (oldIrql
< DISPATCH_LEVEL
) {
155 KeLowerIrql(oldIrql
);
160 * --------------------------------------------------------------------------
161 * OvsDeferredActionsLevelDec --
162 * The function decrements the deferred action execution level
163 * corresponding to the current processor.
164 * --------------------------------------------------------------------------
167 OvsDeferredActionsLevelDec()
170 KIRQL oldIrql
= KeGetCurrentIrql();
172 if (oldIrql
< DISPATCH_LEVEL
) {
173 KeRaiseIrqlToDpcLevel();
176 index
= KeGetCurrentProcessorNumberEx(NULL
);
177 deferredData
[index
].level
--;
179 if (oldIrql
< DISPATCH_LEVEL
) {
180 KeLowerIrql(oldIrql
);
185 * --------------------------------------------------------------------------
186 * OvsDeferredActionsQueueInit --
187 * The function resets the queue to be ready for the next packet.
188 * --------------------------------------------------------------------------
192 OvsDeferredActionsQueueInit(POVS_DEFERRED_ACTION_QUEUE queue
)
199 * --------------------------------------------------------------------------
200 * OvsDeferredActionsQueueIsEmpty --
201 * The function verifies if the queue is empty.
202 * --------------------------------------------------------------------------
206 OvsDeferredActionsQueueIsEmpty(const POVS_DEFERRED_ACTION_QUEUE queue
)
208 return (queue
->head
== queue
->tail
);
212 * --------------------------------------------------------------------------
213 * OvsDeferredActionsQueuePop --
214 * The function pops the next queue element.
215 * --------------------------------------------------------------------------
219 OvsDeferredActionsQueuePop(POVS_DEFERRED_ACTION_QUEUE queue
)
221 POVS_DEFERRED_ACTION deferredAction
= NULL
;
222 KIRQL oldIrql
= KeGetCurrentIrql();
224 if (oldIrql
< DISPATCH_LEVEL
) {
225 KeRaiseIrqlToDpcLevel();
228 if (OvsDeferredActionsQueueIsEmpty(queue
)) {
229 /* Reset the queue for the next packet. */
230 OvsDeferredActionsQueueInit(queue
);
232 deferredAction
= &queue
->deferredActions
[queue
->tail
++];
235 if (oldIrql
< DISPATCH_LEVEL
) {
236 KeLowerIrql(oldIrql
);
239 return deferredAction
;
243 * --------------------------------------------------------------------------
244 * OvsDeferredActionsQueuePush --
245 * The function pushes the current element in the deferred actions queue.
246 * --------------------------------------------------------------------------
250 OvsDeferredActionsQueuePush(POVS_DEFERRED_ACTION_QUEUE queue
)
252 POVS_DEFERRED_ACTION deferredAction
= NULL
;
253 KIRQL oldIrql
= KeGetCurrentIrql();
255 if (oldIrql
< DISPATCH_LEVEL
) {
256 KeRaiseIrqlToDpcLevel();
259 if (queue
->head
< DEFERRED_ACTION_QUEUE_SIZE
) {
260 deferredAction
= &queue
->deferredActions
[queue
->head
++];
263 if (oldIrql
< DISPATCH_LEVEL
) {
264 KeLowerIrql(oldIrql
);
267 return deferredAction
;
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 * --------------------------------------------------------------------------
278 OvsAddDeferredActions(PNET_BUFFER_LIST nbl
,
280 const PNL_ATTR actions
)
282 POVS_DEFERRED_ACTION_QUEUE queue
= OvsDeferredActionsQueueGet();
283 POVS_DEFERRED_ACTION deferredAction
= NULL
;
285 deferredAction
= OvsDeferredActionsQueuePush(queue
);
286 if (deferredAction
) {
287 deferredAction
->nbl
= nbl
;
288 deferredAction
->actions
= actions
;
289 deferredAction
->key
= *key
;
292 return deferredAction
;
296 * --------------------------------------------------------------------------
297 * OvsProcessDeferredActions --
298 * This function processes all deferred actions contained in the queue
299 * corresponding to the current CPU.
300 * --------------------------------------------------------------------------
303 OvsProcessDeferredActions(POVS_SWITCH_CONTEXT switchContext
,
304 OvsCompletionList
*completionList
,
307 OVS_PACKET_HDR_INFO
*layers
)
309 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
310 POVS_DEFERRED_ACTION_QUEUE queue
= OvsDeferredActionsQueueGet();
311 POVS_DEFERRED_ACTION deferredAction
= NULL
;
313 /* Process all deferred actions. */
314 while ((deferredAction
= OvsDeferredActionsQueuePop(queue
)) != NULL
) {
315 if (deferredAction
->actions
) {
316 status
= OvsDoExecuteActions(switchContext
,
321 &deferredAction
->key
, NULL
,
322 layers
, deferredAction
->actions
,
323 NlAttrGetSize(deferredAction
->actions
));
325 status
= OvsDoRecirc(switchContext
,
328 &deferredAction
->key
,