2 * Copyright (c) 2014, 2016 VMware, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * ****************************************************************************
20 * Simple Buffer Management framework for OVS
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.
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.
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.
34 * **Net buffer pool-- this is required when net buffer need to be
35 * allocated separately.
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
41 * Here is the usage of the management API
42 * All external NBL should be initialized its NBL context by calling
43 * OvsInitExternalNBLContext()
45 * After the external NBL context is initialized, it can call the following
46 * API to allocate, copy or partial copy NBL.
48 * OvsAllocateFixSizeNBL()
49 * OvsAllocateVariableSizeNBL()
52 * OvsPartialCopyToMultipleNBLs()
55 * OvsFullCopyToMultipleNBLs()
57 * See code comments for detail description of the functions.
59 * All NBLs is completed through
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.
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.
76 * ****************************************************************************
84 #include "PacketParser.h"
91 #define OVS_DBG_MOD OVS_DBG_BUFMGMT
95 * --------------------------------------------------------------------------
96 * OvsInitBufferPool --
98 * Allocate NBL and NB pool
100 * XXX: more optimization may be done for buffer management include local cache
101 * of NBL, NB, data, context, MDL.
102 * --------------------------------------------------------------------------
105 OvsInitBufferPool(PVOID ovsContext)
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;
112 C_ASSERT(MEMORY_ALLOCATION_ALIGNMENT >= 8);
114 OVS_LOG_TRACE("Enter: context: %p", context);
116 ovsPool = &context->ovsPool;
117 RtlZeroMemory(ovsPool, sizeof (OVS_NBL_POOL));
118 ovsPool->ndisHandle = context->NdisFilterHandle;
119 ovsPool->ndisContext = context->NdisSwitchContext;
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.
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;
138 ovsPool->fixSizePool =
139 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
140 if (ovsPool->fixSizePool == NULL) {
145 * Zero Size NBL Pool includes
147 * This is mainly for packet with large data Size, in this case MDL and
148 * Data will be allocate separately.
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);
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;
161 ovsPool->zeroSizePool =
162 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
163 if (ovsPool->zeroSizePool == NULL) {
168 * NBL only pool just includes
170 * This is mainly used for clone and partial copy
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);
178 nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE;
179 nblParam.PoolTag = OVS_NBL_ONLY_POOL_TAG;
180 nblParam.fAllocateNetBuffer = FALSE;
181 nblParam.DataSize = 0;
183 ovsPool->nblOnlyPool =
184 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
185 if (ovsPool->nblOnlyPool == NULL) {
190 * NB only pool, used for copy
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;
200 NdisAllocateNetBufferPool(context->NdisSwitchContext, &nbParam);
201 if (ovsPool->nbPool == NULL) {
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;
210 OvsCleanupBufferPool(context);
211 OVS_LOG_TRACE("Exit: Fail to initialize ovs buffer pool");
212 return NDIS_STATUS_RESOURCES;
217 * --------------------------------------------------------------------------
218 * OvsCleanupBufferPool --
219 * Free Buffer pool for NBL and NB.
220 * --------------------------------------------------------------------------
223 OvsCleanupBufferPool(PVOID ovsContext)
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);
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);
238 if (ovsPool->fixSizePool) {
239 NdisFreeNetBufferListPool(ovsPool->fixSizePool);
240 ovsPool->fixSizePool = NULL;
242 if (ovsPool->zeroSizePool) {
243 NdisFreeNetBufferListPool(ovsPool->zeroSizePool);
244 ovsPool->zeroSizePool = NULL;
246 if (ovsPool->nblOnlyPool) {
247 NdisFreeNetBufferListPool(ovsPool->nblOnlyPool);
248 ovsPool->nblOnlyPool = NULL;
250 if (ovsPool->nbPool) {
251 NdisFreeNetBufferPool(ovsPool->nbPool);
252 ovsPool->nbPool = NULL;
254 OVS_LOG_TRACE("Exit: cleanup OVS Buffer pool");
259 OvsInitNBLContext(POVS_BUFFER_CONTEXT ctx,
261 UINT32 origDataLength,
264 ctx->magic = OVS_CTX_MAGIC;
267 ctx->srcPortNo = srcPortNo;
268 ctx->origDataLength = origDataLength;
273 OvsDumpForwardingDetails(PNET_BUFFER_LIST nbl)
275 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
276 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
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);
290 OvsDumpNBLContext(PNET_BUFFER_LIST nbl)
292 PNET_BUFFER_LIST_CONTEXT ctx = nbl->Context;
294 OVS_LOG_INFO("No Net Buffer List context");
298 OVS_LOG_INFO("nbl: %p, ctx: %p, TotalSize: %d, Offset: %d",
299 nbl, ctx, ctx->Size, ctx->Offset);
306 OvsDumpMDLChain(PMDL mdl)
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);
321 OvsDumpNetBuffer(PNET_BUFFER nb)
323 OVS_LOG_INFO("NET_BUFFER: %p, ChecksumBias: %d Handle: %p, MDLChain: %p "
324 "CurrMDL: %p, CurrOffset: %d, DataLen: %d, Offset: %d",
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));
337 OvsDumpNetBufferList(PNET_BUFFER_LIST nbl)
340 OVS_LOG_INFO("NBL: %p, parent: %p, SrcHandle: %p, ChildCount:%d "
342 nbl, nbl->ParentNetBufferList,
343 nbl->SourceHandle, nbl->ChildRefCount,
344 nbl->NdisPoolHandle);
345 OvsDumpNBLContext(nbl);
346 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
348 OvsDumpNetBuffer(nb);
349 nb = NET_BUFFER_NEXT_NB(nb);
354 * --------------------------------------------------------------------------
355 * OvsAllocateFixSizeNBL --
357 * Allocate fix size NBL which include
358 * NBL + NB + MBL + Data + Context
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
364 * --------------------------------------------------------------------------
367 OvsAllocateFixSizeNBL(PVOID ovsContext,
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;
377 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
379 if ((headRoom + size) > OVS_FIX_NBL_DATA_SIZE || size == 0) {
384 nbl = NdisAllocateNetBufferList(ovsPool->fixSizePool,
385 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
386 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
393 nbl->SourceHandle = ovsPool->ndisHandle;
394 status = context->NdisSwitchHandlers.
395 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
397 if (status != NDIS_STATUS_SUCCESS) {
398 NdisFreeNetBufferList(nbl);
403 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
405 info->IsPacketDataSafe = TRUE;
406 info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
408 status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
410 ASSERT(status == NDIS_STATUS_SUCCESS);
413 InterlockedIncrement((LONG volatile *)&ovsPool->fixNBLCount);
414 OvsDumpNetBufferList(nbl);
415 OvsDumpForwardingDetails(nbl);
418 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
421 OvsInitNBLContext(ctx, OVS_BUFFER_FROM_FIX_SIZE_POOL |
422 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT, size,
423 OVS_DPPORT_NUMBER_INVALID);
426 OVS_LOG_LOUD("Allocate Fix NBL: %p, line: %d", nbl, line);
432 OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle,
438 data = OvsAllocateMemoryWithTag(dataSize, OVS_MDL_POOL_TAG);
443 mdl = NdisAllocateMdl(ndisHandle, data, dataSize);
445 OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
453 OvsFreeMDLAndData(PMDL mdl)
457 data = MmGetMdlVirtualAddress(mdl);
459 OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
464 * --------------------------------------------------------------------------
465 * OvsAllocateVariableSizeNBL --
467 * Allocate variable size NBL, the NBL looks like
470 * --------------------------------------------------------------------------
473 OvsAllocateVariableSizeNBL(PVOID ovsContext,
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;
484 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
488 realSize = MEM_ALIGN_SIZE(size + headRoom);
490 mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, realSize);
495 nbl = NdisAllocateNetBufferAndNetBufferList(ovsPool->zeroSizePool,
496 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
497 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL,
500 OvsFreeMDLAndData(mdl);
504 nbl->SourceHandle = ovsPool->ndisHandle;
505 status = context->NdisSwitchHandlers.
506 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
508 if (status != NDIS_STATUS_SUCCESS) {
510 * do we need to remove mdl from nbl XXX
512 OvsFreeMDLAndData(mdl);
513 NdisFreeNetBufferList(nbl);
517 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
519 info->IsPacketDataSafe = TRUE;
520 info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
521 status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
523 ASSERT(status == NDIS_STATUS_SUCCESS);
526 InterlockedIncrement((LONG volatile *)&ovsPool->zeroNBLCount);
527 OvsDumpNetBufferList(nbl);
528 OvsDumpForwardingDetails(nbl);
531 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
533 OvsInitNBLContext(ctx, OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
534 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT |
535 OVS_BUFFER_FROM_ZERO_SIZE_POOL,
536 size, OVS_DPPORT_NUMBER_INVALID);
538 OVS_LOG_LOUD("Allocate variable size NBL: %p", nbl);
544 * --------------------------------------------------------------------------
545 * OvsInitExternalNBLContext --
547 * For NBL not allocated by OVS, it will allocate and initialize
549 * --------------------------------------------------------------------------
552 OvsInitExternalNBLContext(PVOID ovsContext,
553 PNET_BUFFER_LIST nbl,
556 NDIS_HANDLE poolHandle;
557 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
558 POVS_BUFFER_CONTEXT ctx;
563 poolHandle = NdisGetPoolFromNetBufferList(nbl);
565 if (poolHandle == context->ovsPool.ndisHandle ||
566 nbl->SourceHandle == context->ovsPool.ndisHandle) {
567 return (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
569 status = NdisAllocateNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT),
570 OVS_DEFAULT_NBL_CONTEXT_FILL,
572 if (status != NDIS_STATUS_SUCCESS) {
576 OvsDumpNBLContext(nbl);
577 InterlockedIncrement((LONG volatile *)&context->ovsPool.sysNBLCount);
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);
583 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
585 * we use first nb to decide whether we need advance or retreat during
588 OvsInitNBLContext(ctx, flags, NET_BUFFER_DATA_LENGTH(nb),
589 OVS_DPPORT_NUMBER_INVALID);
594 * --------------------------------------------------------------------------
595 * OvsAllocateNBLContext
597 * Create NBL buffer context and forwarding context.
598 * --------------------------------------------------------------------------
601 OvsAllocateNBLContext(POVS_SWITCH_CONTEXT context,
602 PNET_BUFFER_LIST nbl)
604 POVS_NBL_POOL ovsPool = &context->ovsPool;
607 status = NdisAllocateNetBufferListContext(nbl,
608 sizeof (OVS_BUFFER_CONTEXT),
609 OVS_DEFAULT_NBL_CONTEXT_FILL,
611 if (status != NDIS_STATUS_SUCCESS) {
612 return NDIS_STATUS_FAILURE;
615 nbl->SourceHandle = ovsPool->ndisHandle;
616 status = context->NdisSwitchHandlers.
617 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
619 if (status != NDIS_STATUS_SUCCESS) {
620 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
621 return NDIS_STATUS_FAILURE;
627 * --------------------------------------------------------------------------
630 * Free the NBL buffer context and forwarding context.
631 * --------------------------------------------------------------------------
634 OvsFreeNBLContext(POVS_SWITCH_CONTEXT context,
635 PNET_BUFFER_LIST nbl)
637 POVS_NBL_POOL ovsPool = &context->ovsPool;
639 context->NdisSwitchHandlers.
640 FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
641 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
643 return NDIS_STATUS_SUCCESS;
647 * --------------------------------------------------------------------------
650 * Copy NBL info from src to dst
651 * --------------------------------------------------------------------------
654 OvsCopyNBLInfo(PNET_BUFFER_LIST srcNbl, PNET_BUFFER_LIST dstNbl,
655 POVS_BUFFER_CONTEXT srcCtx, UINT32 copySize,
658 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO srcInfo, dstInfo;
659 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
661 srcInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(srcNbl);
662 dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(dstNbl);
664 #ifdef OVS_USE_COPY_NET_BUFFER_LIST_INFO
665 status = context->NdisSwitchHandlers.
666 CopyNetBufferListInfo(ovsPool->ndisContext, dstNbl, srcNbl, 0);
668 if (status != NDIS_STATUS_SUCCESS) {
672 dstInfo->SourcePortId = srcInfo->SourcePortId;
673 dstInfo->SourceNicIndex = srcInfo->SourceNicIndex;
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);
682 dstInfo->IsPacketDataSafe = srcInfo->IsPacketDataSafe;
683 if (!srcInfo->IsPacketDataSafe && copySize >
684 srcInfo->SafePacketDataSize) {
685 srcInfo->SafePacketDataSize = copySize;
689 * Assume all data are safe
691 dstInfo->IsPacketDataSafe = TRUE;
692 dstInfo->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
698 * --------------------------------------------------------------------------
699 * OvsPartialCopyNBL --
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.
705 * NBL should have OVS_BUFFER_CONTEXT setup before calling
707 * The NBL should already have ref to itself so that during copy
708 * it will not be freed.
709 * --------------------------------------------------------------------------
712 OvsPartialCopyNBL(PVOID ovsContext,
713 PNET_BUFFER_LIST nbl,
718 PNET_BUFFER_LIST newNbl;
719 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
721 PNET_BUFFER srcNb, dstNb;
723 POVS_NBL_POOL ovsPool = &context->ovsPool;
724 POVS_BUFFER_CONTEXT srcCtx, dstCtx;
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);
735 NdisAdvanceNetBufferListDataStart(nbl, copySize, FALSE, NULL);
737 newNbl = NdisAllocateCloneNetBufferList(nbl, ovsPool->nblOnlyPool,
740 status = NdisRetreatNetBufferListDataStart(nbl, copySize, 0,
742 ASSERT(status == NDIS_STATUS_SUCCESS);
745 if (newNbl == NULL) {
750 * Allocate private memory for copy
752 if (copySize + headRoom) {
753 status = NdisRetreatNetBufferListDataStart(newNbl, copySize + headRoom,
755 if (status != NDIS_STATUS_SUCCESS) {
760 NdisAdvanceNetBufferListDataStart(newNbl, headRoom, FALSE, NULL);
763 srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
764 dstNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
767 status = NdisCopyFromNetBufferToNetBuffer(dstNb, 0, copySize,
770 if (status != NDIS_STATUS_SUCCESS || copySize != byteCopied) {
771 goto nbl_context_error;
773 srcNb = NET_BUFFER_NEXT_NB(srcNb);
774 dstNb = NET_BUFFER_NEXT_NB(dstNb);
779 status = OvsAllocateNBLContext(context, newNbl);
780 if (status != NDIS_STATUS_SUCCESS) {
781 goto nbl_context_error;
784 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copySize, copyNblInfo);
785 if (status != NDIS_STATUS_SUCCESS) {
786 goto copy_list_info_error;
790 InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
793 newNbl->ParentNetBufferList = nbl;
795 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
796 ASSERT(dstCtx != NULL);
798 flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
800 flags |= OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_CONTEXT |
801 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;
803 srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
804 OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(srcNb) - copySize,
805 OVS_DPPORT_NUMBER_INVALID);
807 InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
810 OvsDumpNetBufferList(nbl);
811 OvsDumpForwardingDetails(nbl);
813 OvsDumpNetBufferList(newNbl);
814 OvsDumpForwardingDetails(newNbl);
817 OVS_LOG_LOUD("Partial Copy new NBL: %p", newNbl);
820 copy_list_info_error:
821 OvsFreeNBLContext(context, newNbl);
824 NdisAdvanceNetBufferListDataStart(newNbl, copySize, TRUE, NULL);
827 NdisFreeCloneNetBufferList(newNbl, 0);
832 * --------------------------------------------------------------------------
833 * OvsPartialCopyToMultipleNBLs --
835 * This is similar to OvsPartialCopyNBL() except that each NB will
837 * --------------------------------------------------------------------------
840 OvsPartialCopyToMultipleNBLs(PVOID ovsContext,
841 PNET_BUFFER_LIST nbl,
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;
850 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
851 if (NET_BUFFER_NEXT_NB(nb) == NULL) {
852 return OvsPartialCopyNBL(context, nbl, copySize, headRoom, copyNblInfo);
859 nextNb = NET_BUFFER_NEXT_NB(nb);
860 NET_BUFFER_NEXT_NB(nb) = NULL;
862 NET_BUFFER_LIST_FIRST_NB(nbl) = nb;
864 newNbl = OvsPartialCopyNBL(context, nbl, copySize, headRoom,
866 if (newNbl == NULL) {
869 if (prevNbl == NULL) {
872 NET_BUFFER_LIST_NEXT_NBL(prevNbl) = newNbl;
873 NET_BUFFER_NEXT_NB(prevNb) = nb;
879 NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;
883 NET_BUFFER_NEXT_NB(prevNb) = nb;
884 NET_BUFFER_NEXT_NB(nb) = nextNb;
885 NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;
889 firstNbl = NET_BUFFER_LIST_NEXT_NBL(newNbl);
890 NET_BUFFER_LIST_NEXT_NBL(newNbl) = NULL;
891 OvsCompleteNBL(context, newNbl, TRUE);
898 static PNET_BUFFER_LIST
899 OvsCopySinglePacketNBL(PVOID ovsContext,
900 PNET_BUFFER_LIST nbl,
907 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
908 PNET_BUFFER_LIST newNbl;
911 POVS_BUFFER_CONTEXT srcCtx, dstCtx;
913 size = NET_BUFFER_DATA_LENGTH(nb);
914 if ((size + headRoom) <= OVS_FIX_NBL_DATA_SIZE) {
915 newNbl = OvsAllocateFixSizeNBL(context, size, headRoom);
917 newNbl = OvsAllocateVariableSizeNBL(context, size, headRoom);
919 if (newNbl == NULL) {
922 newNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
923 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
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);
931 if (status != NDIS_STATUS_SUCCESS || copiedSize != size) {
932 OvsCompleteNBL(context, newNbl, TRUE);
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);
940 dstCtx->flags |= srcCtx->flags & (OVS_BUFFER_RECV_BUFFER |
941 OVS_BUFFER_SEND_BUFFER);
943 OvsDumpNetBufferList(newNbl);
944 OvsDumpForwardingDetails(newNbl);
946 OVS_LOG_LOUD("Copy single nb to new NBL: %p", newNbl);
951 * --------------------------------------------------------------------------
954 * Copy the NBL to a new NBL including data.
957 * The NBL can have multiple NBs, but the final result is one NBL.
958 * --------------------------------------------------------------------------
961 OvsFullCopyNBL(PVOID ovsContext,
962 PNET_BUFFER_LIST nbl,
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;
973 UINT32 size, totalSize;
976 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo;
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);
985 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
987 if (NET_BUFFER_NEXT_NB(nb) == NULL) {
988 return OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
991 newNbl = NdisAllocateNetBufferList(ovsPool->nblOnlyPool,
992 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
993 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
994 if (newNbl == NULL) {
999 size = NET_BUFFER_DATA_LENGTH(nb);
1000 totalSize = MEM_ALIGN_SIZE(size + headRoom);
1001 mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, totalSize);
1006 newNb = NdisAllocateNetBuffer(ovsPool->nbPool, mdl, totalSize, 0);
1007 if (newNb == NULL) {
1008 OvsFreeMDLAndData(mdl);
1011 if (firstNb == NULL) {
1014 NET_BUFFER_NEXT_NB(prevNb) = newNb;
1018 InterlockedIncrement((LONG volatile *)&ovsPool->nbCount);
1020 status = NdisRetreatNetBufferDataStart(newNb, size, 0, NULL);
1021 ASSERT(status == NDIS_STATUS_SUCCESS);
1023 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
1025 if (status != NDIS_STATUS_SUCCESS || size != copiedSize) {
1029 nb = NET_BUFFER_NEXT_NB(nb);
1032 NET_BUFFER_LIST_FIRST_NB(newNbl) = firstNb;
1034 newNbl->SourceHandle = ovsPool->ndisHandle;
1035 status = context->NdisSwitchHandlers.
1036 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, newNbl);
1038 if (status != NDIS_STATUS_SUCCESS) {
1042 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, 0, copyNblInfo);
1043 if (status != NDIS_STATUS_SUCCESS) {
1047 dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl);
1048 dstInfo->IsPacketDataSafe = TRUE;
1050 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
1052 flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
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;
1058 OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(firstNb),
1059 OVS_DPPORT_NUMBER_INVALID);
1062 OvsDumpNetBufferList(nbl);
1063 OvsDumpForwardingDetails(nbl);
1064 InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
1066 OVS_LOG_LOUD("newNbl: %p", newNbl);
1072 InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
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);
1081 NdisFreeNetBufferList(newNbl);
1082 OVS_LOG_ERROR("OvsFullCopyNBL failed");
1087 * --------------------------------------------------------------------------
1088 * GetSegmentHeaderInfo
1090 * Extract header size and sequence number for the segment.
1091 * --------------------------------------------------------------------------
1094 GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl,
1095 const POVS_PACKET_HDR_INFO hdrInfo,
1096 UINT32 *hdrSize, UINT32 *seqNumber)
1101 /* Parse the orginal Eth/IP/TCP header */
1102 tcp = OvsGetPacketBytes(nbl, sizeof *tcp, hdrInfo->l4Offset, &tcpStorage);
1104 return NDIS_STATUS_FAILURE;
1106 *seqNumber = ntohl(tcp->seq);
1107 *hdrSize = hdrInfo->l4Offset + TCP_HDR_LEN(tcp);
1109 return NDIS_STATUS_SUCCESS;
1114 * --------------------------------------------------------------------------
1117 * Fix IP length, IP checksum, TCP sequence number and TCP checksum
1119 * --------------------------------------------------------------------------
1122 FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
1123 BOOLEAN lastPacket, UINT16 packetCounter)
1131 mdl = NET_BUFFER_FIRST_MDL(nb);
1133 bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(mdl, LowPagePriority);
1135 return NDIS_STATUS_RESOURCES;
1137 dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb));
1138 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1139 >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr));
1140 dstIP = (IPHdr *)((PCHAR)dstEth + sizeof *dstEth);
1141 dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4);
1142 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1143 >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
1145 /* Fix IP length and checksum */
1146 ASSERT(dstIP->protocol == IPPROTO_TCP);
1147 dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
1148 dstIP->id += packetCounter;
1150 dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);
1152 /* Fix TCP checksum */
1153 dstTCP->seq = htonl(seqNumber);
1156 * Set the TCP FIN and PSH bit only for the last packet
1157 * More information can be found under:
1158 * https://msdn.microsoft.com/en-us/library/windows/hardware/ff568840%28v=vs.85%29.aspx
1161 dstTCP->fin = lastPacket;
1164 dstTCP->psh = lastPacket;
1167 UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP);
1168 dstTCP->check = IPPseudoChecksum(&dstIP->saddr,
1172 dstTCP->check = CalculateChecksumNB(nb,
1174 sizeof *dstEth + dstIP->ihl * 4);
1176 return STATUS_SUCCESS;
1180 * --------------------------------------------------------------------------
1181 * OvsTcpSegmentyNBL --
1183 * Segment TCP payload, and prepend each segment with ether/IP/TCP header.
1184 * Leave headRoom for additional encap.
1187 * NBL should have OVS_BUFFER_CONTEXT setup before calling
1189 * The NBL should already have ref to itself so that during copy
1190 * it will not be freed.
1191 * Currently this API assert there is only one NB in an NBL, it needs
1192 * to be fixed if we receive multiple NBs in an NBL.
1193 * --------------------------------------------------------------------------
1196 OvsTcpSegmentNBL(PVOID ovsContext,
1197 PNET_BUFFER_LIST nbl,
1198 POVS_PACKET_HDR_INFO hdrInfo,
1202 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
1204 POVS_NBL_POOL ovsPool = &context->ovsPool;
1206 POVS_BUFFER_CONTEXT dstCtx, srcCtx;
1207 UINT32 size, hdrSize, seqNumber;
1208 PNET_BUFFER_LIST newNbl;
1209 PNET_BUFFER nb, newNb;
1213 UINT16 packetCounter = 0;
1215 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1216 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
1217 OVS_LOG_INFO("src nbl must have ctx initialized");
1218 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
1222 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1223 ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL);
1225 /* Figure out the segment header size */
1226 status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber);
1227 if (status != NDIS_STATUS_SUCCESS) {
1228 OVS_LOG_INFO("Cannot parse NBL header");
1232 size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize;
1234 /* XXX add to ovsPool counters? */
1235 newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL,
1236 NULL, hdrSize, mss, hdrSize + headRoom , 0, 0);
1237 if (newNbl == NULL) {
1241 /* Now deal with TCP payload */
1242 for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL;
1243 newNb = NET_BUFFER_NEXT_NB(newNb)) {
1244 segmentSize = (size > mss ? mss : size) & 0xffff;
1246 NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL);
1249 /* Now copy the eth/IP/TCP header and fix up */
1250 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize, nb, 0,
1252 if (status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize) {
1256 status = FixSegmentHeader(newNb, segmentSize, seqNumber,
1257 NET_BUFFER_NEXT_NB(newNb) == NULL,
1259 if (status != NDIS_STATUS_SUCCESS) {
1264 /* Move on to the next segment */
1265 size -= segmentSize;
1266 seqNumber += segmentSize;
1270 status = OvsAllocateNBLContext(context, newNbl);
1271 if (status != NDIS_STATUS_SUCCESS) {
1275 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, hdrSize + headRoom, FALSE);
1276 if (status != NDIS_STATUS_SUCCESS) {
1277 goto nbl_context_error;
1280 newNbl->ParentNetBufferList = nbl;
1282 /* Remember it's a fragment NBL so we can free it properly */
1283 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
1284 ASSERT(dstCtx != NULL);
1285 dstCtx->flags = OVS_BUFFER_FRAGMENT | OVS_BUFFER_PRIVATE_CONTEXT |
1286 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | OVS_BUFFER_SEND_BUFFER;
1287 dstCtx->refCount = 1;
1288 dstCtx->magic = OVS_CTX_MAGIC;
1289 dstCtx->dataOffsetDelta = hdrSize + headRoom;
1291 InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
1293 InterlockedIncrement((LONG volatile *)&ovsPool->fragNBLCount);
1295 OvsDumpNetBufferList(nbl);
1296 OvsDumpForwardingDetails(nbl);
1298 OvsDumpNetBufferList(newNbl);
1299 OvsDumpForwardingDetails(newNbl);
1301 OVS_LOG_TRACE("Segment nbl %p to newNbl: %p", nbl, newNbl);
1305 OvsFreeNBLContext(context, newNbl);
1308 InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
1310 NdisFreeFragmentNetBufferList(newNbl, hdrSize + headRoom, 0);
1315 * --------------------------------------------------------------------------
1316 * OvsAllocateNBLFromBuffer --
1318 * This function allocates all the stuff necessary for creating an NBL from the
1319 * input buffer of specified length, namely, a nonpaged data buffer of size
1320 * length, an MDL from it, and a NB and NBL from it. It does not allocate an NBL
1321 * context yet. It also copies data from the specified buffer to the NBL.
1322 * --------------------------------------------------------------------------
1325 OvsAllocateNBLFromBuffer(PVOID context,
1329 POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)context;
1331 PNET_BUFFER_LIST nbl = NULL;
1335 if (length > OVS_DEFAULT_DATA_SIZE) {
1336 nbl = OvsAllocateVariableSizeNBL(switchContext, length,
1337 OVS_DEFAULT_HEADROOM_SIZE);
1340 nbl = OvsAllocateFixSizeNBL(switchContext, length,
1341 OVS_DEFAULT_HEADROOM_SIZE);
1347 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1348 mdl = NET_BUFFER_CURRENT_MDL(nb);
1349 data = (PUINT8)MmGetSystemAddressForMdlSafe(mdl, LowPagePriority) +
1350 NET_BUFFER_CURRENT_MDL_OFFSET(nb);
1352 OvsCompleteNBL(switchContext, nbl, TRUE);
1356 NdisMoveMemory(data, buffer, length);
1362 * --------------------------------------------------------------------------
1363 * OvsFullCopyToMultipleNBLs --
1365 * Copy NBL to multiple NBLs, each NB will have its own NBL
1366 * --------------------------------------------------------------------------
1369 OvsFullCopyToMultipleNBLs(PVOID ovsContext,
1370 PNET_BUFFER_LIST nbl,
1372 BOOLEAN copyNblInfo)
1375 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
1376 PNET_BUFFER_LIST firstNbl, currNbl, newNbl;
1378 POVS_BUFFER_CONTEXT srcCtx;
1380 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1381 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
1382 OVS_LOG_INFO("src nbl must have ctx initialized");
1383 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
1387 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1388 newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
1390 if (newNbl == NULL || NET_BUFFER_NEXT_NB(nb) == NULL) {
1398 newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom,
1400 if (newNbl == NULL) {
1401 goto copymultiple_error;
1403 NET_BUFFER_LIST_NEXT_NBL(currNbl) = newNbl;
1405 nb = NET_BUFFER_NEXT_NB(nb);
1412 firstNbl = NET_BUFFER_LIST_NEXT_NBL(firstNbl);
1413 NET_BUFFER_LIST_NEXT_NBL(currNbl) = NULL;
1414 OvsCompleteNBL(context, currNbl, TRUE);
1422 * --------------------------------------------------------------------------
1425 * This function tries to free the NBL allocated by OVS buffer
1426 * management module. If it trigger the completion of the parent
1427 * NBL, it will recursively call itself. If it trigger the completion
1428 * of external NBL, it will be returned to the caller. The caller
1429 * is responsible to call API to return to upper layer.
1430 * --------------------------------------------------------------------------
1433 OvsCompleteNBL(POVS_SWITCH_CONTEXT context,
1434 PNET_BUFFER_LIST nbl,
1437 POVS_BUFFER_CONTEXT ctx;
1439 PNET_BUFFER_LIST parent;
1441 NDIS_HANDLE poolHandle;
1443 POVS_NBL_POOL ovsPool = &context->ovsPool;
1447 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1449 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1451 OVS_LOG_TRACE("Enter: nbl: %p, ctx: %p, refCount: %d, updateRef:%d",
1452 nbl, ctx, ctx->refCount, updateRef);
1455 value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
1461 * This is a special case, the refCount must be zero
1463 ASSERT(ctx->refCount == 0);
1466 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1469 if (!(flags & OVS_BUFFER_FRAGMENT) &&
1470 NET_BUFFER_DATA_LENGTH(nb) != ctx->origDataLength) {
1472 if (NET_BUFFER_DATA_LENGTH(nb) < ctx->origDataLength) {
1473 diff = ctx->origDataLength -NET_BUFFER_DATA_LENGTH(nb);
1474 status = NdisRetreatNetBufferListDataStart(nbl, diff, 0,
1476 ASSERT(status == NDIS_STATUS_SUCCESS);
1478 diff = NET_BUFFER_DATA_LENGTH(nb) - ctx->origDataLength;
1479 NdisAdvanceNetBufferListDataStart(nbl, diff, TRUE, NULL);
1483 if (ctx->flags & OVS_BUFFER_PRIVATE_CONTEXT) {
1484 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
1487 if (flags & OVS_BUFFER_NEED_COMPLETE) {
1489 * return to caller for completion
1492 InterlockedDecrement((LONG volatile *)&ovsPool->sysNBLCount);
1497 if (flags & OVS_BUFFER_PRIVATE_FORWARD_CONTEXT) {
1498 context->NdisSwitchHandlers.
1499 FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
1502 if (flags & (OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA)) {
1503 PNET_BUFFER nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1505 PMDL mdl = NET_BUFFER_FIRST_MDL(nb);
1506 NET_BUFFER_FIRST_MDL(nb) = NULL;
1507 ASSERT(mdl->Next == NULL);
1508 OvsFreeMDLAndData(mdl);
1509 nb = NET_BUFFER_NEXT_NB(nb);
1513 if (flags & OVS_BUFFER_PRIVATE_NET_BUFFER) {
1514 PNET_BUFFER nb, nextNb;
1516 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1518 nextNb = NET_BUFFER_NEXT_NB(nb);
1519 NdisFreeNetBuffer(nb);
1521 InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
1525 NET_BUFFER_LIST_FIRST_NB(nbl) = NULL;
1528 parent = nbl->ParentNetBufferList;
1530 poolHandle = NdisGetPoolFromNetBufferList(nbl);
1531 if (flags & OVS_BUFFER_FROM_FIX_SIZE_POOL) {
1532 ASSERT(poolHandle == ovsPool->fixSizePool);
1534 InterlockedDecrement((LONG volatile *)&ovsPool->fixNBLCount);
1536 NdisFreeNetBufferList(nbl);
1537 } else if (flags & OVS_BUFFER_FROM_ZERO_SIZE_POOL) {
1538 ASSERT(poolHandle == ovsPool->zeroSizePool);
1540 InterlockedDecrement((LONG volatile *)&ovsPool->zeroNBLCount);
1542 NdisFreeNetBufferList(nbl);
1543 } else if (flags & OVS_BUFFER_FROM_NBL_ONLY_POOL) {
1544 ASSERT(poolHandle == ovsPool->nblOnlyPool);
1546 InterlockedDecrement((LONG volatile *)&ovsPool->nblOnlyCount);
1548 NdisFreeCloneNetBufferList(nbl, 0);
1549 } else if (flags & OVS_BUFFER_FRAGMENT) {
1550 OVS_LOG_TRACE("Free fragment %p parent %p", nbl, parent);
1552 InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
1554 NdisFreeFragmentNetBufferList(nbl, ctx->dataOffsetDelta, 0);
1557 if (parent != NULL) {
1558 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(parent);
1559 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1560 value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
1562 return OvsCompleteNBL(context, parent, FALSE);
1569 * --------------------------------------------------------------------------
1570 * OvsSetCtxSourcePortNo --
1571 * Setter function which stores the source port of an NBL in the NBL
1573 * --------------------------------------------------------------------------
1576 OvsSetCtxSourcePortNo(PNET_BUFFER_LIST nbl,
1579 POVS_BUFFER_CONTEXT ctx;
1580 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1582 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1583 return STATUS_INVALID_PARAMETER;
1586 ctx->srcPortNo = portNo;
1587 return NDIS_STATUS_SUCCESS;
1591 * --------------------------------------------------------------------------
1592 * OvsGetCtxSourcePortNo --
1593 * Get source port of an NBL from its Context Info.
1594 * --------------------------------------------------------------------------
1597 OvsGetCtxSourcePortNo(PNET_BUFFER_LIST nbl,
1600 POVS_BUFFER_CONTEXT ctx;
1601 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1602 if (ctx == NULL || portNo == NULL) {
1603 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1604 return STATUS_INVALID_PARAMETER;
1606 *portNo = ctx->srcPortNo;
1607 return NDIS_STATUS_SUCCESS;