]>
Commit | Line | Data |
---|---|---|
c803536e | 1 | /* |
7b383a56 | 2 | * Copyright (c) 2014, 2016 VMware, Inc. |
c803536e SS |
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 | * **************************************************************************** | |
19 | * | |
20 | * Simple Buffer Management framework for OVS | |
21 | * | |
22 | * It introduces four NDIS buffer pools | |
23 | * **Fix size net buffer list pool--this is used for small buffer | |
24 | * One allocation will include NBL + NB + MDL + Data + CONTEXT. | |
25 | * | |
26 | * **Variable size net buffer list pool--this is used for variable size | |
27 | * buffer. The allocation of net buffer list will include NBL + NB + | |
28 | * CONTEXT, a separate allocation of MDL + data buffer is required. | |
29 | * | |
30 | * **NBL only net buffer list pool-- this is used for partial copy | |
31 | * (or clone). In this case we can not allocate net buffer list and | |
32 | * net buffer at the same time. | |
33 | * | |
34 | * **Net buffer pool-- this is required when net buffer need to be | |
35 | * allocated separately. | |
36 | * | |
37 | * A Buffer context is defined to track the buffer specific information | |
38 | * so that during NBL completion, proper action can be taken. Please see | |
39 | * code for details. | |
40 | * | |
41 | * Here is the usage of the management API | |
42 | * All external NBL should be initialized its NBL context by calling | |
43 | * OvsInitExternalNBLContext() | |
44 | * | |
45 | * After the external NBL context is initialized, it can call the following | |
46 | * API to allocate, copy or partial copy NBL. | |
47 | * | |
48 | * OvsAllocateFixSizeNBL() | |
49 | * OvsAllocateVariableSizeNBL() | |
50 | * | |
51 | * OvsPartialCopyNBL() | |
52 | * OvsPartialCopyToMultipleNBLs() | |
53 | * | |
54 | * OvsFullCopyNBL() | |
55 | * OvsFullCopyToMultipleNBLs() | |
56 | * | |
57 | * See code comments for detail description of the functions. | |
58 | * | |
59 | * All NBLs is completed through | |
60 | * OvsCompleteNBL() | |
61 | * If this API return non NULL value, then the returned NBL should be | |
62 | * returned to upper layer by calling | |
63 | * NdisFSendNetBufferListsComplete() if the buffer is from upper | |
64 | * layer. In case of WFP, it can call the corresponding completion routine | |
65 | * to return the NBL to the framework. | |
66 | * | |
67 | * NOTE: | |
68 | * 1. Copy or partial copy will not copy destination port array | |
69 | * 2. Copy or partial copy will copy src port id and index | |
70 | * 3. New Allocated NBL will have src port set to default port id | |
71 | * 4. If original packet has direction flag set, the copied or partial | |
72 | * copied NBL will still be in same direction. | |
73 | * 5. When you advance or retreate the buffer, you may need to update | |
74 | * relevant meta data to keep it consistent. | |
75 | * | |
76 | * **************************************************************************** | |
77 | */ | |
78 | ||
79 | #include "precomp.h" | |
7b383a56 AS |
80 | #include "Debug.h" |
81 | #include "Flow.h" | |
82 | #include "Offload.h" | |
83 | #include "NetProto.h" | |
84 | #include "PacketParser.h" | |
fa1324c9 | 85 | #include "Switch.h" |
7b383a56 | 86 | #include "Vport.h" |
c803536e SS |
87 | |
88 | #ifdef OVS_DBG_MOD | |
89 | #undef OVS_DBG_MOD | |
90 | #endif | |
91 | #define OVS_DBG_MOD OVS_DBG_BUFMGMT | |
7b383a56 | 92 | |
c803536e SS |
93 | |
94 | /* | |
95 | * -------------------------------------------------------------------------- | |
96 | * OvsInitBufferPool -- | |
97 | * | |
98 | * Allocate NBL and NB pool | |
99 | * | |
100 | * XXX: more optimization may be done for buffer management include local cache | |
101 | * of NBL, NB, data, context, MDL. | |
102 | * -------------------------------------------------------------------------- | |
103 | */ | |
104 | NDIS_STATUS | |
105 | OvsInitBufferPool(PVOID ovsContext) | |
106 | { | |
107 | POVS_NBL_POOL ovsPool; | |
108 | POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; | |
109 | NET_BUFFER_LIST_POOL_PARAMETERS nblParam; | |
110 | NET_BUFFER_POOL_PARAMETERS nbParam; | |
111 | ||
112 | C_ASSERT(MEMORY_ALLOCATION_ALIGNMENT >= 8); | |
113 | ||
114 | OVS_LOG_TRACE("Enter: context: %p", context); | |
115 | ||
116 | ovsPool = &context->ovsPool; | |
117 | RtlZeroMemory(ovsPool, sizeof (OVS_NBL_POOL)); | |
118 | ovsPool->ndisHandle = context->NdisFilterHandle; | |
119 | ovsPool->ndisContext = context->NdisSwitchContext; | |
120 | /* | |
121 | * fix size NBL pool includes | |
122 | * NBL + NB + MDL + DATA + Context | |
123 | * This is mainly used for Packet execute or slow path when copy is | |
124 | * required and size is less than OVS_DEFAULT_DATA_SIZE. We expect | |
125 | * Most of packet from user space will use this Pool. (This is | |
126 | * true for all bfd and cfm packet. | |
127 | */ | |
128 | RtlZeroMemory(&nblParam, sizeof (nblParam)); | |
129 | OVS_INIT_OBJECT_HEADER(&nblParam.Header, | |
130 | NDIS_OBJECT_TYPE_DEFAULT, | |
131 | NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1, | |
132 | NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1); | |
133 | nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE; | |
134 | nblParam.PoolTag = OVS_FIX_SIZE_NBL_POOL_TAG; | |
135 | nblParam.fAllocateNetBuffer = TRUE; | |
136 | nblParam.DataSize = OVS_DEFAULT_DATA_SIZE + OVS_DEFAULT_HEADROOM_SIZE; | |
137 | ||
138 | ovsPool->fixSizePool = | |
139 | NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam); | |
140 | if (ovsPool->fixSizePool == NULL) { | |
141 | goto pool_cleanup; | |
142 | } | |
143 | ||
144 | /* | |
145 | * Zero Size NBL Pool includes | |
146 | * NBL + NB + Context | |
147 | * This is mainly for packet with large data Size, in this case MDL and | |
148 | * Data will be allocate separately. | |
149 | */ | |
150 | RtlZeroMemory(&nblParam, sizeof (nblParam)); | |
151 | OVS_INIT_OBJECT_HEADER(&nblParam.Header, | |
152 | NDIS_OBJECT_TYPE_DEFAULT, | |
153 | NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1, | |
154 | NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1); | |
155 | ||
156 | nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE; | |
157 | nblParam.PoolTag = OVS_VARIABLE_SIZE_NBL_POOL_TAG; | |
158 | nblParam.fAllocateNetBuffer = TRUE; | |
159 | nblParam.DataSize = 0; | |
160 | ||
161 | ovsPool->zeroSizePool = | |
162 | NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam); | |
163 | if (ovsPool->zeroSizePool == NULL) { | |
164 | goto pool_cleanup; | |
165 | } | |
166 | ||
167 | /* | |
168 | * NBL only pool just includes | |
169 | * NBL (+ context) | |
170 | * This is mainly used for clone and partial copy | |
171 | */ | |
172 | RtlZeroMemory(&nblParam, sizeof (nblParam)); | |
173 | OVS_INIT_OBJECT_HEADER(&nblParam.Header, | |
174 | NDIS_OBJECT_TYPE_DEFAULT, | |
175 | NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1, | |
176 | NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1); | |
177 | ||
178 | nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE; | |
179 | nblParam.PoolTag = OVS_NBL_ONLY_POOL_TAG; | |
180 | nblParam.fAllocateNetBuffer = FALSE; | |
181 | nblParam.DataSize = 0; | |
182 | ||
183 | ovsPool->nblOnlyPool = | |
184 | NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam); | |
185 | if (ovsPool->nblOnlyPool == NULL) { | |
186 | goto pool_cleanup; | |
187 | } | |
188 | ||
189 | /* nb Pool | |
190 | * NB only pool, used for copy | |
191 | */ | |
192 | ||
193 | OVS_INIT_OBJECT_HEADER(&nbParam.Header, | |
194 | NDIS_OBJECT_TYPE_DEFAULT, | |
195 | NET_BUFFER_POOL_PARAMETERS_REVISION_1, | |
196 | NDIS_SIZEOF_NET_BUFFER_POOL_PARAMETERS_REVISION_1); | |
197 | nbParam.PoolTag = OVS_NET_BUFFER_POOL_TAG; | |
198 | nbParam.DataSize = 0; | |
199 | ovsPool->nbPool = | |
200 | NdisAllocateNetBufferPool(context->NdisSwitchContext, &nbParam); | |
201 | if (ovsPool->nbPool == NULL) { | |
202 | goto pool_cleanup; | |
203 | } | |
204 | OVS_LOG_TRACE("Exit: fixSizePool: %p zeroSizePool: %p nblOnlyPool: %p" | |
205 | "nbPool: %p", ovsPool->fixSizePool, ovsPool->zeroSizePool, | |
206 | ovsPool->nblOnlyPool, ovsPool->nbPool); | |
207 | return NDIS_STATUS_SUCCESS; | |
208 | ||
209 | pool_cleanup: | |
210 | OvsCleanupBufferPool(context); | |
211 | OVS_LOG_TRACE("Exit: Fail to initialize ovs buffer pool"); | |
212 | return NDIS_STATUS_RESOURCES; | |
213 | } | |
214 | ||
215 | ||
216 | /* | |
217 | * -------------------------------------------------------------------------- | |
218 | * OvsCleanupBufferPool -- | |
219 | * Free Buffer pool for NBL and NB. | |
220 | * -------------------------------------------------------------------------- | |
221 | */ | |
222 | VOID | |
223 | OvsCleanupBufferPool(PVOID ovsContext) | |
224 | { | |
225 | POVS_NBL_POOL ovsPool; | |
226 | POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; | |
227 | ovsPool = &context->ovsPool; | |
228 | OVS_LOG_TRACE("Enter: context: %p", context); | |
229 | #ifdef DBG | |
230 | ASSERT(ovsPool->fixNBLCount == 0); | |
231 | ASSERT(ovsPool->zeroNBLCount == 0); | |
232 | ASSERT(ovsPool->nblOnlyCount == 0); | |
233 | ASSERT(ovsPool->nbCount == 0); | |
234 | ASSERT(ovsPool->sysNBLCount == 0); | |
235 | ASSERT(ovsPool->fragNBLCount == 0); | |
236 | #endif | |
237 | ||
238 | if (ovsPool->fixSizePool) { | |
239 | NdisFreeNetBufferListPool(ovsPool->fixSizePool); | |
240 | ovsPool->fixSizePool = NULL; | |
241 | } | |
242 | if (ovsPool->zeroSizePool) { | |
243 | NdisFreeNetBufferListPool(ovsPool->zeroSizePool); | |
244 | ovsPool->zeroSizePool = NULL; | |
245 | } | |
246 | if (ovsPool->nblOnlyPool) { | |
247 | NdisFreeNetBufferListPool(ovsPool->nblOnlyPool); | |
248 | ovsPool->nblOnlyPool = NULL; | |
249 | } | |
250 | if (ovsPool->nbPool) { | |
251 | NdisFreeNetBufferPool(ovsPool->nbPool); | |
252 | ovsPool->nbPool = NULL; | |
253 | } | |
254 | OVS_LOG_TRACE("Exit: cleanup OVS Buffer pool"); | |
255 | } | |
256 | ||
257 | ||
258 | static VOID | |
259 | OvsInitNBLContext(POVS_BUFFER_CONTEXT ctx, | |
260 | UINT16 flags, | |
261 | UINT32 origDataLength, | |
262 | UINT32 srcPortNo) | |
263 | { | |
264 | ctx->magic = OVS_CTX_MAGIC; | |
265 | ctx->refCount = 1; | |
266 | ctx->flags = flags; | |
267 | ctx->srcPortNo = srcPortNo; | |
268 | ctx->origDataLength = origDataLength; | |
269 | } | |
270 | ||
271 | ||
272 | static VOID | |
273 | OvsDumpForwardingDetails(PNET_BUFFER_LIST nbl) | |
274 | { | |
275 | PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info; | |
276 | info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl); | |
277 | if (info == NULL) { | |
278 | return; | |
279 | } | |
280 | OVS_LOG_INFO("nbl: %p, numAvailableDest: %d, srcId:%d, srcIndex: %d " | |
281 | "isDataSafe: %s, safeDataSize: %d", | |
282 | nbl, info->NumAvailableDestinations, info->SourcePortId, | |
283 | info->SourceNicIndex, | |
284 | info->IsPacketDataSafe ? "TRUE" : "FALSE", | |
285 | info->IsPacketDataSafe ? 0 : info->SafePacketDataSize); | |
286 | ||
287 | } | |
288 | ||
289 | static VOID | |
290 | OvsDumpNBLContext(PNET_BUFFER_LIST nbl) | |
291 | { | |
292 | PNET_BUFFER_LIST_CONTEXT ctx = nbl->Context; | |
293 | if (ctx == NULL) { | |
294 | OVS_LOG_INFO("No Net Buffer List context"); | |
295 | return; | |
296 | } | |
297 | while (ctx) { | |
298 | OVS_LOG_INFO("nbl: %p, ctx: %p, TotalSize: %d, Offset: %d", | |
299 | nbl, ctx, ctx->Size, ctx->Offset); | |
300 | ctx = ctx->Next; | |
301 | } | |
302 | } | |
303 | ||
304 | ||
305 | static VOID | |
306 | OvsDumpMDLChain(PMDL mdl) | |
307 | { | |
308 | PMDL tmp; | |
309 | tmp = mdl; | |
310 | while (tmp) { | |
311 | OVS_LOG_INFO("MDL: %p, Size: %d, MappedSystemVa: %p, StartVa: %p" | |
312 | " ByteCount: %d, ByteOffset: %d", | |
313 | tmp, tmp->Size, tmp->MappedSystemVa, | |
314 | tmp->StartVa, tmp->ByteCount, tmp->ByteOffset); | |
315 | tmp = tmp->Next; | |
316 | } | |
317 | } | |
318 | ||
319 | ||
320 | static VOID | |
321 | OvsDumpNetBuffer(PNET_BUFFER nb) | |
322 | { | |
323 | OVS_LOG_INFO("NET_BUFFER: %p, ChecksumBias: %d Handle: %p, MDLChain: %p " | |
324 | "CurrMDL: %p, CurrOffset: %d, DataLen: %d, Offset: %d", | |
325 | nb, | |
326 | NET_BUFFER_CHECKSUM_BIAS(nb), nb->NdisPoolHandle, | |
327 | NET_BUFFER_FIRST_MDL(nb), | |
328 | NET_BUFFER_CURRENT_MDL(nb), | |
329 | NET_BUFFER_CURRENT_MDL_OFFSET(nb), | |
330 | NET_BUFFER_DATA_LENGTH(nb), | |
331 | NET_BUFFER_DATA_OFFSET(nb)); | |
332 | OvsDumpMDLChain(NET_BUFFER_FIRST_MDL(nb)); | |
333 | } | |
334 | ||
335 | ||
336 | static VOID | |
337 | OvsDumpNetBufferList(PNET_BUFFER_LIST nbl) | |
338 | { | |
339 | PNET_BUFFER nb; | |
340 | OVS_LOG_INFO("NBL: %p, parent: %p, SrcHandle: %p, ChildCount:%d " | |
341 | "poolHandle: %p", | |
342 | nbl, nbl->ParentNetBufferList, | |
343 | nbl->SourceHandle, nbl->ChildRefCount, | |
344 | nbl->NdisPoolHandle); | |
345 | OvsDumpNBLContext(nbl); | |
346 | nb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
347 | while (nb) { | |
348 | OvsDumpNetBuffer(nb); | |
349 | nb = NET_BUFFER_NEXT_NB(nb); | |
350 | } | |
351 | } | |
352 | ||
353 | /* | |
354 | * -------------------------------------------------------------------------- | |
355 | * OvsAllocateFixSizeNBL -- | |
356 | * | |
357 | * Allocate fix size NBL which include | |
358 | * NBL + NB + MBL + Data + Context | |
359 | * Please note: | |
360 | * * Forwarding Context is allocated, but forwarding detail information | |
361 | * is not initailized. | |
362 | * * The headroom can not be larger than OVS_DEFAULT_HEADROOM_SIZE(128 | |
363 | * byte). | |
364 | * -------------------------------------------------------------------------- | |
365 | */ | |
366 | PNET_BUFFER_LIST | |
367 | OvsAllocateFixSizeNBL(PVOID ovsContext, | |
368 | UINT32 size, | |
369 | UINT32 headRoom) | |
370 | { | |
371 | PNET_BUFFER_LIST nbl = NULL; | |
372 | POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; | |
373 | POVS_BUFFER_CONTEXT ctx; | |
374 | POVS_NBL_POOL ovsPool = &context->ovsPool; | |
375 | NDIS_STATUS status; | |
376 | UINT32 line; | |
377 | PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info; | |
378 | ||
379 | if ((headRoom + size) > OVS_FIX_NBL_DATA_SIZE || size == 0) { | |
380 | line = __LINE__; | |
381 | goto allocate_done; | |
382 | } | |
383 | ||
384 | nbl = NdisAllocateNetBufferList(ovsPool->fixSizePool, | |
385 | (UINT16)sizeof (OVS_BUFFER_CONTEXT), | |
386 | (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL); | |
387 | ||
388 | if (nbl == NULL) { | |
389 | line = __LINE__; | |
390 | goto allocate_done; | |
391 | } | |
392 | ||
393 | nbl->SourceHandle = ovsPool->ndisHandle; | |
394 | status = context->NdisSwitchHandlers. | |
395 | AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl); | |
396 | ||
397 | if (status != NDIS_STATUS_SUCCESS) { | |
398 | NdisFreeNetBufferList(nbl); | |
399 | nbl = NULL; | |
400 | line = __LINE__; | |
401 | goto allocate_done; | |
402 | } | |
403 | info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl); | |
404 | ASSERT(info); | |
405 | info->IsPacketDataSafe = TRUE; | |
406 | info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID; | |
407 | ||
408 | status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl), | |
409 | size, 0, NULL); | |
410 | ASSERT(status == NDIS_STATUS_SUCCESS); | |
411 | ||
412 | #ifdef DBG | |
413 | InterlockedIncrement((LONG volatile *)&ovsPool->fixNBLCount); | |
414 | OvsDumpNetBufferList(nbl); | |
415 | OvsDumpForwardingDetails(nbl); | |
416 | #endif | |
417 | ||
418 | ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); | |
419 | ASSERT(ctx); | |
420 | ||
421 | OvsInitNBLContext(ctx, OVS_BUFFER_FROM_FIX_SIZE_POOL | | |
422 | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT, size, | |
12e888ba | 423 | OVS_DPPORT_NUMBER_INVALID); |
c803536e SS |
424 | line = __LINE__; |
425 | allocate_done: | |
426 | OVS_LOG_LOUD("Allocate Fix NBL: %p, line: %d", nbl, line); | |
427 | return nbl; | |
428 | } | |
429 | ||
430 | ||
431 | static PMDL | |
432 | OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle, | |
433 | UINT32 dataSize) | |
434 | { | |
435 | PMDL mdl; | |
436 | PVOID data; | |
437 | ||
48b3e646 | 438 | data = OvsAllocateMemoryWithTag(dataSize, OVS_MDL_POOL_TAG); |
c803536e SS |
439 | if (data == NULL) { |
440 | return NULL; | |
441 | } | |
442 | ||
443 | mdl = NdisAllocateMdl(ndisHandle, data, dataSize); | |
444 | if (mdl == NULL) { | |
48b3e646 | 445 | OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG); |
c803536e SS |
446 | } |
447 | ||
448 | return mdl; | |
449 | } | |
450 | ||
451 | ||
452 | static VOID | |
453 | OvsFreeMDLAndData(PMDL mdl) | |
454 | { | |
455 | PVOID data; | |
456 | ||
457 | data = MmGetMdlVirtualAddress(mdl); | |
458 | NdisFreeMdl(mdl); | |
48b3e646 | 459 | OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG); |
c803536e SS |
460 | } |
461 | ||
462 | ||
463 | /* | |
464 | * -------------------------------------------------------------------------- | |
465 | * OvsAllocateVariableSizeNBL -- | |
466 | * | |
467 | * Allocate variable size NBL, the NBL looks like | |
468 | * NBL + NB + Context | |
469 | * MDL + Data | |
470 | * -------------------------------------------------------------------------- | |
471 | */ | |
472 | PNET_BUFFER_LIST | |
473 | OvsAllocateVariableSizeNBL(PVOID ovsContext, | |
474 | UINT32 size, | |
475 | UINT32 headRoom) | |
476 | { | |
477 | PNET_BUFFER_LIST nbl = NULL; | |
478 | POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; | |
479 | POVS_NBL_POOL ovsPool = &context->ovsPool; | |
480 | POVS_BUFFER_CONTEXT ctx; | |
481 | UINT32 realSize; | |
482 | PMDL mdl; | |
483 | NDIS_STATUS status; | |
484 | PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info; | |
485 | if (size == 0) { | |
486 | return NULL; | |
487 | } | |
488 | realSize = MEM_ALIGN_SIZE(size + headRoom); | |
489 | ||
490 | mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, realSize); | |
491 | if (mdl == NULL) { | |
492 | return NULL; | |
493 | } | |
494 | ||
495 | nbl = NdisAllocateNetBufferAndNetBufferList(ovsPool->zeroSizePool, | |
496 | (UINT16)sizeof (OVS_BUFFER_CONTEXT), | |
497 | (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL, | |
498 | mdl, realSize, 0); | |
499 | if (nbl == NULL) { | |
500 | OvsFreeMDLAndData(mdl); | |
501 | return NULL; | |
502 | } | |
503 | ||
504 | nbl->SourceHandle = ovsPool->ndisHandle; | |
505 | status = context->NdisSwitchHandlers. | |
506 | AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl); | |
507 | ||
508 | if (status != NDIS_STATUS_SUCCESS) { | |
509 | /* | |
510 | * do we need to remove mdl from nbl XXX | |
511 | */ | |
512 | OvsFreeMDLAndData(mdl); | |
513 | NdisFreeNetBufferList(nbl); | |
514 | return NULL; | |
515 | } | |
516 | ||
517 | info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl); | |
518 | ASSERT(info); | |
519 | info->IsPacketDataSafe = TRUE; | |
520 | info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID; | |
521 | status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl), | |
522 | size, 0, NULL); | |
523 | ASSERT(status == NDIS_STATUS_SUCCESS); | |
524 | ||
525 | #ifdef DBG | |
526 | InterlockedIncrement((LONG volatile *)&ovsPool->zeroNBLCount); | |
527 | OvsDumpNetBufferList(nbl); | |
528 | OvsDumpForwardingDetails(nbl); | |
529 | #endif | |
530 | ||
531 | ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); | |
532 | ||
533 | OvsInitNBLContext(ctx, OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA | | |
534 | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | | |
535 | OVS_BUFFER_FROM_ZERO_SIZE_POOL, | |
12e888ba | 536 | size, OVS_DPPORT_NUMBER_INVALID); |
c803536e SS |
537 | |
538 | OVS_LOG_LOUD("Allocate variable size NBL: %p", nbl); | |
539 | return nbl; | |
540 | } | |
541 | ||
542 | ||
543 | /* | |
544 | * -------------------------------------------------------------------------- | |
545 | * OvsInitExternalNBLContext -- | |
546 | * | |
547 | * For NBL not allocated by OVS, it will allocate and initialize | |
548 | * the NBL context. | |
549 | * -------------------------------------------------------------------------- | |
550 | */ | |
551 | POVS_BUFFER_CONTEXT | |
552 | OvsInitExternalNBLContext(PVOID ovsContext, | |
553 | PNET_BUFFER_LIST nbl, | |
554 | BOOLEAN isRecv) | |
555 | { | |
556 | NDIS_HANDLE poolHandle; | |
557 | POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; | |
558 | POVS_BUFFER_CONTEXT ctx; | |
559 | PNET_BUFFER nb; | |
560 | NDIS_STATUS status; | |
561 | UINT16 flags; | |
562 | ||
563 | poolHandle = NdisGetPoolFromNetBufferList(nbl); | |
564 | ||
7552cf4b SV |
565 | if (poolHandle == context->ovsPool.ndisHandle || |
566 | nbl->SourceHandle == context->ovsPool.ndisHandle) { | |
c803536e SS |
567 | return (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); |
568 | } | |
569 | status = NdisAllocateNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT), | |
570 | OVS_DEFAULT_NBL_CONTEXT_FILL, | |
571 | OVS_OTHER_POOL_TAG); | |
572 | if (status != NDIS_STATUS_SUCCESS) { | |
573 | return NULL; | |
574 | } | |
575 | #ifdef DBG | |
576 | OvsDumpNBLContext(nbl); | |
577 | InterlockedIncrement((LONG volatile *)&context->ovsPool.sysNBLCount); | |
578 | #endif | |
579 | flags = isRecv ? OVS_BUFFER_RECV_BUFFER : OVS_BUFFER_SEND_BUFFER; | |
580 | flags |= OVS_BUFFER_NEED_COMPLETE | OVS_BUFFER_PRIVATE_CONTEXT; | |
581 | ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); | |
582 | ||
583 | nb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
584 | /* | |
585 | * we use first nb to decide whether we need advance or retreat during | |
586 | * complete. | |
587 | */ | |
12e888ba NR |
588 | OvsInitNBLContext(ctx, flags, NET_BUFFER_DATA_LENGTH(nb), |
589 | OVS_DPPORT_NUMBER_INVALID); | |
c803536e SS |
590 | return ctx; |
591 | } | |
592 | ||
593 | /* | |
594 | * -------------------------------------------------------------------------- | |
595 | * OvsAllocateNBLContext | |
596 | * | |
597 | * Create NBL buffer context and forwarding context. | |
598 | * -------------------------------------------------------------------------- | |
599 | */ | |
600 | NDIS_STATUS | |
601 | OvsAllocateNBLContext(POVS_SWITCH_CONTEXT context, | |
602 | PNET_BUFFER_LIST nbl) | |
603 | { | |
604 | POVS_NBL_POOL ovsPool = &context->ovsPool; | |
605 | NDIS_STATUS status; | |
606 | ||
607 | status = NdisAllocateNetBufferListContext(nbl, | |
608 | sizeof (OVS_BUFFER_CONTEXT), | |
609 | OVS_DEFAULT_NBL_CONTEXT_FILL, | |
610 | OVS_OTHER_POOL_TAG); | |
611 | if (status != NDIS_STATUS_SUCCESS) { | |
612 | return NDIS_STATUS_FAILURE; | |
613 | } | |
614 | ||
615 | nbl->SourceHandle = ovsPool->ndisHandle; | |
616 | status = context->NdisSwitchHandlers. | |
617 | AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl); | |
618 | ||
619 | if (status != NDIS_STATUS_SUCCESS) { | |
620 | NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT)); | |
621 | return NDIS_STATUS_FAILURE; | |
622 | } | |
623 | return status; | |
624 | } | |
625 | ||
626 | /* | |
627 | * -------------------------------------------------------------------------- | |
628 | * OvsFreeNBLContext | |
629 | * | |
630 | * Free the NBL buffer context and forwarding context. | |
631 | * -------------------------------------------------------------------------- | |
632 | */ | |
633 | NDIS_STATUS | |
634 | OvsFreeNBLContext(POVS_SWITCH_CONTEXT context, | |
635 | PNET_BUFFER_LIST nbl) | |
636 | { | |
637 | POVS_NBL_POOL ovsPool = &context->ovsPool; | |
638 | ||
639 | context->NdisSwitchHandlers. | |
640 | FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl); | |
641 | NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT)); | |
642 | ||
643 | return NDIS_STATUS_SUCCESS; | |
644 | } | |
645 | ||
646 | /* | |
647 | * -------------------------------------------------------------------------- | |
648 | * OvsCopyNBLInfo | |
649 | * | |
650 | * Copy NBL info from src to dst | |
651 | * -------------------------------------------------------------------------- | |
652 | */ | |
653 | NDIS_STATUS | |
654 | OvsCopyNBLInfo(PNET_BUFFER_LIST srcNbl, PNET_BUFFER_LIST dstNbl, | |
655 | POVS_BUFFER_CONTEXT srcCtx, UINT32 copySize, | |
656 | BOOLEAN copyNblInfo) | |
657 | { | |
658 | PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO srcInfo, dstInfo; | |
659 | NDIS_STATUS status = NDIS_STATUS_SUCCESS; | |
660 | ||
661 | srcInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(srcNbl); | |
662 | dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(dstNbl); | |
663 | if (srcInfo) { | |
664 | #ifdef OVS_USE_COPY_NET_BUFFER_LIST_INFO | |
665 | status = context->NdisSwitchHandlers. | |
666 | CopyNetBufferListInfo(ovsPool->ndisContext, dstNbl, srcNbl, 0); | |
667 | ||
668 | if (status != NDIS_STATUS_SUCCESS) { | |
669 | return status; | |
670 | } | |
671 | #else | |
672 | dstInfo->SourcePortId = srcInfo->SourcePortId; | |
673 | dstInfo->SourceNicIndex = srcInfo->SourceNicIndex; | |
674 | if (copyNblInfo) { | |
675 | if (srcCtx->flags & OVS_BUFFER_RECV_BUFFER) { | |
676 | NdisCopyReceiveNetBufferListInfo(dstNbl, srcNbl); | |
677 | } else if (srcCtx->flags & OVS_BUFFER_SEND_BUFFER) { | |
678 | NdisCopySendNetBufferListInfo(dstNbl, srcNbl); | |
679 | } | |
680 | } | |
681 | #endif | |
682 | dstInfo->IsPacketDataSafe = srcInfo->IsPacketDataSafe; | |
683 | if (!srcInfo->IsPacketDataSafe && copySize > | |
684 | srcInfo->SafePacketDataSize) { | |
685 | srcInfo->SafePacketDataSize = copySize; | |
686 | } | |
687 | } else { | |
688 | /* | |
689 | * Assume all data are safe | |
690 | */ | |
691 | dstInfo->IsPacketDataSafe = TRUE; | |
692 | dstInfo->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID; | |
693 | } | |
694 | return status; | |
695 | } | |
696 | ||
697 | /* | |
698 | * -------------------------------------------------------------------------- | |
699 | * OvsPartialCopyNBL -- | |
700 | * | |
701 | * Partial copy NBL, if there is multiple NB in NBL, each one will be | |
702 | * copied. We also reserve headroom for the new NBL. | |
703 | * | |
704 | * Please note, | |
705 | * NBL should have OVS_BUFFER_CONTEXT setup before calling | |
706 | * this function. | |
707 | * The NBL should already have ref to itself so that during copy | |
708 | * it will not be freed. | |
709 | * -------------------------------------------------------------------------- | |
710 | */ | |
711 | PNET_BUFFER_LIST | |
712 | OvsPartialCopyNBL(PVOID ovsContext, | |
713 | PNET_BUFFER_LIST nbl, | |
714 | UINT32 copySize, | |
715 | UINT32 headRoom, | |
716 | BOOLEAN copyNblInfo) | |
717 | { | |
718 | PNET_BUFFER_LIST newNbl; | |
719 | POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; | |
720 | NDIS_STATUS status; | |
721 | PNET_BUFFER srcNb, dstNb; | |
722 | ULONG byteCopied; | |
723 | POVS_NBL_POOL ovsPool = &context->ovsPool; | |
724 | POVS_BUFFER_CONTEXT srcCtx, dstCtx; | |
725 | UINT16 flags; | |
726 | ||
727 | srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); | |
728 | if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) { | |
729 | OVS_LOG_INFO("src nbl must have ctx initialized"); | |
730 | ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC); | |
731 | return NULL; | |
732 | } | |
733 | ||
734 | if (copySize) { | |
735 | NdisAdvanceNetBufferListDataStart(nbl, copySize, FALSE, NULL); | |
736 | } | |
737 | newNbl = NdisAllocateCloneNetBufferList(nbl, ovsPool->nblOnlyPool, | |
738 | NULL, 0); | |
739 | if (copySize) { | |
740 | status = NdisRetreatNetBufferListDataStart(nbl, copySize, 0, | |
741 | NULL, NULL); | |
742 | ASSERT(status == NDIS_STATUS_SUCCESS); | |
743 | } | |
744 | ||
745 | if (newNbl == NULL) { | |
746 | return NULL; | |
747 | } | |
748 | ||
749 | /* | |
750 | * Allocate private memory for copy | |
751 | */ | |
752 | if (copySize + headRoom) { | |
753 | status = NdisRetreatNetBufferListDataStart(newNbl, copySize + headRoom, | |
754 | 0, NULL, NULL); | |
755 | if (status != NDIS_STATUS_SUCCESS) { | |
756 | goto retreat_error; | |
757 | } | |
758 | ||
759 | if (headRoom) { | |
760 | NdisAdvanceNetBufferListDataStart(newNbl, headRoom, FALSE, NULL); | |
761 | } | |
762 | if (copySize) { | |
763 | srcNb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
764 | dstNb = NET_BUFFER_LIST_FIRST_NB(newNbl); | |
765 | ||
766 | while (srcNb) { | |
767 | status = NdisCopyFromNetBufferToNetBuffer(dstNb, 0, copySize, | |
768 | srcNb, 0, | |
769 | &byteCopied); | |
770 | if (status != NDIS_STATUS_SUCCESS || copySize != byteCopied) { | |
771 | goto nbl_context_error; | |
772 | } | |
773 | srcNb = NET_BUFFER_NEXT_NB(srcNb); | |
774 | dstNb = NET_BUFFER_NEXT_NB(dstNb); | |
775 | } | |
776 | } | |
777 | } | |
778 | ||
779 | status = OvsAllocateNBLContext(context, newNbl); | |
780 | if (status != NDIS_STATUS_SUCCESS) { | |
781 | goto nbl_context_error; | |
782 | } | |
783 | ||
784 | status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copySize, copyNblInfo); | |
785 | if (status != NDIS_STATUS_SUCCESS) { | |
786 | goto copy_list_info_error; | |
787 | } | |
788 | ||
789 | #ifdef DBG | |
790 | InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount); | |
791 | #endif | |
792 | ||
793 | newNbl->ParentNetBufferList = nbl; | |
794 | ||
795 | dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl); | |
796 | ASSERT(dstCtx != NULL); | |
797 | ||
798 | flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER); | |
799 | ||
800 | flags |= OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_CONTEXT | | |
801 | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT; | |
802 | ||
803 | srcNb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
804 | OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(srcNb) - copySize, | |
12e888ba | 805 | OVS_DPPORT_NUMBER_INVALID); |
c803536e SS |
806 | |
807 | InterlockedIncrement((LONG volatile *)&srcCtx->refCount); | |
7552cf4b | 808 | |
c803536e SS |
809 | #ifdef DBG |
810 | OvsDumpNetBufferList(nbl); | |
811 | OvsDumpForwardingDetails(nbl); | |
812 | ||
813 | OvsDumpNetBufferList(newNbl); | |
814 | OvsDumpForwardingDetails(newNbl); | |
815 | #endif | |
7552cf4b | 816 | |
c803536e SS |
817 | OVS_LOG_LOUD("Partial Copy new NBL: %p", newNbl); |
818 | return newNbl; | |
819 | ||
820 | copy_list_info_error: | |
821 | OvsFreeNBLContext(context, newNbl); | |
822 | nbl_context_error: | |
823 | if (copySize) { | |
824 | NdisAdvanceNetBufferListDataStart(newNbl, copySize, TRUE, NULL); | |
825 | } | |
826 | retreat_error: | |
827 | NdisFreeCloneNetBufferList(newNbl, 0); | |
828 | return NULL; | |
829 | } | |
830 | ||
831 | /* | |
832 | * -------------------------------------------------------------------------- | |
833 | * OvsPartialCopyToMultipleNBLs -- | |
834 | * | |
835 | * This is similar to OvsPartialCopyNBL() except that each NB will | |
836 | * have its own NBL. | |
837 | * -------------------------------------------------------------------------- | |
838 | */ | |
839 | PNET_BUFFER_LIST | |
840 | OvsPartialCopyToMultipleNBLs(PVOID ovsContext, | |
841 | PNET_BUFFER_LIST nbl, | |
842 | UINT32 copySize, | |
843 | UINT32 headRoom, | |
844 | BOOLEAN copyNblInfo) | |
845 | { | |
846 | PNET_BUFFER nb, nextNb = NULL, firstNb, prevNb; | |
847 | POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; | |
848 | PNET_BUFFER_LIST firstNbl = NULL, newNbl, prevNbl = NULL; | |
849 | ||
850 | nb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
851 | if (NET_BUFFER_NEXT_NB(nb) == NULL) { | |
852 | return OvsPartialCopyNBL(context, nbl, copySize, headRoom, copyNblInfo); | |
853 | } | |
854 | ||
855 | firstNb = nb; | |
856 | prevNb = nb; | |
857 | ||
858 | while (nb) { | |
859 | nextNb = NET_BUFFER_NEXT_NB(nb); | |
860 | NET_BUFFER_NEXT_NB(nb) = NULL; | |
861 | ||
862 | NET_BUFFER_LIST_FIRST_NB(nbl) = nb; | |
863 | ||
864 | newNbl = OvsPartialCopyNBL(context, nbl, copySize, headRoom, | |
865 | copyNblInfo); | |
866 | if (newNbl == NULL) { | |
867 | goto cleanup; | |
868 | } | |
869 | if (prevNbl == NULL) { | |
870 | firstNbl = newNbl; | |
871 | } else { | |
caa63627 | 872 | NET_BUFFER_LIST_NEXT_NBL(prevNbl) = newNbl; |
c803536e SS |
873 | NET_BUFFER_NEXT_NB(prevNb) = nb; |
874 | } | |
875 | prevNbl = newNbl; | |
876 | prevNb = nb; | |
877 | nb = nextNb; | |
878 | } | |
879 | NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb; | |
880 | return firstNbl; | |
881 | ||
882 | cleanup: | |
883 | NET_BUFFER_NEXT_NB(prevNb) = nb; | |
884 | NET_BUFFER_NEXT_NB(nb) = nextNb; | |
885 | NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb; | |
886 | ||
887 | newNbl = firstNbl; | |
888 | while (newNbl) { | |
889 | firstNbl = NET_BUFFER_LIST_NEXT_NBL(newNbl); | |
885648d9 | 890 | NET_BUFFER_LIST_NEXT_NBL(newNbl) = NULL; |
c803536e SS |
891 | OvsCompleteNBL(context, newNbl, TRUE); |
892 | newNbl = firstNbl; | |
893 | } | |
894 | return NULL; | |
895 | } | |
896 | ||
897 | ||
898 | static PNET_BUFFER_LIST | |
899 | OvsCopySinglePacketNBL(PVOID ovsContext, | |
900 | PNET_BUFFER_LIST nbl, | |
901 | PNET_BUFFER nb, | |
902 | UINT32 headRoom, | |
903 | BOOLEAN copyNblInfo) | |
904 | { | |
905 | UINT32 size; | |
906 | ULONG copiedSize; | |
907 | POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; | |
908 | PNET_BUFFER_LIST newNbl; | |
909 | PNET_BUFFER newNb; | |
910 | NDIS_STATUS status; | |
911 | POVS_BUFFER_CONTEXT srcCtx, dstCtx; | |
912 | ||
913 | size = NET_BUFFER_DATA_LENGTH(nb); | |
914 | if ((size + headRoom) <= OVS_FIX_NBL_DATA_SIZE) { | |
915 | newNbl = OvsAllocateFixSizeNBL(context, size, headRoom); | |
916 | } else { | |
917 | newNbl = OvsAllocateVariableSizeNBL(context, size, headRoom); | |
918 | } | |
919 | if (newNbl == NULL) { | |
920 | return NULL; | |
921 | } | |
922 | newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); | |
923 | status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0, | |
924 | &copiedSize); | |
925 | ||
926 | srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); | |
927 | if (status == NDIS_STATUS_SUCCESS) { | |
928 | status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copiedSize, copyNblInfo); | |
929 | } | |
930 | ||
931 | if (status != NDIS_STATUS_SUCCESS || copiedSize != size) { | |
932 | OvsCompleteNBL(context, newNbl, TRUE); | |
933 | return NULL; | |
934 | } | |
935 | ||
936 | dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl); | |
937 | ASSERT(dstCtx && srcCtx); | |
938 | ASSERT(srcCtx->magic == OVS_CTX_MAGIC && dstCtx->magic == OVS_CTX_MAGIC); | |
939 | ||
940 | dstCtx->flags |= srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | | |
941 | OVS_BUFFER_SEND_BUFFER); | |
942 | #ifdef DBG | |
943 | OvsDumpNetBufferList(newNbl); | |
944 | OvsDumpForwardingDetails(newNbl); | |
945 | #endif | |
946 | OVS_LOG_LOUD("Copy single nb to new NBL: %p", newNbl); | |
947 | return newNbl; | |
948 | } | |
949 | ||
950 | /* | |
951 | * -------------------------------------------------------------------------- | |
952 | * OvsFullCopyNBL -- | |
953 | * | |
954 | * Copy the NBL to a new NBL including data. | |
955 | * | |
956 | * Notes: | |
957 | * The NBL can have multiple NBs, but the final result is one NBL. | |
958 | * -------------------------------------------------------------------------- | |
959 | */ | |
960 | PNET_BUFFER_LIST | |
961 | OvsFullCopyNBL(PVOID ovsContext, | |
962 | PNET_BUFFER_LIST nbl, | |
963 | UINT32 headRoom, | |
964 | BOOLEAN copyNblInfo) | |
965 | { | |
966 | POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; | |
967 | POVS_NBL_POOL ovsPool = &context->ovsPool; | |
968 | PNET_BUFFER_LIST newNbl; | |
969 | PNET_BUFFER nb, newNb, firstNb = NULL, prevNb = NULL; | |
970 | POVS_BUFFER_CONTEXT dstCtx, srcCtx; | |
971 | PMDL mdl; | |
972 | NDIS_STATUS status; | |
973 | UINT32 size, totalSize; | |
974 | ULONG copiedSize; | |
975 | UINT16 flags; | |
976 | PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo; | |
977 | ||
978 | srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); | |
979 | if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) { | |
980 | OVS_LOG_INFO("src nbl must have ctx initialized"); | |
981 | ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC); | |
982 | return NULL; | |
983 | } | |
984 | ||
985 | nb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
986 | ||
987 | if (NET_BUFFER_NEXT_NB(nb) == NULL) { | |
988 | return OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo); | |
989 | } | |
990 | ||
991 | newNbl = NdisAllocateNetBufferList(ovsPool->nblOnlyPool, | |
992 | (UINT16)sizeof (OVS_BUFFER_CONTEXT), | |
993 | (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL); | |
994 | if (newNbl == NULL) { | |
995 | return NULL; | |
996 | } | |
997 | ||
998 | while (nb) { | |
999 | size = NET_BUFFER_DATA_LENGTH(nb); | |
1000 | totalSize = MEM_ALIGN_SIZE(size + headRoom); | |
1001 | mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, totalSize); | |
1002 | ||
1003 | if (mdl == NULL) { | |
1004 | goto nblcopy_error; | |
1005 | } | |
1006 | newNb = NdisAllocateNetBuffer(ovsPool->nbPool, mdl, totalSize, 0); | |
1007 | if (newNb == NULL) { | |
1008 | OvsFreeMDLAndData(mdl); | |
1009 | goto nblcopy_error; | |
1010 | } | |
1011 | if (firstNb == NULL) { | |
1012 | firstNb = newNb; | |
1013 | } else { | |
1014 | NET_BUFFER_NEXT_NB(prevNb) = newNb; | |
1015 | } | |
1016 | prevNb = newNb; | |
1017 | #ifdef DBG | |
1018 | InterlockedIncrement((LONG volatile *)&ovsPool->nbCount); | |
1019 | #endif | |
1020 | status = NdisRetreatNetBufferDataStart(newNb, size, 0, NULL); | |
1021 | ASSERT(status == NDIS_STATUS_SUCCESS); | |
1022 | ||
1023 | status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0, | |
1024 | &copiedSize); | |
1025 | if (status != NDIS_STATUS_SUCCESS || size != copiedSize) { | |
1026 | goto nblcopy_error; | |
1027 | } | |
1028 | ||
1029 | nb = NET_BUFFER_NEXT_NB(nb); | |
1030 | } | |
1031 | ||
1032 | NET_BUFFER_LIST_FIRST_NB(newNbl) = firstNb; | |
1033 | ||
1034 | newNbl->SourceHandle = ovsPool->ndisHandle; | |
1035 | status = context->NdisSwitchHandlers. | |
1036 | AllocateNetBufferListForwardingContext(ovsPool->ndisContext, newNbl); | |
1037 | ||
1038 | if (status != NDIS_STATUS_SUCCESS) { | |
1039 | goto nblcopy_error; | |
1040 | } | |
1041 | ||
1042 | status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, 0, copyNblInfo); | |
1043 | if (status != NDIS_STATUS_SUCCESS) { | |
1044 | goto nblcopy_error; | |
1045 | } | |
1046 | ||
1047 | dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl); | |
1048 | dstInfo->IsPacketDataSafe = TRUE; | |
1049 | ||
1050 | dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl); | |
1051 | ||
1052 | flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER); | |
1053 | ||
1054 | flags |= OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA | | |
1055 | OVS_BUFFER_PRIVATE_NET_BUFFER | OVS_BUFFER_FROM_NBL_ONLY_POOL | | |
1056 | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT; | |
1057 | ||
1058 | OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(firstNb), | |
12e888ba | 1059 | OVS_DPPORT_NUMBER_INVALID); |
c803536e SS |
1060 | |
1061 | #ifdef DBG | |
1062 | OvsDumpNetBufferList(nbl); | |
1063 | OvsDumpForwardingDetails(nbl); | |
1064 | InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount); | |
1065 | #endif | |
1066 | OVS_LOG_LOUD("newNbl: %p", newNbl); | |
1067 | return newNbl; | |
1068 | ||
1069 | nblcopy_error: | |
1070 | while (firstNb) { | |
1071 | #ifdef DBG | |
1072 | InterlockedDecrement((LONG volatile *)&ovsPool->nbCount); | |
1073 | #endif | |
1074 | prevNb = firstNb; | |
1075 | firstNb = NET_BUFFER_NEXT_NB(prevNb); | |
1076 | mdl = NET_BUFFER_FIRST_MDL(prevNb); | |
1077 | NET_BUFFER_FIRST_MDL(prevNb) = NULL; | |
1078 | NdisFreeNetBuffer(prevNb); | |
1079 | OvsFreeMDLAndData(mdl); | |
1080 | } | |
1081 | NdisFreeNetBufferList(newNbl); | |
1082 | OVS_LOG_ERROR("OvsFullCopyNBL failed"); | |
1083 | return NULL; | |
1084 | } | |
1085 | ||
1086 | /* | |
1087 | * -------------------------------------------------------------------------- | |
1088 | * GetSegmentHeaderInfo | |
1089 | * | |
1090 | * Extract header size and sequence number for the segment. | |
1091 | * -------------------------------------------------------------------------- | |
1092 | */ | |
1093 | static NDIS_STATUS | |
1094 | GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl, | |
1095 | const POVS_PACKET_HDR_INFO hdrInfo, | |
1096 | UINT32 *hdrSize, UINT32 *seqNumber) | |
1097 | { | |
1098 | TCPHdr tcpStorage; | |
1099 | const TCPHdr *tcp; | |
1100 | ||
1101 | /* Parse the orginal Eth/IP/TCP header */ | |
1102 | tcp = OvsGetPacketBytes(nbl, sizeof *tcp, hdrInfo->l4Offset, &tcpStorage); | |
1103 | if (tcp == NULL) { | |
1104 | return NDIS_STATUS_FAILURE; | |
1105 | } | |
1106 | *seqNumber = ntohl(tcp->seq); | |
1107 | *hdrSize = hdrInfo->l4Offset + TCP_HDR_LEN(tcp); | |
1108 | ||
1109 | return NDIS_STATUS_SUCCESS; | |
1110 | } | |
1111 | ||
1112 | ||
1113 | /* | |
1114 | * -------------------------------------------------------------------------- | |
1115 | * FixSegmentHeader | |
1116 | * | |
1117 | * Fix IP length, IP checksum, TCP sequence number and TCP checksum | |
1118 | * in the segment. | |
1119 | * -------------------------------------------------------------------------- | |
1120 | */ | |
1121 | static NDIS_STATUS | |
89d762f3 AS |
1122 | FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber, |
1123 | BOOLEAN lastPacket, UINT16 packetCounter) | |
c803536e | 1124 | { |
884d541f SV |
1125 | EthHdr *dstEth = NULL; |
1126 | TCPHdr *dstTCP = NULL; | |
1127 | PMDL mdl = NULL; | |
1128 | PUINT8 bufferStart = NULL; | |
c803536e SS |
1129 | |
1130 | mdl = NET_BUFFER_FIRST_MDL(nb); | |
1131 | ||
1132 | bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(mdl, LowPagePriority); | |
1133 | if (!bufferStart) { | |
1134 | return NDIS_STATUS_RESOURCES; | |
1135 | } | |
1136 | dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb)); | |
89d762f3 | 1137 | |
884d541f SV |
1138 | switch (dstEth->Type) { |
1139 | case ETH_TYPE_IPV4_NBO: | |
1140 | { | |
1141 | IPHdr *dstIP = NULL; | |
1142 | ||
1143 | ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) | |
1144 | >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr)); | |
1145 | dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth)); | |
1146 | dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4); | |
1147 | ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) | |
1148 | >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP)); | |
1149 | ||
1150 | /* Fix IP length and checksum */ | |
1151 | ASSERT(dstIP->protocol == IPPROTO_TCP); | |
1152 | dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP)); | |
1153 | dstIP->id += packetCounter; | |
1154 | dstIP->check = 0; | |
1155 | dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0); | |
1156 | dstTCP->seq = htonl(seqNumber); | |
1157 | ||
1158 | /* | |
1159 | * Set the TCP FIN and PSH bit only for the last packet | |
1160 | * More information can be found under: | |
1161 | * https://msdn.microsoft.com/en-us/library/windows/hardware/ff568840%28v=vs.85%29.aspx | |
1162 | */ | |
1163 | if (dstTCP->fin) { | |
1164 | dstTCP->fin = lastPacket; | |
1165 | } | |
1166 | if (dstTCP->psh) { | |
1167 | dstTCP->psh = lastPacket; | |
1168 | } | |
1169 | UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP); | |
1170 | dstTCP->check = IPPseudoChecksum(&dstIP->saddr, | |
1171 | &dstIP->daddr, | |
1172 | IPPROTO_TCP, | |
1173 | csumLength); | |
1174 | dstTCP->check = CalculateChecksumNB(nb, | |
1175 | csumLength, | |
1176 | sizeof(*dstEth) + dstIP->ihl * 4); | |
1177 | break; | |
89d762f3 | 1178 | } |
884d541f SV |
1179 | case ETH_TYPE_IPV6_NBO: |
1180 | { | |
1181 | IPv6Hdr *dstIP = NULL; | |
1182 | ||
1183 | ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) | |
1184 | >= sizeof(EthHdr) + sizeof(IPv6Hdr) + sizeof(TCPHdr)); | |
1185 | dstIP = (IPv6Hdr *)((PCHAR)dstEth + sizeof(*dstEth)); | |
1186 | dstTCP = (TCPHdr *)((PCHAR)dstIP + sizeof(IPv6Hdr)); | |
1187 | ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) | |
1188 | >= sizeof(EthHdr) + sizeof(IPv6Hdr) + TCP_HDR_LEN(dstTCP)); | |
1189 | ||
1190 | /* Fix IP length */ | |
1191 | ASSERT(dstIP->nexthdr == IPPROTO_TCP); | |
1192 | dstIP->payload_len = htons(segmentSize + sizeof(IPv6Hdr) + TCP_HDR_LEN(dstTCP)); | |
1193 | ||
1194 | dstTCP->seq = htonl(seqNumber); | |
1195 | if (dstTCP->fin) { | |
1196 | dstTCP->fin = lastPacket; | |
1197 | } | |
1198 | if (dstTCP->psh) { | |
1199 | dstTCP->psh = lastPacket; | |
1200 | } | |
89d762f3 | 1201 | |
884d541f SV |
1202 | UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP); |
1203 | dstTCP->check = IPv6PseudoChecksum((UINT32*)&dstIP->saddr, | |
1204 | (UINT32*)&dstIP->daddr, | |
1205 | IPPROTO_TCP, | |
1206 | csumLength); | |
1207 | dstTCP->check = CalculateChecksumNB(nb, | |
1208 | csumLength, | |
1209 | sizeof(*dstEth) + sizeof(IPv6Hdr)); | |
1210 | break; | |
1211 | } | |
1212 | default: | |
1213 | OVS_LOG_ERROR("Invalid eth type: %d\n", dstEth->Type); | |
1214 | ASSERT(! "Invalid eth type"); | |
1215 | } | |
89d762f3 | 1216 | |
c803536e SS |
1217 | return STATUS_SUCCESS; |
1218 | } | |
1219 | ||
1220 | /* | |
1221 | * -------------------------------------------------------------------------- | |
1222 | * OvsTcpSegmentyNBL -- | |
1223 | * | |
1224 | * Segment TCP payload, and prepend each segment with ether/IP/TCP header. | |
1225 | * Leave headRoom for additional encap. | |
1226 | * | |
1227 | * Please note, | |
1228 | * NBL should have OVS_BUFFER_CONTEXT setup before calling | |
1229 | * this function. | |
1230 | * The NBL should already have ref to itself so that during copy | |
1231 | * it will not be freed. | |
1232 | * Currently this API assert there is only one NB in an NBL, it needs | |
1233 | * to be fixed if we receive multiple NBs in an NBL. | |
1234 | * -------------------------------------------------------------------------- | |
1235 | */ | |
1236 | PNET_BUFFER_LIST | |
1237 | OvsTcpSegmentNBL(PVOID ovsContext, | |
1238 | PNET_BUFFER_LIST nbl, | |
1239 | POVS_PACKET_HDR_INFO hdrInfo, | |
1240 | UINT32 mss, | |
1241 | UINT32 headRoom) | |
1242 | { | |
1243 | POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; | |
1244 | #ifdef DBG | |
1245 | POVS_NBL_POOL ovsPool = &context->ovsPool; | |
1246 | #endif | |
1247 | POVS_BUFFER_CONTEXT dstCtx, srcCtx; | |
1248 | UINT32 size, hdrSize, seqNumber; | |
1249 | PNET_BUFFER_LIST newNbl; | |
1250 | PNET_BUFFER nb, newNb; | |
1251 | NDIS_STATUS status; | |
1252 | UINT16 segmentSize; | |
1253 | ULONG copiedSize; | |
89d762f3 | 1254 | UINT16 packetCounter = 0; |
c803536e SS |
1255 | |
1256 | srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); | |
1257 | if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) { | |
1258 | OVS_LOG_INFO("src nbl must have ctx initialized"); | |
1259 | ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC); | |
1260 | return NULL; | |
1261 | } | |
1262 | ||
1263 | nb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
1264 | ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL); | |
1265 | ||
1266 | /* Figure out the segment header size */ | |
1267 | status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber); | |
1268 | if (status != NDIS_STATUS_SUCCESS) { | |
1269 | OVS_LOG_INFO("Cannot parse NBL header"); | |
1270 | return NULL; | |
1271 | } | |
1272 | ||
1273 | size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize; | |
1274 | ||
1275 | /* XXX add to ovsPool counters? */ | |
1276 | newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL, | |
1277 | NULL, hdrSize, mss, hdrSize + headRoom , 0, 0); | |
1278 | if (newNbl == NULL) { | |
1279 | return NULL; | |
1280 | } | |
1281 | ||
1282 | /* Now deal with TCP payload */ | |
1283 | for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL; | |
1284 | newNb = NET_BUFFER_NEXT_NB(newNb)) { | |
1285 | segmentSize = (size > mss ? mss : size) & 0xffff; | |
1286 | if (headRoom) { | |
1287 | NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL); | |
1288 | } | |
1289 | ||
1290 | /* Now copy the eth/IP/TCP header and fix up */ | |
1291 | status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize, nb, 0, | |
1292 | &copiedSize); | |
1293 | if (status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize) { | |
1294 | goto nblcopy_error; | |
1295 | } | |
1296 | ||
89d762f3 AS |
1297 | status = FixSegmentHeader(newNb, segmentSize, seqNumber, |
1298 | NET_BUFFER_NEXT_NB(newNb) == NULL, | |
1299 | packetCounter); | |
c803536e SS |
1300 | if (status != NDIS_STATUS_SUCCESS) { |
1301 | goto nblcopy_error; | |
1302 | } | |
1303 | ||
1304 | ||
1305 | /* Move on to the next segment */ | |
1306 | size -= segmentSize; | |
1307 | seqNumber += segmentSize; | |
89d762f3 | 1308 | packetCounter++; |
c803536e SS |
1309 | } |
1310 | ||
1311 | status = OvsAllocateNBLContext(context, newNbl); | |
1312 | if (status != NDIS_STATUS_SUCCESS) { | |
1313 | goto nblcopy_error; | |
1314 | } | |
1315 | ||
1316 | status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, hdrSize + headRoom, FALSE); | |
1317 | if (status != NDIS_STATUS_SUCCESS) { | |
1318 | goto nbl_context_error; | |
1319 | } | |
1320 | ||
1321 | newNbl->ParentNetBufferList = nbl; | |
1322 | ||
1323 | /* Remember it's a fragment NBL so we can free it properly */ | |
1324 | dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl); | |
1325 | ASSERT(dstCtx != NULL); | |
1326 | dstCtx->flags = OVS_BUFFER_FRAGMENT | OVS_BUFFER_PRIVATE_CONTEXT | | |
1327 | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | OVS_BUFFER_SEND_BUFFER; | |
1328 | dstCtx->refCount = 1; | |
1329 | dstCtx->magic = OVS_CTX_MAGIC; | |
1330 | dstCtx->dataOffsetDelta = hdrSize + headRoom; | |
1331 | ||
1332 | InterlockedIncrement((LONG volatile *)&srcCtx->refCount); | |
1333 | #ifdef DBG | |
1334 | InterlockedIncrement((LONG volatile *)&ovsPool->fragNBLCount); | |
1335 | ||
1336 | OvsDumpNetBufferList(nbl); | |
1337 | OvsDumpForwardingDetails(nbl); | |
1338 | ||
1339 | OvsDumpNetBufferList(newNbl); | |
1340 | OvsDumpForwardingDetails(newNbl); | |
1341 | #endif | |
1342 | OVS_LOG_TRACE("Segment nbl %p to newNbl: %p", nbl, newNbl); | |
1343 | return newNbl; | |
1344 | ||
1345 | nbl_context_error: | |
1346 | OvsFreeNBLContext(context, newNbl); | |
1347 | nblcopy_error: | |
1348 | #ifdef DBG | |
1349 | InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount); | |
1350 | #endif | |
1351 | NdisFreeFragmentNetBufferList(newNbl, hdrSize + headRoom, 0); | |
1352 | return NULL; | |
1353 | } | |
1354 | ||
9a80ee14 SV |
1355 | /* |
1356 | * -------------------------------------------------------------------------- | |
1357 | * OvsAllocateNBLFromBuffer -- | |
1358 | * | |
1359 | * This function allocates all the stuff necessary for creating an NBL from the | |
1360 | * input buffer of specified length, namely, a nonpaged data buffer of size | |
1361 | * length, an MDL from it, and a NB and NBL from it. It does not allocate an NBL | |
1362 | * context yet. It also copies data from the specified buffer to the NBL. | |
1363 | * -------------------------------------------------------------------------- | |
1364 | */ | |
1365 | PNET_BUFFER_LIST | |
1366 | OvsAllocateNBLFromBuffer(PVOID context, | |
1367 | PVOID buffer, | |
1368 | ULONG length) | |
1369 | { | |
1370 | POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)context; | |
1371 | UINT8 *data = NULL; | |
1372 | PNET_BUFFER_LIST nbl = NULL; | |
1373 | PNET_BUFFER nb; | |
1374 | PMDL mdl; | |
1375 | ||
1376 | if (length > OVS_DEFAULT_DATA_SIZE) { | |
1377 | nbl = OvsAllocateVariableSizeNBL(switchContext, length, | |
1378 | OVS_DEFAULT_HEADROOM_SIZE); | |
1379 | ||
1380 | } else { | |
1381 | nbl = OvsAllocateFixSizeNBL(switchContext, length, | |
1382 | OVS_DEFAULT_HEADROOM_SIZE); | |
1383 | } | |
1384 | if (nbl == NULL) { | |
1385 | return NULL; | |
1386 | } | |
1387 | ||
1388 | nb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
1389 | mdl = NET_BUFFER_CURRENT_MDL(nb); | |
1390 | data = (PUINT8)MmGetSystemAddressForMdlSafe(mdl, LowPagePriority) + | |
1391 | NET_BUFFER_CURRENT_MDL_OFFSET(nb); | |
1392 | if (!data) { | |
1393 | OvsCompleteNBL(switchContext, nbl, TRUE); | |
1394 | return NULL; | |
1395 | } | |
1396 | ||
1397 | NdisMoveMemory(data, buffer, length); | |
1398 | ||
1399 | return nbl; | |
1400 | } | |
c803536e SS |
1401 | |
1402 | /* | |
1403 | * -------------------------------------------------------------------------- | |
1404 | * OvsFullCopyToMultipleNBLs -- | |
1405 | * | |
1406 | * Copy NBL to multiple NBLs, each NB will have its own NBL | |
1407 | * -------------------------------------------------------------------------- | |
1408 | */ | |
1409 | PNET_BUFFER_LIST | |
1410 | OvsFullCopyToMultipleNBLs(PVOID ovsContext, | |
1411 | PNET_BUFFER_LIST nbl, | |
1412 | UINT32 headRoom, | |
1413 | BOOLEAN copyNblInfo) | |
1414 | { | |
1415 | ||
1416 | POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext; | |
1417 | PNET_BUFFER_LIST firstNbl, currNbl, newNbl; | |
1418 | PNET_BUFFER nb; | |
1419 | POVS_BUFFER_CONTEXT srcCtx; | |
1420 | ||
1421 | srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); | |
1422 | if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) { | |
1423 | OVS_LOG_INFO("src nbl must have ctx initialized"); | |
1424 | ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC); | |
1425 | return NULL; | |
1426 | } | |
1427 | ||
1428 | nb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
1429 | newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo); | |
1430 | ||
1431 | if (newNbl == NULL || NET_BUFFER_NEXT_NB(nb) == NULL) { | |
1432 | return newNbl; | |
1433 | } else { | |
1434 | firstNbl = newNbl; | |
1435 | currNbl = newNbl; | |
1436 | } | |
1437 | ||
1438 | while (nb) { | |
1439 | newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom, | |
1440 | copyNblInfo); | |
1441 | if (newNbl == NULL) { | |
1442 | goto copymultiple_error; | |
1443 | } | |
1444 | NET_BUFFER_LIST_NEXT_NBL(currNbl) = newNbl; | |
1445 | currNbl = newNbl; | |
1446 | nb = NET_BUFFER_NEXT_NB(nb); | |
1447 | } | |
1448 | return firstNbl; | |
1449 | ||
1450 | copymultiple_error: | |
1451 | while (firstNbl) { | |
1452 | currNbl = firstNbl; | |
1453 | firstNbl = NET_BUFFER_LIST_NEXT_NBL(firstNbl); | |
1454 | NET_BUFFER_LIST_NEXT_NBL(currNbl) = NULL; | |
1455 | OvsCompleteNBL(context, currNbl, TRUE); | |
1456 | } | |
1457 | return NULL; | |
1458 | ||
1459 | } | |
1460 | ||
1461 | ||
1462 | /* | |
1463 | * -------------------------------------------------------------------------- | |
1464 | * OvsCompleteNBL -- | |
1465 | * | |
1466 | * This function tries to free the NBL allocated by OVS buffer | |
1467 | * management module. If it trigger the completion of the parent | |
1468 | * NBL, it will recursively call itself. If it trigger the completion | |
1469 | * of external NBL, it will be returned to the caller. The caller | |
1470 | * is responsible to call API to return to upper layer. | |
1471 | * -------------------------------------------------------------------------- | |
1472 | */ | |
1473 | PNET_BUFFER_LIST | |
1474 | OvsCompleteNBL(POVS_SWITCH_CONTEXT context, | |
1475 | PNET_BUFFER_LIST nbl, | |
1476 | BOOLEAN updateRef) | |
1477 | { | |
1478 | POVS_BUFFER_CONTEXT ctx; | |
1479 | UINT16 flags; | |
1480 | PNET_BUFFER_LIST parent; | |
1481 | NDIS_STATUS status; | |
1482 | NDIS_HANDLE poolHandle; | |
1483 | LONG value; | |
1484 | POVS_NBL_POOL ovsPool = &context->ovsPool; | |
1485 | PNET_BUFFER nb; | |
1486 | ||
1487 | ||
1488 | ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); | |
1489 | ||
1490 | ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC); | |
1491 | ||
1492 | OVS_LOG_TRACE("Enter: nbl: %p, ctx: %p, refCount: %d, updateRef:%d", | |
1493 | nbl, ctx, ctx->refCount, updateRef); | |
1494 | ||
1495 | if (updateRef) { | |
1496 | value = InterlockedDecrement((LONG volatile *)&ctx->refCount); | |
1497 | if (value != 0) { | |
1498 | return NULL; | |
1499 | } | |
1500 | } else { | |
1501 | /* | |
1502 | * This is a special case, the refCount must be zero | |
1503 | */ | |
1504 | ASSERT(ctx->refCount == 0); | |
1505 | } | |
1506 | ||
1507 | nb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
1508 | ||
1509 | flags = ctx->flags; | |
1510 | if (!(flags & OVS_BUFFER_FRAGMENT) && | |
1511 | NET_BUFFER_DATA_LENGTH(nb) != ctx->origDataLength) { | |
1512 | UINT32 diff; | |
1513 | if (NET_BUFFER_DATA_LENGTH(nb) < ctx->origDataLength) { | |
1514 | diff = ctx->origDataLength -NET_BUFFER_DATA_LENGTH(nb); | |
1515 | status = NdisRetreatNetBufferListDataStart(nbl, diff, 0, | |
1516 | NULL, NULL); | |
1517 | ASSERT(status == NDIS_STATUS_SUCCESS); | |
1518 | } else { | |
1519 | diff = NET_BUFFER_DATA_LENGTH(nb) - ctx->origDataLength; | |
1520 | NdisAdvanceNetBufferListDataStart(nbl, diff, TRUE, NULL); | |
1521 | } | |
1522 | } | |
1523 | ||
1524 | if (ctx->flags & OVS_BUFFER_PRIVATE_CONTEXT) { | |
1525 | NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT)); | |
1526 | } | |
1527 | ||
1528 | if (flags & OVS_BUFFER_NEED_COMPLETE) { | |
1529 | /* | |
1530 | * return to caller for completion | |
1531 | */ | |
1532 | #ifdef DBG | |
1533 | InterlockedDecrement((LONG volatile *)&ovsPool->sysNBLCount); | |
1534 | #endif | |
1535 | return nbl; | |
1536 | } | |
1537 | ||
1538 | if (flags & OVS_BUFFER_PRIVATE_FORWARD_CONTEXT) { | |
1539 | context->NdisSwitchHandlers. | |
1540 | FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl); | |
1541 | } | |
1542 | ||
1543 | if (flags & (OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA)) { | |
1544 | PNET_BUFFER nb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
1545 | while (nb) { | |
1546 | PMDL mdl = NET_BUFFER_FIRST_MDL(nb); | |
1547 | NET_BUFFER_FIRST_MDL(nb) = NULL; | |
1548 | ASSERT(mdl->Next == NULL); | |
1549 | OvsFreeMDLAndData(mdl); | |
1550 | nb = NET_BUFFER_NEXT_NB(nb); | |
1551 | } | |
1552 | } | |
1553 | ||
1554 | if (flags & OVS_BUFFER_PRIVATE_NET_BUFFER) { | |
1555 | PNET_BUFFER nb, nextNb; | |
1556 | ||
1557 | nb = NET_BUFFER_LIST_FIRST_NB(nbl); | |
1558 | while (nb) { | |
1559 | nextNb = NET_BUFFER_NEXT_NB(nb); | |
1560 | NdisFreeNetBuffer(nb); | |
1561 | #ifdef DBG | |
1562 | InterlockedDecrement((LONG volatile *)&ovsPool->nbCount); | |
1563 | #endif | |
1564 | nb = nextNb; | |
1565 | } | |
1566 | NET_BUFFER_LIST_FIRST_NB(nbl) = NULL; | |
1567 | } | |
1568 | ||
1569 | parent = nbl->ParentNetBufferList; | |
1570 | ||
1571 | poolHandle = NdisGetPoolFromNetBufferList(nbl); | |
1572 | if (flags & OVS_BUFFER_FROM_FIX_SIZE_POOL) { | |
1573 | ASSERT(poolHandle == ovsPool->fixSizePool); | |
1574 | #ifdef DBG | |
1575 | InterlockedDecrement((LONG volatile *)&ovsPool->fixNBLCount); | |
1576 | #endif | |
1577 | NdisFreeNetBufferList(nbl); | |
1578 | } else if (flags & OVS_BUFFER_FROM_ZERO_SIZE_POOL) { | |
1579 | ASSERT(poolHandle == ovsPool->zeroSizePool); | |
1580 | #ifdef DBG | |
1581 | InterlockedDecrement((LONG volatile *)&ovsPool->zeroNBLCount); | |
1582 | #endif | |
1583 | NdisFreeNetBufferList(nbl); | |
1584 | } else if (flags & OVS_BUFFER_FROM_NBL_ONLY_POOL) { | |
1585 | ASSERT(poolHandle == ovsPool->nblOnlyPool); | |
1586 | #ifdef DBG | |
1587 | InterlockedDecrement((LONG volatile *)&ovsPool->nblOnlyCount); | |
1588 | #endif | |
1589 | NdisFreeCloneNetBufferList(nbl, 0); | |
1590 | } else if (flags & OVS_BUFFER_FRAGMENT) { | |
1591 | OVS_LOG_TRACE("Free fragment %p parent %p", nbl, parent); | |
1592 | #ifdef DBG | |
1593 | InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount); | |
1594 | #endif | |
1595 | NdisFreeFragmentNetBufferList(nbl, ctx->dataOffsetDelta, 0); | |
1596 | } | |
1597 | ||
1598 | if (parent != NULL) { | |
1599 | ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(parent); | |
1600 | ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC); | |
1601 | value = InterlockedDecrement((LONG volatile *)&ctx->refCount); | |
1602 | if (value == 0) { | |
1603 | return OvsCompleteNBL(context, parent, FALSE); | |
1604 | } | |
1605 | } | |
1606 | return NULL; | |
1607 | } | |
1608 | ||
1609 | /* | |
1610 | * -------------------------------------------------------------------------- | |
1611 | * OvsSetCtxSourcePortNo -- | |
1612 | * Setter function which stores the source port of an NBL in the NBL | |
1613 | * Context Info. | |
1614 | * -------------------------------------------------------------------------- | |
1615 | */ | |
1616 | NDIS_STATUS | |
1617 | OvsSetCtxSourcePortNo(PNET_BUFFER_LIST nbl, | |
1618 | UINT32 portNo) | |
1619 | { | |
1620 | POVS_BUFFER_CONTEXT ctx; | |
1621 | ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); | |
1622 | if (ctx == NULL) { | |
1623 | ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC); | |
1624 | return STATUS_INVALID_PARAMETER; | |
1625 | } | |
1626 | ||
1627 | ctx->srcPortNo = portNo; | |
1628 | return NDIS_STATUS_SUCCESS; | |
1629 | } | |
1630 | ||
1631 | /* | |
1632 | * -------------------------------------------------------------------------- | |
1633 | * OvsGetCtxSourcePortNo -- | |
1634 | * Get source port of an NBL from its Context Info. | |
1635 | * -------------------------------------------------------------------------- | |
1636 | */ | |
1637 | NDIS_STATUS | |
1638 | OvsGetCtxSourcePortNo(PNET_BUFFER_LIST nbl, | |
1639 | UINT32 *portNo) | |
1640 | { | |
1641 | POVS_BUFFER_CONTEXT ctx; | |
1642 | ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl); | |
1643 | if (ctx == NULL || portNo == NULL) { | |
1644 | ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC); | |
1645 | return STATUS_INVALID_PARAMETER; | |
1646 | } | |
1647 | *portNo = ctx->srcPortNo; | |
1648 | return NDIS_STATUS_SUCCESS; | |
1649 | } |