]> git.proxmox.com Git - mirror_ovs.git/blob - datapath-windows/ovsext/BufferMgmt.c
448cd7652b2574f96ff95ddd35b4a831f33bae3c
[mirror_ovs.git] / datapath-windows / ovsext / BufferMgmt.c
1 /*
2 * Copyright (c) 2014, 2016 VMware, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * ****************************************************************************
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"
80 #include "Debug.h"
81 #include "Flow.h"
82 #include "Offload.h"
83 #include "NetProto.h"
84 #include "PacketParser.h"
85 #include "Switch.h"
86 #include "Vport.h"
87
88 #ifdef OVS_DBG_MOD
89 #undef OVS_DBG_MOD
90 #endif
91 #define OVS_DBG_MOD OVS_DBG_BUFMGMT
92
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 ctx->mru = 0;
270 }
271
272
273 static VOID
274 OvsDumpForwardingDetails(PNET_BUFFER_LIST nbl)
275 {
276 #if OVS_DBG_DEFAULT >= OVS_DBG_LOUD
277 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
278 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
279 if (info == NULL) {
280 return;
281 }
282 OVS_LOG_INFO("nbl: %p, numAvailableDest: %d, srcId:%d, srcIndex: %d "
283 "isDataSafe: %s, safeDataSize: %d",
284 nbl, info->NumAvailableDestinations, info->SourcePortId,
285 info->SourceNicIndex,
286 info->IsPacketDataSafe ? "TRUE" : "FALSE",
287 info->IsPacketDataSafe ? 0 : info->SafePacketDataSize);
288 #else
289 UNREFERENCED_PARAMETER(nbl);
290 #endif
291 }
292
293 static VOID
294 OvsDumpNBLContext(PNET_BUFFER_LIST nbl)
295 {
296 #if OVS_DBG_DEFAULT >= OVS_DBG_LOUD
297 PNET_BUFFER_LIST_CONTEXT ctx = nbl->Context;
298 if (ctx == NULL) {
299 OVS_LOG_INFO("No Net Buffer List context");
300 return;
301 }
302 while (ctx) {
303 OVS_LOG_INFO("nbl: %p, ctx: %p, TotalSize: %d, Offset: %d",
304 nbl, ctx, ctx->Size, ctx->Offset);
305 ctx = ctx->Next;
306 }
307 #else
308 UNREFERENCED_PARAMETER(nbl);
309 #endif
310 }
311
312
313 static VOID
314 OvsDumpMDLChain(PMDL mdl)
315 {
316 PMDL tmp;
317 tmp = mdl;
318 while (tmp) {
319 OVS_LOG_INFO("MDL: %p, Size: %d, MappedSystemVa: %p, StartVa: %p"
320 " ByteCount: %d, ByteOffset: %d",
321 tmp, tmp->Size, tmp->MappedSystemVa,
322 tmp->StartVa, tmp->ByteCount, tmp->ByteOffset);
323 tmp = tmp->Next;
324 }
325 }
326
327
328 static VOID
329 OvsDumpNetBuffer(PNET_BUFFER nb)
330 {
331 OVS_LOG_INFO("NET_BUFFER: %p, ChecksumBias: %d Handle: %p, MDLChain: %p "
332 "CurrMDL: %p, CurrOffset: %d, DataLen: %d, Offset: %d",
333 nb,
334 NET_BUFFER_CHECKSUM_BIAS(nb), nb->NdisPoolHandle,
335 NET_BUFFER_FIRST_MDL(nb),
336 NET_BUFFER_CURRENT_MDL(nb),
337 NET_BUFFER_CURRENT_MDL_OFFSET(nb),
338 NET_BUFFER_DATA_LENGTH(nb),
339 NET_BUFFER_DATA_OFFSET(nb));
340 OvsDumpMDLChain(NET_BUFFER_FIRST_MDL(nb));
341 }
342
343
344 static VOID
345 OvsDumpNetBufferList(PNET_BUFFER_LIST nbl)
346 {
347 #if OVS_DBG_DEFAULT >= OVS_DBG_LOUD
348 PNET_BUFFER nb;
349 OVS_LOG_INFO("NBL: %p, parent: %p, SrcHandle: %p, ChildCount:%d "
350 "poolHandle: %p",
351 nbl, nbl->ParentNetBufferList,
352 nbl->SourceHandle, nbl->ChildRefCount,
353 nbl->NdisPoolHandle);
354 OvsDumpNBLContext(nbl);
355 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
356 while (nb) {
357 OvsDumpNetBuffer(nb);
358 nb = NET_BUFFER_NEXT_NB(nb);
359 }
360 #else
361 UNREFERENCED_PARAMETER(nbl);
362 #endif
363 }
364
365 /*
366 * --------------------------------------------------------------------------
367 * OvsAllocateFixSizeNBL --
368 *
369 * Allocate fix size NBL which include
370 * NBL + NB + MBL + Data + Context
371 * Please note:
372 * * Forwarding Context is allocated, but forwarding detail information
373 * is not initailized.
374 * * The headroom can not be larger than OVS_DEFAULT_HEADROOM_SIZE(128
375 * byte).
376 * --------------------------------------------------------------------------
377 */
378 PNET_BUFFER_LIST
379 OvsAllocateFixSizeNBL(PVOID ovsContext,
380 UINT32 size,
381 UINT32 headRoom)
382 {
383 PNET_BUFFER_LIST nbl = NULL;
384 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
385 POVS_BUFFER_CONTEXT ctx;
386 POVS_NBL_POOL ovsPool = &context->ovsPool;
387 NDIS_STATUS status;
388 UINT32 line;
389 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
390
391 if ((headRoom + size) > OVS_FIX_NBL_DATA_SIZE || size == 0) {
392 line = __LINE__;
393 goto allocate_done;
394 }
395
396 nbl = NdisAllocateNetBufferList(ovsPool->fixSizePool,
397 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
398 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
399
400 if (nbl == NULL) {
401 line = __LINE__;
402 goto allocate_done;
403 }
404
405 nbl->SourceHandle = ovsPool->ndisHandle;
406 status = context->NdisSwitchHandlers.
407 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
408
409 if (status != NDIS_STATUS_SUCCESS) {
410 NdisFreeNetBufferList(nbl);
411 nbl = NULL;
412 line = __LINE__;
413 goto allocate_done;
414 }
415 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
416 ASSERT(info);
417 info->IsPacketDataSafe = TRUE;
418 info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
419
420 status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
421 size, 0, NULL);
422 ASSERT(status == NDIS_STATUS_SUCCESS);
423
424 #ifdef DBG
425 InterlockedIncrement((LONG volatile *)&ovsPool->fixNBLCount);
426 OvsDumpNetBufferList(nbl);
427 OvsDumpForwardingDetails(nbl);
428 #endif
429
430 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
431 ASSERT(ctx);
432
433 OvsInitNBLContext(ctx, OVS_BUFFER_FROM_FIX_SIZE_POOL |
434 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT, size,
435 OVS_DPPORT_NUMBER_INVALID);
436 line = __LINE__;
437 allocate_done:
438 OVS_LOG_LOUD("Allocate Fix NBL: %p, line: %d", nbl, line);
439 return nbl;
440 }
441
442
443 static PMDL
444 OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle,
445 UINT32 dataSize)
446 {
447 PMDL mdl;
448 PVOID data;
449
450 data = OvsAllocateMemoryWithTag(dataSize, OVS_MDL_POOL_TAG);
451 if (data == NULL) {
452 return NULL;
453 }
454
455 mdl = NdisAllocateMdl(ndisHandle, data, dataSize);
456 if (mdl == NULL) {
457 OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
458 }
459
460 return mdl;
461 }
462
463
464 static VOID
465 OvsFreeMDLAndData(PMDL mdl)
466 {
467 PVOID data;
468
469 data = MmGetMdlVirtualAddress(mdl);
470 NdisFreeMdl(mdl);
471 OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
472 }
473
474
475 /*
476 * --------------------------------------------------------------------------
477 * OvsAllocateVariableSizeNBL --
478 *
479 * Allocate variable size NBL, the NBL looks like
480 * NBL + NB + Context
481 * MDL + Data
482 * --------------------------------------------------------------------------
483 */
484 PNET_BUFFER_LIST
485 OvsAllocateVariableSizeNBL(PVOID ovsContext,
486 UINT32 size,
487 UINT32 headRoom)
488 {
489 PNET_BUFFER_LIST nbl = NULL;
490 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
491 POVS_NBL_POOL ovsPool = &context->ovsPool;
492 POVS_BUFFER_CONTEXT ctx;
493 UINT32 realSize;
494 PMDL mdl;
495 NDIS_STATUS status;
496 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
497 if (size == 0) {
498 return NULL;
499 }
500 realSize = MEM_ALIGN_SIZE(size + headRoom);
501
502 mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, realSize);
503 if (mdl == NULL) {
504 return NULL;
505 }
506
507 nbl = NdisAllocateNetBufferAndNetBufferList(ovsPool->zeroSizePool,
508 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
509 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL,
510 mdl, realSize, 0);
511 if (nbl == NULL) {
512 OvsFreeMDLAndData(mdl);
513 return NULL;
514 }
515
516 nbl->SourceHandle = ovsPool->ndisHandle;
517 status = context->NdisSwitchHandlers.
518 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
519
520 if (status != NDIS_STATUS_SUCCESS) {
521 /*
522 * do we need to remove mdl from nbl XXX
523 */
524 OvsFreeMDLAndData(mdl);
525 NdisFreeNetBufferList(nbl);
526 return NULL;
527 }
528
529 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
530 ASSERT(info);
531 info->IsPacketDataSafe = TRUE;
532 info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
533 status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
534 size, 0, NULL);
535 ASSERT(status == NDIS_STATUS_SUCCESS);
536
537 #ifdef DBG
538 InterlockedIncrement((LONG volatile *)&ovsPool->zeroNBLCount);
539 OvsDumpNetBufferList(nbl);
540 OvsDumpForwardingDetails(nbl);
541 #endif
542
543 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
544
545 OvsInitNBLContext(ctx, OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
546 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT |
547 OVS_BUFFER_FROM_ZERO_SIZE_POOL,
548 size, OVS_DPPORT_NUMBER_INVALID);
549
550 OVS_LOG_LOUD("Allocate variable size NBL: %p", nbl);
551 return nbl;
552 }
553
554
555 /*
556 * --------------------------------------------------------------------------
557 * OvsInitExternalNBLContext --
558 *
559 * For NBL not allocated by OVS, it will allocate and initialize
560 * the NBL context.
561 * --------------------------------------------------------------------------
562 */
563 POVS_BUFFER_CONTEXT
564 OvsInitExternalNBLContext(PVOID ovsContext,
565 PNET_BUFFER_LIST nbl,
566 BOOLEAN isRecv)
567 {
568 NDIS_HANDLE poolHandle;
569 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
570 POVS_BUFFER_CONTEXT ctx;
571 PNET_BUFFER nb;
572 NDIS_STATUS status;
573 UINT16 flags;
574
575 poolHandle = NdisGetPoolFromNetBufferList(nbl);
576
577 if (poolHandle == context->ovsPool.ndisHandle ||
578 nbl->SourceHandle == context->ovsPool.ndisHandle) {
579 return (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
580 }
581 status = NdisAllocateNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT),
582 OVS_DEFAULT_NBL_CONTEXT_FILL,
583 OVS_OTHER_POOL_TAG);
584 if (status != NDIS_STATUS_SUCCESS) {
585 return NULL;
586 }
587 #ifdef DBG
588 OvsDumpNBLContext(nbl);
589 InterlockedIncrement((LONG volatile *)&context->ovsPool.sysNBLCount);
590 #endif
591 flags = isRecv ? OVS_BUFFER_RECV_BUFFER : OVS_BUFFER_SEND_BUFFER;
592 flags |= OVS_BUFFER_NEED_COMPLETE | OVS_BUFFER_PRIVATE_CONTEXT;
593 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
594
595 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
596 /*
597 * we use first nb to decide whether we need advance or retreat during
598 * complete.
599 */
600 OvsInitNBLContext(ctx, flags, NET_BUFFER_DATA_LENGTH(nb),
601 OVS_DPPORT_NUMBER_INVALID);
602 return ctx;
603 }
604
605 /*
606 * --------------------------------------------------------------------------
607 * OvsAllocateNBLContext
608 *
609 * Create NBL buffer context and forwarding context.
610 * --------------------------------------------------------------------------
611 */
612 NDIS_STATUS
613 OvsAllocateNBLContext(POVS_SWITCH_CONTEXT context,
614 PNET_BUFFER_LIST nbl)
615 {
616 POVS_NBL_POOL ovsPool = &context->ovsPool;
617 NDIS_STATUS status;
618
619 status = NdisAllocateNetBufferListContext(nbl,
620 sizeof (OVS_BUFFER_CONTEXT),
621 OVS_DEFAULT_NBL_CONTEXT_FILL,
622 OVS_OTHER_POOL_TAG);
623 if (status != NDIS_STATUS_SUCCESS) {
624 return NDIS_STATUS_FAILURE;
625 }
626
627 nbl->SourceHandle = ovsPool->ndisHandle;
628 status = context->NdisSwitchHandlers.
629 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
630
631 if (status != NDIS_STATUS_SUCCESS) {
632 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
633 return NDIS_STATUS_FAILURE;
634 }
635 return status;
636 }
637
638 /*
639 * --------------------------------------------------------------------------
640 * OvsFreeNBLContext
641 *
642 * Free the NBL buffer context and forwarding context.
643 * --------------------------------------------------------------------------
644 */
645 NDIS_STATUS
646 OvsFreeNBLContext(POVS_SWITCH_CONTEXT context,
647 PNET_BUFFER_LIST nbl)
648 {
649 POVS_NBL_POOL ovsPool = &context->ovsPool;
650
651 context->NdisSwitchHandlers.
652 FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
653 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
654
655 return NDIS_STATUS_SUCCESS;
656 }
657
658 /*
659 * --------------------------------------------------------------------------
660 * OvsCopyNBLInfo
661 *
662 * Copy NBL info from src to dst
663 * --------------------------------------------------------------------------
664 */
665 NDIS_STATUS
666 OvsCopyNBLInfo(PNET_BUFFER_LIST srcNbl, PNET_BUFFER_LIST dstNbl,
667 POVS_BUFFER_CONTEXT srcCtx, UINT32 copySize,
668 BOOLEAN copyNblInfo)
669 {
670 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO srcInfo, dstInfo;
671 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
672
673 srcInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(srcNbl);
674 dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(dstNbl);
675 if (srcInfo) {
676 #ifdef OVS_USE_COPY_NET_BUFFER_LIST_INFO
677 status = context->NdisSwitchHandlers.
678 CopyNetBufferListInfo(ovsPool->ndisContext, dstNbl, srcNbl, 0);
679
680 if (status != NDIS_STATUS_SUCCESS) {
681 return status;
682 }
683 #else
684 dstInfo->SourcePortId = srcInfo->SourcePortId;
685 dstInfo->SourceNicIndex = srcInfo->SourceNicIndex;
686 if (copyNblInfo) {
687 if (srcCtx->flags & OVS_BUFFER_RECV_BUFFER) {
688 NdisCopyReceiveNetBufferListInfo(dstNbl, srcNbl);
689 } else if (srcCtx->flags & OVS_BUFFER_SEND_BUFFER) {
690 NdisCopySendNetBufferListInfo(dstNbl, srcNbl);
691 }
692 }
693 #endif
694 dstInfo->IsPacketDataSafe = srcInfo->IsPacketDataSafe;
695 if (!srcInfo->IsPacketDataSafe && copySize >
696 srcInfo->SafePacketDataSize) {
697 srcInfo->SafePacketDataSize = copySize;
698 }
699 } else {
700 /*
701 * Assume all data are safe
702 */
703 dstInfo->IsPacketDataSafe = TRUE;
704 dstInfo->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
705 }
706 return status;
707 }
708
709 /*
710 * --------------------------------------------------------------------------
711 * OvsPartialCopyNBL --
712 *
713 * Partial copy NBL, if there is multiple NB in NBL, each one will be
714 * copied. We also reserve headroom for the new NBL.
715 *
716 * Please note,
717 * NBL should have OVS_BUFFER_CONTEXT setup before calling
718 * this function.
719 * The NBL should already have ref to itself so that during copy
720 * it will not be freed.
721 * --------------------------------------------------------------------------
722 */
723 PNET_BUFFER_LIST
724 OvsPartialCopyNBL(PVOID ovsContext,
725 PNET_BUFFER_LIST nbl,
726 UINT32 copySize,
727 UINT32 headRoom,
728 BOOLEAN copyNblInfo)
729 {
730 PNET_BUFFER_LIST newNbl;
731 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
732 NDIS_STATUS status;
733 PNET_BUFFER srcNb, dstNb;
734 ULONG byteCopied;
735 POVS_NBL_POOL ovsPool = &context->ovsPool;
736 POVS_BUFFER_CONTEXT srcCtx, dstCtx;
737 UINT16 flags;
738
739 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
740 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
741 OVS_LOG_INFO("src nbl must have ctx initialized");
742 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
743 return NULL;
744 }
745
746 if (copySize) {
747 NdisAdvanceNetBufferListDataStart(nbl, copySize, FALSE, NULL);
748 }
749 newNbl = NdisAllocateCloneNetBufferList(nbl, ovsPool->nblOnlyPool,
750 NULL, 0);
751 if (copySize) {
752 status = NdisRetreatNetBufferListDataStart(nbl, copySize, 0,
753 NULL, NULL);
754 ASSERT(status == NDIS_STATUS_SUCCESS);
755 }
756
757 if (newNbl == NULL) {
758 return NULL;
759 }
760
761 /*
762 * Allocate private memory for copy
763 */
764 if (copySize + headRoom) {
765 status = NdisRetreatNetBufferListDataStart(newNbl, copySize + headRoom,
766 0, NULL, NULL);
767 if (status != NDIS_STATUS_SUCCESS) {
768 goto retreat_error;
769 }
770
771 if (headRoom) {
772 NdisAdvanceNetBufferListDataStart(newNbl, headRoom, FALSE, NULL);
773 }
774 if (copySize) {
775 srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
776 dstNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
777
778 while (srcNb) {
779 status = NdisCopyFromNetBufferToNetBuffer(dstNb, 0, copySize,
780 srcNb, 0,
781 &byteCopied);
782 if (status != NDIS_STATUS_SUCCESS || copySize != byteCopied) {
783 goto nbl_context_error;
784 }
785 srcNb = NET_BUFFER_NEXT_NB(srcNb);
786 dstNb = NET_BUFFER_NEXT_NB(dstNb);
787 }
788 }
789 }
790
791 status = OvsAllocateNBLContext(context, newNbl);
792 if (status != NDIS_STATUS_SUCCESS) {
793 goto nbl_context_error;
794 }
795
796 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copySize, copyNblInfo);
797 if (status != NDIS_STATUS_SUCCESS) {
798 goto copy_list_info_error;
799 }
800
801 #ifdef DBG
802 InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
803 #endif
804
805 newNbl->ParentNetBufferList = nbl;
806
807 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
808 ASSERT(dstCtx != NULL);
809
810 flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
811
812 flags |= OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_CONTEXT |
813 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;
814
815 srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
816 ASSERT(srcNb);
817 OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(srcNb) - copySize,
818 OVS_DPPORT_NUMBER_INVALID);
819
820 InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
821
822 #ifdef DBG
823 OvsDumpNetBufferList(nbl);
824 OvsDumpForwardingDetails(nbl);
825
826 OvsDumpNetBufferList(newNbl);
827 OvsDumpForwardingDetails(newNbl);
828 #endif
829
830 OVS_LOG_LOUD("Partial Copy new NBL: %p", newNbl);
831 return newNbl;
832
833 copy_list_info_error:
834 OvsFreeNBLContext(context, newNbl);
835 nbl_context_error:
836 if (copySize) {
837 NdisAdvanceNetBufferListDataStart(newNbl, copySize, TRUE, NULL);
838 }
839 retreat_error:
840 NdisFreeCloneNetBufferList(newNbl, 0);
841 return NULL;
842 }
843
844 /*
845 * --------------------------------------------------------------------------
846 * OvsPartialCopyToMultipleNBLs --
847 *
848 * This is similar to OvsPartialCopyNBL() except that each NB will
849 * have its own NBL.
850 * --------------------------------------------------------------------------
851 */
852 PNET_BUFFER_LIST
853 OvsPartialCopyToMultipleNBLs(PVOID ovsContext,
854 PNET_BUFFER_LIST nbl,
855 UINT32 copySize,
856 UINT32 headRoom,
857 BOOLEAN copyNblInfo)
858 {
859 PNET_BUFFER nb, nextNb = NULL, firstNb, prevNb;
860 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
861 PNET_BUFFER_LIST firstNbl = NULL, newNbl, prevNbl = NULL;
862
863 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
864 if (NET_BUFFER_NEXT_NB(nb) == NULL) {
865 return OvsPartialCopyNBL(context, nbl, copySize, headRoom, copyNblInfo);
866 }
867
868 firstNb = nb;
869 prevNb = nb;
870
871 while (nb) {
872 nextNb = NET_BUFFER_NEXT_NB(nb);
873 NET_BUFFER_NEXT_NB(nb) = NULL;
874
875 NET_BUFFER_LIST_FIRST_NB(nbl) = nb;
876
877 newNbl = OvsPartialCopyNBL(context, nbl, copySize, headRoom,
878 copyNblInfo);
879 if (newNbl == NULL) {
880 goto cleanup;
881 }
882 if (prevNbl == NULL) {
883 firstNbl = newNbl;
884 } else {
885 NET_BUFFER_LIST_NEXT_NBL(prevNbl) = newNbl;
886 NET_BUFFER_NEXT_NB(prevNb) = nb;
887 }
888 prevNbl = newNbl;
889 prevNb = nb;
890 nb = nextNb;
891 }
892 NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;
893 return firstNbl;
894
895 cleanup:
896 NET_BUFFER_NEXT_NB(prevNb) = nb;
897 NET_BUFFER_NEXT_NB(nb) = nextNb;
898 NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;
899
900 newNbl = firstNbl;
901 while (newNbl) {
902 firstNbl = NET_BUFFER_LIST_NEXT_NBL(newNbl);
903 NET_BUFFER_LIST_NEXT_NBL(newNbl) = NULL;
904 OvsCompleteNBL(context, newNbl, TRUE);
905 newNbl = firstNbl;
906 }
907 return NULL;
908 }
909
910
911 static PNET_BUFFER_LIST
912 OvsCopySinglePacketNBL(PVOID ovsContext,
913 PNET_BUFFER_LIST nbl,
914 PNET_BUFFER nb,
915 UINT32 headRoom,
916 BOOLEAN copyNblInfo)
917 {
918 UINT32 size;
919 ULONG copiedSize;
920 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
921 PNET_BUFFER_LIST newNbl;
922 PNET_BUFFER newNb;
923 NDIS_STATUS status;
924 POVS_BUFFER_CONTEXT srcCtx, dstCtx;
925
926 size = NET_BUFFER_DATA_LENGTH(nb);
927 if ((size + headRoom) <= OVS_FIX_NBL_DATA_SIZE) {
928 newNbl = OvsAllocateFixSizeNBL(context, size, headRoom);
929 } else {
930 newNbl = OvsAllocateVariableSizeNBL(context, size, headRoom);
931 }
932 if (newNbl == NULL) {
933 return NULL;
934 }
935 newNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
936 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
937 &copiedSize);
938
939 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
940 if (status == NDIS_STATUS_SUCCESS) {
941 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copiedSize, copyNblInfo);
942 }
943
944 if (status != NDIS_STATUS_SUCCESS || copiedSize != size) {
945 OvsCompleteNBL(context, newNbl, TRUE);
946 return NULL;
947 }
948
949 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
950 ASSERT(dstCtx && srcCtx);
951 ASSERT(srcCtx->magic == OVS_CTX_MAGIC && dstCtx->magic == OVS_CTX_MAGIC);
952
953 dstCtx->flags |= srcCtx->flags & (OVS_BUFFER_RECV_BUFFER |
954 OVS_BUFFER_SEND_BUFFER);
955 #ifdef DBG
956 OvsDumpNetBufferList(newNbl);
957 OvsDumpForwardingDetails(newNbl);
958 #endif
959 OVS_LOG_LOUD("Copy single nb to new NBL: %p", newNbl);
960 return newNbl;
961 }
962
963 /*
964 * --------------------------------------------------------------------------
965 * OvsFullCopyNBL --
966 *
967 * Copy the NBL to a new NBL including data.
968 *
969 * Notes:
970 * The NBL can have multiple NBs, but the final result is one NBL.
971 * --------------------------------------------------------------------------
972 */
973 PNET_BUFFER_LIST
974 OvsFullCopyNBL(PVOID ovsContext,
975 PNET_BUFFER_LIST nbl,
976 UINT32 headRoom,
977 BOOLEAN copyNblInfo)
978 {
979 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
980 POVS_NBL_POOL ovsPool = &context->ovsPool;
981 PNET_BUFFER_LIST newNbl;
982 PNET_BUFFER nb, newNb, firstNb = NULL, prevNb = NULL;
983 POVS_BUFFER_CONTEXT dstCtx, srcCtx;
984 PMDL mdl;
985 NDIS_STATUS status;
986 UINT32 size, totalSize;
987 ULONG copiedSize;
988 UINT16 flags;
989 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo;
990
991 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
992 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
993 OVS_LOG_INFO("src nbl must have ctx initialized");
994 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
995 return NULL;
996 }
997
998 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
999 if (nb == NULL) {
1000 return NULL;
1001 }
1002
1003 if (NET_BUFFER_NEXT_NB(nb) == NULL) {
1004 return OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
1005 }
1006
1007 newNbl = NdisAllocateNetBufferList(ovsPool->nblOnlyPool,
1008 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
1009 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
1010 if (newNbl == NULL) {
1011 return NULL;
1012 }
1013
1014 while (nb) {
1015 size = NET_BUFFER_DATA_LENGTH(nb);
1016 totalSize = MEM_ALIGN_SIZE(size + headRoom);
1017 mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, totalSize);
1018
1019 if (mdl == NULL) {
1020 goto nblcopy_error;
1021 }
1022 newNb = NdisAllocateNetBuffer(ovsPool->nbPool, mdl, totalSize, 0);
1023 if (newNb == NULL) {
1024 OvsFreeMDLAndData(mdl);
1025 goto nblcopy_error;
1026 }
1027 if (firstNb == NULL) {
1028 firstNb = newNb;
1029 } else {
1030 NET_BUFFER_NEXT_NB(prevNb) = newNb;
1031 }
1032 prevNb = newNb;
1033 #ifdef DBG
1034 InterlockedIncrement((LONG volatile *)&ovsPool->nbCount);
1035 #endif
1036 status = NdisRetreatNetBufferDataStart(newNb, size, 0, NULL);
1037 ASSERT(status == NDIS_STATUS_SUCCESS);
1038
1039 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
1040 &copiedSize);
1041 if (status != NDIS_STATUS_SUCCESS || size != copiedSize) {
1042 goto nblcopy_error;
1043 }
1044
1045 nb = NET_BUFFER_NEXT_NB(nb);
1046 }
1047
1048 NET_BUFFER_LIST_FIRST_NB(newNbl) = firstNb;
1049
1050 newNbl->SourceHandle = ovsPool->ndisHandle;
1051 status = context->NdisSwitchHandlers.
1052 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, newNbl);
1053
1054 if (status != NDIS_STATUS_SUCCESS) {
1055 goto nblcopy_error;
1056 }
1057
1058 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, 0, copyNblInfo);
1059 if (status != NDIS_STATUS_SUCCESS) {
1060 goto nblcopy_error;
1061 }
1062
1063 dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl);
1064 dstInfo->IsPacketDataSafe = TRUE;
1065
1066 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
1067
1068 flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
1069
1070 flags |= OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
1071 OVS_BUFFER_PRIVATE_NET_BUFFER | OVS_BUFFER_FROM_NBL_ONLY_POOL |
1072 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;
1073
1074 OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(firstNb),
1075 OVS_DPPORT_NUMBER_INVALID);
1076
1077 #ifdef DBG
1078 OvsDumpNetBufferList(nbl);
1079 OvsDumpForwardingDetails(nbl);
1080 InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
1081 #endif
1082 OVS_LOG_LOUD("newNbl: %p", newNbl);
1083 return newNbl;
1084
1085 nblcopy_error:
1086 while (firstNb) {
1087 #ifdef DBG
1088 InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
1089 #endif
1090 prevNb = firstNb;
1091 firstNb = NET_BUFFER_NEXT_NB(prevNb);
1092 mdl = NET_BUFFER_FIRST_MDL(prevNb);
1093 NET_BUFFER_FIRST_MDL(prevNb) = NULL;
1094 NdisFreeNetBuffer(prevNb);
1095 OvsFreeMDLAndData(mdl);
1096 }
1097 NdisFreeNetBufferList(newNbl);
1098 OVS_LOG_ERROR("OvsFullCopyNBL failed");
1099 return NULL;
1100 }
1101
1102 NDIS_STATUS
1103 GetIpHeaderInfo(PNET_BUFFER_LIST curNbl,
1104 UINT32 *hdrSize)
1105 {
1106 CHAR *ethBuf[sizeof(EthHdr)];
1107 EthHdr *eth;
1108 IPHdr *ipHdr;
1109 PNET_BUFFER curNb;
1110
1111 curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
1112 ASSERT(NET_BUFFER_NEXT_NB(curNb) == NULL);
1113
1114 eth = (EthHdr *)NdisGetDataBuffer(curNb, ETH_HEADER_LENGTH,
1115 (PVOID)&ethBuf, 1, 0);
1116 if (eth == NULL) {
1117 return NDIS_STATUS_INVALID_PACKET;
1118 }
1119 ipHdr = (IPHdr *)((PCHAR)eth + ETH_HEADER_LENGTH);
1120 if (ipHdr == NULL) {
1121 return NDIS_STATUS_INVALID_PACKET;
1122 }
1123 *hdrSize = (UINT32)(ETH_HEADER_LENGTH + (ipHdr->ihl * 4));
1124 return NDIS_STATUS_SUCCESS;
1125 }
1126
1127 /*
1128 * --------------------------------------------------------------------------
1129 * GetSegmentHeaderInfo
1130 *
1131 * Extract header size and sequence number for the segment.
1132 * --------------------------------------------------------------------------
1133 */
1134 static NDIS_STATUS
1135 GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl,
1136 const POVS_PACKET_HDR_INFO hdrInfo,
1137 UINT32 *hdrSize, UINT32 *seqNumber)
1138 {
1139 TCPHdr tcpStorage;
1140 const TCPHdr *tcp;
1141
1142 /* Parse the orginal Eth/IP/TCP header */
1143 tcp = OvsGetPacketBytes(nbl, sizeof *tcp, hdrInfo->l4Offset, &tcpStorage);
1144 if (tcp == NULL) {
1145 return NDIS_STATUS_FAILURE;
1146 }
1147 *seqNumber = ntohl(tcp->seq);
1148 *hdrSize = hdrInfo->l4Offset + TCP_HDR_LEN(tcp);
1149
1150 return NDIS_STATUS_SUCCESS;
1151 }
1152
1153 /*
1154 * --------------------------------------------------------------------------
1155 * FixFragmentHeader
1156 *
1157 * Fix IP length, Offset, IP checksum.
1158 * XXX - Support IpV6 Fragments
1159 * --------------------------------------------------------------------------
1160 */
1161 static NDIS_STATUS
1162 FixFragmentHeader(PNET_BUFFER nb, UINT16 fragmentSize,
1163 BOOLEAN lastPacket, UINT16 offset)
1164 {
1165 EthHdr *dstEth = NULL;
1166 PMDL mdl = NULL;
1167 PUINT8 bufferStart = NULL;
1168
1169 mdl = NET_BUFFER_FIRST_MDL(nb);
1170
1171 bufferStart = (PUINT8)OvsGetMdlWithLowPriority(mdl);
1172 if (!bufferStart) {
1173 return NDIS_STATUS_RESOURCES;
1174 }
1175 dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb));
1176
1177 switch (dstEth->Type) {
1178 case ETH_TYPE_IPV4_NBO:
1179 {
1180 IPHdr *dstIP = NULL;
1181 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1182 >= sizeof(EthHdr) + sizeof(IPHdr));
1183
1184 dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth));
1185 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1186 >= sizeof(EthHdr) + dstIP->ihl * 4);
1187 dstIP->tot_len = htons(fragmentSize + dstIP->ihl * 4);
1188 if (lastPacket) {
1189 dstIP->frag_off = htons(offset & IP_OFFSET);
1190 } else {
1191 dstIP->frag_off = htons((offset & IP_OFFSET) | IP_MF);
1192 }
1193
1194 dstIP->check = 0;
1195 dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);
1196 break;
1197 }
1198 case ETH_TYPE_IPV6_NBO:
1199 {
1200 return NDIS_STATUS_NOT_SUPPORTED;
1201 }
1202 default:
1203 OVS_LOG_ERROR("Invalid eth type: %d\n", dstEth->Type);
1204 ASSERT(! "Invalid eth type");
1205 }
1206
1207 return STATUS_SUCCESS;
1208 }
1209
1210 /*
1211 * --------------------------------------------------------------------------
1212 * FixSegmentHeader
1213 *
1214 * Fix IP length, IP checksum, TCP sequence number and TCP checksum
1215 * in the segment.
1216 * --------------------------------------------------------------------------
1217 */
1218 static NDIS_STATUS
1219 FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
1220 BOOLEAN lastPacket, UINT16 packetCounter)
1221 {
1222 EthHdr *dstEth = NULL;
1223 TCPHdr *dstTCP = NULL;
1224 PMDL mdl = NULL;
1225 PUINT8 bufferStart = NULL;
1226
1227 mdl = NET_BUFFER_FIRST_MDL(nb);
1228
1229 bufferStart = (PUINT8)OvsGetMdlWithLowPriority(mdl);
1230 if (!bufferStart) {
1231 return NDIS_STATUS_RESOURCES;
1232 }
1233 dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb));
1234
1235 switch (dstEth->Type) {
1236 case ETH_TYPE_IPV4_NBO:
1237 {
1238 IPHdr *dstIP = NULL;
1239
1240 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1241 >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr));
1242 dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth));
1243 dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4);
1244 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1245 >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
1246
1247 /* Fix IP length and checksum */
1248 ASSERT(dstIP->protocol == IPPROTO_TCP);
1249 dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
1250 dstIP->id += packetCounter;
1251 dstIP->check = 0;
1252 dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);
1253 dstTCP->seq = htonl(seqNumber);
1254
1255 /*
1256 * Set the TCP FIN and PSH bit only for the last packet
1257 * More information can be found under:
1258 * https://msdn.microsoft.com/en-us/library/windows/hardware/ff568840%28v=vs.85%29.aspx
1259 */
1260 if (dstTCP->fin) {
1261 dstTCP->fin = lastPacket;
1262 }
1263 if (dstTCP->psh) {
1264 dstTCP->psh = lastPacket;
1265 }
1266 UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP);
1267 dstTCP->check = IPPseudoChecksum(&dstIP->saddr,
1268 &dstIP->daddr,
1269 IPPROTO_TCP,
1270 csumLength);
1271 dstTCP->check = CalculateChecksumNB(nb,
1272 csumLength,
1273 sizeof(*dstEth) + dstIP->ihl * 4);
1274 break;
1275 }
1276 case ETH_TYPE_IPV6_NBO:
1277 {
1278 IPv6Hdr *dstIP = NULL;
1279
1280 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1281 >= sizeof(EthHdr) + sizeof(IPv6Hdr) + sizeof(TCPHdr));
1282 dstIP = (IPv6Hdr *)((PCHAR)dstEth + sizeof(*dstEth));
1283 dstTCP = (TCPHdr *)((PCHAR)dstIP + sizeof(IPv6Hdr));
1284 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1285 >= sizeof(EthHdr) + sizeof(IPv6Hdr) + TCP_HDR_LEN(dstTCP));
1286
1287 /* Fix IP length */
1288 ASSERT(dstIP->nexthdr == IPPROTO_TCP);
1289 dstIP->payload_len = htons(segmentSize + sizeof(IPv6Hdr) + TCP_HDR_LEN(dstTCP));
1290
1291 dstTCP->seq = htonl(seqNumber);
1292 if (dstTCP->fin) {
1293 dstTCP->fin = lastPacket;
1294 }
1295 if (dstTCP->psh) {
1296 dstTCP->psh = lastPacket;
1297 }
1298
1299 UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP);
1300 dstTCP->check = IPv6PseudoChecksum((UINT32*)&dstIP->saddr,
1301 (UINT32*)&dstIP->daddr,
1302 IPPROTO_TCP,
1303 csumLength);
1304 dstTCP->check = CalculateChecksumNB(nb,
1305 csumLength,
1306 sizeof(*dstEth) + sizeof(IPv6Hdr));
1307 break;
1308 }
1309 default:
1310 OVS_LOG_ERROR("Invalid eth type: %d\n", dstEth->Type);
1311 ASSERT(! "Invalid eth type");
1312 }
1313
1314 return STATUS_SUCCESS;
1315 }
1316 /*
1317 * --------------------------------------------------------------------------
1318 * OvsTcpSegmentNBL --
1319 * Wrapper function to Fragment a given NBL based on MSS
1320 * --------------------------------------------------------------------------
1321 */
1322 PNET_BUFFER_LIST
1323 OvsTcpSegmentNBL(PVOID ovsContext,
1324 PNET_BUFFER_LIST nbl,
1325 POVS_PACKET_HDR_INFO hdrInfo,
1326 UINT32 mss,
1327 UINT32 headRoom,
1328 BOOLEAN isIpFragment)
1329 {
1330 return OvsFragmentNBL(ovsContext, nbl, hdrInfo, mss, headRoom, isIpFragment);
1331 }
1332
1333
1334 /*
1335 * --------------------------------------------------------------------------
1336 * OvsFragmentNBL --
1337 *
1338 * Fragment NBL payload, and prepend each segment with Ether/IP/TCP header.
1339 * Leave headRoom for additional encap.
1340 *
1341 * Please note,
1342 * NBL should have OVS_BUFFER_CONTEXT setup before calling
1343 * this function.
1344 * The NBL should already have ref to itself so that during copy
1345 * it will not be freed.
1346 * Currently this API assert there is only one NB in an NBL, it needs
1347 * to be fixed if we receive multiple NBs in an NBL.
1348 * --------------------------------------------------------------------------
1349 */
1350 PNET_BUFFER_LIST
1351 OvsFragmentNBL(PVOID ovsContext,
1352 PNET_BUFFER_LIST nbl,
1353 POVS_PACKET_HDR_INFO hdrInfo,
1354 UINT32 fragmentSize,
1355 UINT32 headRoom,
1356 BOOLEAN isIpFragment)
1357 {
1358 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
1359 #ifdef DBG
1360 POVS_NBL_POOL ovsPool = &context->ovsPool;
1361 #endif
1362 POVS_BUFFER_CONTEXT dstCtx, srcCtx;
1363 UINT32 size, hdrSize, nblSize, seqNumber = 0;
1364 PNET_BUFFER_LIST newNbl;
1365 PNET_BUFFER nb, newNb;
1366 NDIS_STATUS status;
1367 UINT16 segmentSize;
1368 ULONG copiedSize;
1369 UINT16 offset = 0, packetCounter = 0;
1370
1371 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1372 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
1373 OVS_LOG_INFO("src nbl must have ctx initialized");
1374 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
1375 return NULL;
1376 }
1377
1378 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1379 ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL);
1380
1381 /* Figure out the header size */
1382 if (isIpFragment) {
1383 status = GetIpHeaderInfo(nbl, &hdrSize);
1384 } else {
1385 status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber);
1386 }
1387 if (status != NDIS_STATUS_SUCCESS) {
1388 OVS_LOG_INFO("Cannot parse NBL header");
1389 return NULL;
1390 }
1391 /* Get the NBL size. */
1392 if (isIpFragment) {
1393 nblSize = fragmentSize - hdrSize;
1394 } else {
1395 nblSize = fragmentSize;
1396 }
1397 size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize;
1398
1399 /* XXX add to ovsPool counters? */
1400 newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL, NULL, hdrSize,
1401 nblSize, hdrSize + headRoom ,
1402 0, 0);
1403 if (newNbl == NULL) {
1404 return NULL;
1405 }
1406
1407 /* Now deal with TCP payload */
1408 for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL;
1409 newNb = NET_BUFFER_NEXT_NB(newNb)) {
1410 segmentSize = (size > nblSize ? nblSize : size) & 0xffff;
1411 if (headRoom) {
1412 NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL);
1413 }
1414
1415 /* Now copy the eth/IP/TCP header and fix up */
1416 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize, nb, 0,
1417 &copiedSize);
1418 if (status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize) {
1419 goto nblcopy_error;
1420 }
1421
1422 if (isIpFragment) {
1423 status = FixFragmentHeader(newNb, segmentSize,
1424 NET_BUFFER_NEXT_NB(newNb) == NULL,
1425 offset);
1426 } else {
1427 status = FixSegmentHeader(newNb, segmentSize, seqNumber,
1428 NET_BUFFER_NEXT_NB(newNb) == NULL,
1429 packetCounter);
1430 }
1431
1432 if (status != NDIS_STATUS_SUCCESS) {
1433 goto nblcopy_error;
1434 }
1435
1436 /* Move on to the next segment */
1437 if (isIpFragment) {
1438 offset += (segmentSize) / 8;
1439 } else {
1440 seqNumber += segmentSize;
1441 }
1442 size -= segmentSize;
1443 packetCounter++;
1444 }
1445
1446 status = OvsAllocateNBLContext(context, newNbl);
1447 if (status != NDIS_STATUS_SUCCESS) {
1448 goto nblcopy_error;
1449 }
1450
1451 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, hdrSize + headRoom, FALSE);
1452 if (status != NDIS_STATUS_SUCCESS) {
1453 goto nbl_context_error;
1454 }
1455
1456 if (isIpFragment) {
1457 /*Copy with Flag - NDIS_SWITCH_COPY_NBL_INFO_FLAGS_PRESERVE_DESTINATIONS.*/
1458 status = context->NdisSwitchHandlers.
1459 CopyNetBufferListInfo(context->ovsPool.ndisContext, newNbl, nbl, 1);
1460
1461 if (status != NDIS_STATUS_SUCCESS) {
1462 goto nbl_context_error;
1463 }
1464 }
1465 newNbl->ParentNetBufferList = nbl;
1466
1467 /* Remember it's a fragment NBL so we can free it properly */
1468 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
1469 ASSERT(dstCtx != NULL);
1470 dstCtx->flags = OVS_BUFFER_FRAGMENT | OVS_BUFFER_PRIVATE_CONTEXT |
1471 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | OVS_BUFFER_SEND_BUFFER;
1472 dstCtx->refCount = 1;
1473 dstCtx->magic = OVS_CTX_MAGIC;
1474 dstCtx->dataOffsetDelta = hdrSize + headRoom;
1475 dstCtx->mru = 0;
1476
1477 InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
1478 #ifdef DBG
1479 InterlockedIncrement((LONG volatile *)&ovsPool->fragNBLCount);
1480
1481 OvsDumpNetBufferList(nbl);
1482 OvsDumpForwardingDetails(nbl);
1483
1484 OvsDumpNetBufferList(newNbl);
1485 OvsDumpForwardingDetails(newNbl);
1486 #endif
1487 OVS_LOG_TRACE("Fragment nbl %p to newNbl: %p", nbl, newNbl);
1488 return newNbl;
1489
1490 nbl_context_error:
1491 OvsFreeNBLContext(context, newNbl);
1492 nblcopy_error:
1493 #ifdef DBG
1494 InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
1495 #endif
1496 NdisFreeFragmentNetBufferList(newNbl, hdrSize + headRoom, 0);
1497 return NULL;
1498 }
1499
1500 /*
1501 * --------------------------------------------------------------------------
1502 * OvsAllocateNBLFromBuffer --
1503 *
1504 * This function allocates all the stuff necessary for creating an NBL from the
1505 * input buffer of specified length, namely, a nonpaged data buffer of size
1506 * length, an MDL from it, and a NB and NBL from it. It does not allocate an NBL
1507 * context yet. It also copies data from the specified buffer to the NBL.
1508 * --------------------------------------------------------------------------
1509 */
1510 PNET_BUFFER_LIST
1511 OvsAllocateNBLFromBuffer(PVOID context,
1512 PVOID buffer,
1513 ULONG length)
1514 {
1515 POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)context;
1516 UINT8 *data = NULL;
1517 PNET_BUFFER_LIST nbl = NULL;
1518 PNET_BUFFER nb;
1519 PMDL mdl;
1520
1521 if (length > OVS_DEFAULT_DATA_SIZE) {
1522 nbl = OvsAllocateVariableSizeNBL(switchContext, length,
1523 OVS_DEFAULT_HEADROOM_SIZE);
1524
1525 } else {
1526 nbl = OvsAllocateFixSizeNBL(switchContext, length,
1527 OVS_DEFAULT_HEADROOM_SIZE);
1528 }
1529 if (nbl == NULL) {
1530 return NULL;
1531 }
1532
1533 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1534 mdl = NET_BUFFER_CURRENT_MDL(nb);
1535 data = (PUINT8)OvsGetMdlWithLowPriority(mdl)
1536 + NET_BUFFER_CURRENT_MDL_OFFSET(nb);
1537 if (!data) {
1538 OvsCompleteNBL(switchContext, nbl, TRUE);
1539 return NULL;
1540 }
1541
1542 NdisMoveMemory(data, buffer, length);
1543
1544 return nbl;
1545 }
1546
1547 /*
1548 * --------------------------------------------------------------------------
1549 * OvsFullCopyToMultipleNBLs --
1550 *
1551 * Copy NBL to multiple NBLs, each NB will have its own NBL
1552 * --------------------------------------------------------------------------
1553 */
1554 PNET_BUFFER_LIST
1555 OvsFullCopyToMultipleNBLs(PVOID ovsContext,
1556 PNET_BUFFER_LIST nbl,
1557 UINT32 headRoom,
1558 BOOLEAN copyNblInfo)
1559 {
1560
1561 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
1562 PNET_BUFFER_LIST firstNbl, currNbl, newNbl;
1563 PNET_BUFFER nb;
1564 POVS_BUFFER_CONTEXT srcCtx;
1565
1566 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1567 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
1568 OVS_LOG_INFO("src nbl must have ctx initialized");
1569 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
1570 return NULL;
1571 }
1572
1573 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1574 newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
1575
1576 if (newNbl == NULL || NET_BUFFER_NEXT_NB(nb) == NULL) {
1577 return newNbl;
1578 } else {
1579 firstNbl = newNbl;
1580 currNbl = newNbl;
1581 }
1582
1583 while (nb) {
1584 newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom,
1585 copyNblInfo);
1586 if (newNbl == NULL) {
1587 goto copymultiple_error;
1588 }
1589 NET_BUFFER_LIST_NEXT_NBL(currNbl) = newNbl;
1590 currNbl = newNbl;
1591 nb = NET_BUFFER_NEXT_NB(nb);
1592 }
1593 return firstNbl;
1594
1595 copymultiple_error:
1596 while (firstNbl) {
1597 currNbl = firstNbl;
1598 firstNbl = NET_BUFFER_LIST_NEXT_NBL(firstNbl);
1599 NET_BUFFER_LIST_NEXT_NBL(currNbl) = NULL;
1600 OvsCompleteNBL(context, currNbl, TRUE);
1601 }
1602 return NULL;
1603
1604 }
1605
1606
1607 /*
1608 * --------------------------------------------------------------------------
1609 * OvsCompleteNBL --
1610 *
1611 * This function tries to free the NBL allocated by OVS buffer
1612 * management module. If it trigger the completion of the parent
1613 * NBL, it will recursively call itself. If it trigger the completion
1614 * of external NBL, it will be returned to the caller. The caller
1615 * is responsible to call API to return to upper layer.
1616 * --------------------------------------------------------------------------
1617 */
1618 PNET_BUFFER_LIST
1619 OvsCompleteNBL(PVOID switch_ctx,
1620 PNET_BUFFER_LIST nbl,
1621 BOOLEAN updateRef)
1622 {
1623 POVS_BUFFER_CONTEXT ctx;
1624 UINT16 flags;
1625 PNET_BUFFER_LIST parent;
1626 NDIS_STATUS status;
1627 NDIS_HANDLE poolHandle;
1628 LONG value;
1629 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)switch_ctx;
1630 POVS_NBL_POOL ovsPool = &context->ovsPool;
1631 PNET_BUFFER nb;
1632
1633
1634 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1635
1636 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1637
1638 OVS_LOG_TRACE("Enter: nbl: %p, ctx: %p, refCount: %d, updateRef:%d",
1639 nbl, ctx, ctx->refCount, updateRef);
1640
1641 if (updateRef) {
1642 value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
1643 if (value != 0) {
1644 return NULL;
1645 }
1646 } else {
1647 /*
1648 * This is a special case, the refCount must be zero
1649 */
1650 ASSERT(ctx->refCount == 0);
1651 }
1652
1653 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1654
1655 flags = ctx->flags;
1656 if (!(flags & OVS_BUFFER_FRAGMENT) &&
1657 NET_BUFFER_DATA_LENGTH(nb) != ctx->origDataLength) {
1658 UINT32 diff;
1659 if (NET_BUFFER_DATA_LENGTH(nb) < ctx->origDataLength) {
1660 diff = ctx->origDataLength -NET_BUFFER_DATA_LENGTH(nb);
1661 status = NdisRetreatNetBufferListDataStart(nbl, diff, 0,
1662 NULL, NULL);
1663 ASSERT(status == NDIS_STATUS_SUCCESS);
1664 } else {
1665 diff = NET_BUFFER_DATA_LENGTH(nb) - ctx->origDataLength;
1666 NdisAdvanceNetBufferListDataStart(nbl, diff, TRUE, NULL);
1667 }
1668 }
1669
1670 if (ctx->flags & OVS_BUFFER_PRIVATE_CONTEXT) {
1671 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
1672 }
1673
1674 if (flags & OVS_BUFFER_NEED_COMPLETE) {
1675 /*
1676 * return to caller for completion
1677 */
1678 #ifdef DBG
1679 InterlockedDecrement((LONG volatile *)&ovsPool->sysNBLCount);
1680 #endif
1681 return nbl;
1682 }
1683
1684 if (flags & OVS_BUFFER_PRIVATE_FORWARD_CONTEXT) {
1685 context->NdisSwitchHandlers.
1686 FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
1687 }
1688
1689 if (flags & (OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA)) {
1690 PNET_BUFFER nbTemp = NET_BUFFER_LIST_FIRST_NB(nbl);
1691 while (nbTemp) {
1692 PMDL mdl = NET_BUFFER_FIRST_MDL(nbTemp);
1693 if (mdl) {
1694 ASSERT(mdl->Next == NULL);
1695 OvsFreeMDLAndData(mdl);
1696 }
1697 NET_BUFFER_FIRST_MDL(nbTemp) = NULL;
1698 nbTemp = NET_BUFFER_NEXT_NB(nbTemp);
1699 }
1700 }
1701
1702 if (flags & OVS_BUFFER_PRIVATE_NET_BUFFER) {
1703 PNET_BUFFER nbTemp, nextNb;
1704
1705 nbTemp = NET_BUFFER_LIST_FIRST_NB(nbl);
1706 while (nbTemp) {
1707 nextNb = NET_BUFFER_NEXT_NB(nbTemp);
1708 NdisFreeNetBuffer(nbTemp);
1709 #ifdef DBG
1710 InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
1711 #endif
1712 nbTemp = nextNb;
1713 }
1714 NET_BUFFER_LIST_FIRST_NB(nbl) = NULL;
1715 }
1716
1717 parent = nbl->ParentNetBufferList;
1718
1719 poolHandle = NdisGetPoolFromNetBufferList(nbl);
1720 if (flags & OVS_BUFFER_FROM_FIX_SIZE_POOL) {
1721 ASSERT(poolHandle == ovsPool->fixSizePool);
1722 #ifdef DBG
1723 InterlockedDecrement((LONG volatile *)&ovsPool->fixNBLCount);
1724 #endif
1725 NdisFreeNetBufferList(nbl);
1726 } else if (flags & OVS_BUFFER_FROM_ZERO_SIZE_POOL) {
1727 ASSERT(poolHandle == ovsPool->zeroSizePool);
1728 #ifdef DBG
1729 InterlockedDecrement((LONG volatile *)&ovsPool->zeroNBLCount);
1730 #endif
1731 NdisFreeNetBufferList(nbl);
1732 } else if (flags & OVS_BUFFER_FROM_NBL_ONLY_POOL) {
1733 ASSERT(poolHandle == ovsPool->nblOnlyPool);
1734 #ifdef DBG
1735 InterlockedDecrement((LONG volatile *)&ovsPool->nblOnlyCount);
1736 #endif
1737 NdisFreeCloneNetBufferList(nbl, 0);
1738 } else if (flags & OVS_BUFFER_FRAGMENT) {
1739 OVS_LOG_TRACE("Free fragment %p parent %p", nbl, parent);
1740 #ifdef DBG
1741 InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
1742 #endif
1743 NdisFreeFragmentNetBufferList(nbl, ctx->dataOffsetDelta, 0);
1744 }
1745
1746 if (parent != NULL) {
1747 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(parent);
1748 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1749 value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
1750 if (value == 0) {
1751 return OvsCompleteNBL(context, parent, FALSE);
1752 }
1753 }
1754 return NULL;
1755 }
1756
1757 /*
1758 * --------------------------------------------------------------------------
1759 * OvsSetCtxSourcePortNo --
1760 * Setter function which stores the source port of an NBL in the NBL
1761 * Context Info.
1762 * --------------------------------------------------------------------------
1763 */
1764 NDIS_STATUS
1765 OvsSetCtxSourcePortNo(PNET_BUFFER_LIST nbl,
1766 UINT32 portNo)
1767 {
1768 POVS_BUFFER_CONTEXT ctx;
1769 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1770 if (ctx == NULL) {
1771 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1772 return STATUS_INVALID_PARAMETER;
1773 }
1774
1775 ctx->srcPortNo = portNo;
1776 return NDIS_STATUS_SUCCESS;
1777 }
1778
1779 /*
1780 * --------------------------------------------------------------------------
1781 * OvsGetCtxSourcePortNo --
1782 * Get source port of an NBL from its Context Info.
1783 * --------------------------------------------------------------------------
1784 */
1785 NDIS_STATUS
1786 OvsGetCtxSourcePortNo(PNET_BUFFER_LIST nbl,
1787 UINT32 *portNo)
1788 {
1789 POVS_BUFFER_CONTEXT ctx;
1790 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1791 if (ctx == NULL || portNo == NULL) {
1792 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1793 return STATUS_INVALID_PARAMETER;
1794 }
1795 *portNo = ctx->srcPortNo;
1796 return NDIS_STATUS_SUCCESS;
1797 }
1798
1799 /*
1800 * --------------------------------------------------------------------------
1801 * OvsCreateNewNBLsFromMultipleNBs --
1802 * Creates an NBL chain where each NBL has a single NB,
1803 * from an NBL which has multiple NBs.
1804 * Sets 'curNbl' and 'lastNbl' to the first and last NBL in the
1805 * newly created NBL chain respectively, and completes the original NBL.
1806 * --------------------------------------------------------------------------
1807 */
1808 NTSTATUS
1809 OvsCreateNewNBLsFromMultipleNBs(POVS_SWITCH_CONTEXT switchContext,
1810 PNET_BUFFER_LIST *curNbl,
1811 PNET_BUFFER_LIST *lastNbl)
1812 {
1813 NTSTATUS status = STATUS_SUCCESS;
1814 PNET_BUFFER_LIST newNbls = NULL;
1815 PNET_BUFFER_LIST nbl = NULL;
1816 BOOLEAN error = TRUE;
1817
1818 do {
1819 /* Create new NBLs from curNbl with multiple net buffers. */
1820 newNbls = OvsPartialCopyToMultipleNBLs(switchContext,
1821 *curNbl, 0, 0, TRUE);
1822 if (NULL == newNbls) {
1823 OVS_LOG_ERROR("Failed to allocate NBLs with single NB.");
1824 status = NDIS_STATUS_RESOURCES;
1825 break;
1826 }
1827
1828 nbl = newNbls;
1829 while (nbl) {
1830 *lastNbl = nbl;
1831 nbl = NET_BUFFER_LIST_NEXT_NBL(nbl);
1832 }
1833
1834 (*curNbl)->Next = NULL;
1835
1836 OvsCompleteNBL(switchContext, *curNbl, TRUE);
1837
1838 *curNbl = newNbls;
1839
1840 error = FALSE;
1841 } while (error);
1842
1843 return status;
1844 }