2 * Copyright (c) 2014 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 * ****************************************************************************
85 #define OVS_DBG_MOD OVS_DBG_BUFMGMT
90 #include "PacketParser.h"
94 * --------------------------------------------------------------------------
95 * OvsInitBufferPool --
97 * Allocate NBL and NB pool
99 * XXX: more optimization may be done for buffer management include local cache
100 * of NBL, NB, data, context, MDL.
101 * --------------------------------------------------------------------------
104 OvsInitBufferPool(PVOID ovsContext)
106 POVS_NBL_POOL ovsPool;
107 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
108 NET_BUFFER_LIST_POOL_PARAMETERS nblParam;
109 NET_BUFFER_POOL_PARAMETERS nbParam;
111 C_ASSERT(MEMORY_ALLOCATION_ALIGNMENT >= 8);
113 OVS_LOG_TRACE("Enter: context: %p", context);
115 ovsPool = &context->ovsPool;
116 RtlZeroMemory(ovsPool, sizeof (OVS_NBL_POOL));
117 ovsPool->ndisHandle = context->NdisFilterHandle;
118 ovsPool->ndisContext = context->NdisSwitchContext;
120 * fix size NBL pool includes
121 * NBL + NB + MDL + DATA + Context
122 * This is mainly used for Packet execute or slow path when copy is
123 * required and size is less than OVS_DEFAULT_DATA_SIZE. We expect
124 * Most of packet from user space will use this Pool. (This is
125 * true for all bfd and cfm packet.
127 RtlZeroMemory(&nblParam, sizeof (nblParam));
128 OVS_INIT_OBJECT_HEADER(&nblParam.Header,
129 NDIS_OBJECT_TYPE_DEFAULT,
130 NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1,
131 NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1);
132 nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE;
133 nblParam.PoolTag = OVS_FIX_SIZE_NBL_POOL_TAG;
134 nblParam.fAllocateNetBuffer = TRUE;
135 nblParam.DataSize = OVS_DEFAULT_DATA_SIZE + OVS_DEFAULT_HEADROOM_SIZE;
137 ovsPool->fixSizePool =
138 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
139 if (ovsPool->fixSizePool == NULL) {
144 * Zero Size NBL Pool includes
146 * This is mainly for packet with large data Size, in this case MDL and
147 * Data will be allocate separately.
149 RtlZeroMemory(&nblParam, sizeof (nblParam));
150 OVS_INIT_OBJECT_HEADER(&nblParam.Header,
151 NDIS_OBJECT_TYPE_DEFAULT,
152 NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1,
153 NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1);
155 nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE;
156 nblParam.PoolTag = OVS_VARIABLE_SIZE_NBL_POOL_TAG;
157 nblParam.fAllocateNetBuffer = TRUE;
158 nblParam.DataSize = 0;
160 ovsPool->zeroSizePool =
161 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
162 if (ovsPool->zeroSizePool == NULL) {
167 * NBL only pool just includes
169 * This is mainly used for clone and partial copy
171 RtlZeroMemory(&nblParam, sizeof (nblParam));
172 OVS_INIT_OBJECT_HEADER(&nblParam.Header,
173 NDIS_OBJECT_TYPE_DEFAULT,
174 NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1,
175 NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1);
177 nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE;
178 nblParam.PoolTag = OVS_NBL_ONLY_POOL_TAG;
179 nblParam.fAllocateNetBuffer = FALSE;
180 nblParam.DataSize = 0;
182 ovsPool->nblOnlyPool =
183 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
184 if (ovsPool->nblOnlyPool == NULL) {
189 * NB only pool, used for copy
192 OVS_INIT_OBJECT_HEADER(&nbParam.Header,
193 NDIS_OBJECT_TYPE_DEFAULT,
194 NET_BUFFER_POOL_PARAMETERS_REVISION_1,
195 NDIS_SIZEOF_NET_BUFFER_POOL_PARAMETERS_REVISION_1);
196 nbParam.PoolTag = OVS_NET_BUFFER_POOL_TAG;
197 nbParam.DataSize = 0;
199 NdisAllocateNetBufferPool(context->NdisSwitchContext, &nbParam);
200 if (ovsPool->nbPool == NULL) {
203 OVS_LOG_TRACE("Exit: fixSizePool: %p zeroSizePool: %p nblOnlyPool: %p"
204 "nbPool: %p", ovsPool->fixSizePool, ovsPool->zeroSizePool,
205 ovsPool->nblOnlyPool, ovsPool->nbPool);
206 return NDIS_STATUS_SUCCESS;
209 OvsCleanupBufferPool(context);
210 OVS_LOG_TRACE("Exit: Fail to initialize ovs buffer pool");
211 return NDIS_STATUS_RESOURCES;
216 * --------------------------------------------------------------------------
217 * OvsCleanupBufferPool --
218 * Free Buffer pool for NBL and NB.
219 * --------------------------------------------------------------------------
222 OvsCleanupBufferPool(PVOID ovsContext)
224 POVS_NBL_POOL ovsPool;
225 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
226 ovsPool = &context->ovsPool;
227 OVS_LOG_TRACE("Enter: context: %p", context);
229 ASSERT(ovsPool->fixNBLCount == 0);
230 ASSERT(ovsPool->zeroNBLCount == 0);
231 ASSERT(ovsPool->nblOnlyCount == 0);
232 ASSERT(ovsPool->nbCount == 0);
233 ASSERT(ovsPool->sysNBLCount == 0);
234 ASSERT(ovsPool->fragNBLCount == 0);
237 if (ovsPool->fixSizePool) {
238 NdisFreeNetBufferListPool(ovsPool->fixSizePool);
239 ovsPool->fixSizePool = NULL;
241 if (ovsPool->zeroSizePool) {
242 NdisFreeNetBufferListPool(ovsPool->zeroSizePool);
243 ovsPool->zeroSizePool = NULL;
245 if (ovsPool->nblOnlyPool) {
246 NdisFreeNetBufferListPool(ovsPool->nblOnlyPool);
247 ovsPool->nblOnlyPool = NULL;
249 if (ovsPool->nbPool) {
250 NdisFreeNetBufferPool(ovsPool->nbPool);
251 ovsPool->nbPool = NULL;
253 OVS_LOG_TRACE("Exit: cleanup OVS Buffer pool");
258 OvsInitNBLContext(POVS_BUFFER_CONTEXT ctx,
260 UINT32 origDataLength,
263 ctx->magic = OVS_CTX_MAGIC;
266 ctx->srcPortNo = srcPortNo;
267 ctx->origDataLength = origDataLength;
272 OvsDumpForwardingDetails(PNET_BUFFER_LIST nbl)
274 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
275 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
279 OVS_LOG_INFO("nbl: %p, numAvailableDest: %d, srcId:%d, srcIndex: %d "
280 "isDataSafe: %s, safeDataSize: %d",
281 nbl, info->NumAvailableDestinations, info->SourcePortId,
282 info->SourceNicIndex,
283 info->IsPacketDataSafe ? "TRUE" : "FALSE",
284 info->IsPacketDataSafe ? 0 : info->SafePacketDataSize);
289 OvsDumpNBLContext(PNET_BUFFER_LIST nbl)
291 PNET_BUFFER_LIST_CONTEXT ctx = nbl->Context;
293 OVS_LOG_INFO("No Net Buffer List context");
297 OVS_LOG_INFO("nbl: %p, ctx: %p, TotalSize: %d, Offset: %d",
298 nbl, ctx, ctx->Size, ctx->Offset);
305 OvsDumpMDLChain(PMDL mdl)
310 OVS_LOG_INFO("MDL: %p, Size: %d, MappedSystemVa: %p, StartVa: %p"
311 " ByteCount: %d, ByteOffset: %d",
312 tmp, tmp->Size, tmp->MappedSystemVa,
313 tmp->StartVa, tmp->ByteCount, tmp->ByteOffset);
320 OvsDumpNetBuffer(PNET_BUFFER nb)
322 OVS_LOG_INFO("NET_BUFFER: %p, ChecksumBias: %d Handle: %p, MDLChain: %p "
323 "CurrMDL: %p, CurrOffset: %d, DataLen: %d, Offset: %d",
325 NET_BUFFER_CHECKSUM_BIAS(nb), nb->NdisPoolHandle,
326 NET_BUFFER_FIRST_MDL(nb),
327 NET_BUFFER_CURRENT_MDL(nb),
328 NET_BUFFER_CURRENT_MDL_OFFSET(nb),
329 NET_BUFFER_DATA_LENGTH(nb),
330 NET_BUFFER_DATA_OFFSET(nb));
331 OvsDumpMDLChain(NET_BUFFER_FIRST_MDL(nb));
336 OvsDumpNetBufferList(PNET_BUFFER_LIST nbl)
339 OVS_LOG_INFO("NBL: %p, parent: %p, SrcHandle: %p, ChildCount:%d "
341 nbl, nbl->ParentNetBufferList,
342 nbl->SourceHandle, nbl->ChildRefCount,
343 nbl->NdisPoolHandle);
344 OvsDumpNBLContext(nbl);
345 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
347 OvsDumpNetBuffer(nb);
348 nb = NET_BUFFER_NEXT_NB(nb);
353 * --------------------------------------------------------------------------
354 * OvsAllocateFixSizeNBL --
356 * Allocate fix size NBL which include
357 * NBL + NB + MBL + Data + Context
359 * * Forwarding Context is allocated, but forwarding detail information
360 * is not initailized.
361 * * The headroom can not be larger than OVS_DEFAULT_HEADROOM_SIZE(128
363 * --------------------------------------------------------------------------
366 OvsAllocateFixSizeNBL(PVOID ovsContext,
370 PNET_BUFFER_LIST nbl = NULL;
371 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
372 POVS_BUFFER_CONTEXT ctx;
373 POVS_NBL_POOL ovsPool = &context->ovsPool;
376 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
378 if ((headRoom + size) > OVS_FIX_NBL_DATA_SIZE || size == 0) {
383 nbl = NdisAllocateNetBufferList(ovsPool->fixSizePool,
384 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
385 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
392 nbl->SourceHandle = ovsPool->ndisHandle;
393 status = context->NdisSwitchHandlers.
394 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
396 if (status != NDIS_STATUS_SUCCESS) {
397 NdisFreeNetBufferList(nbl);
402 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
404 info->IsPacketDataSafe = TRUE;
405 info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
407 status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
409 ASSERT(status == NDIS_STATUS_SUCCESS);
412 InterlockedIncrement((LONG volatile *)&ovsPool->fixNBLCount);
413 OvsDumpNetBufferList(nbl);
414 OvsDumpForwardingDetails(nbl);
417 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
420 OvsInitNBLContext(ctx, OVS_BUFFER_FROM_FIX_SIZE_POOL |
421 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT, size,
422 OVS_DPPORT_NUMBER_INVALID);
425 OVS_LOG_LOUD("Allocate Fix NBL: %p, line: %d", nbl, line);
431 OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle,
437 data = OvsAllocateMemoryWithTag(dataSize, OVS_MDL_POOL_TAG);
442 mdl = NdisAllocateMdl(ndisHandle, data, dataSize);
444 OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
452 OvsFreeMDLAndData(PMDL mdl)
456 data = MmGetMdlVirtualAddress(mdl);
458 OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
463 * --------------------------------------------------------------------------
464 * OvsAllocateVariableSizeNBL --
466 * Allocate variable size NBL, the NBL looks like
469 * --------------------------------------------------------------------------
472 OvsAllocateVariableSizeNBL(PVOID ovsContext,
476 PNET_BUFFER_LIST nbl = NULL;
477 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
478 POVS_NBL_POOL ovsPool = &context->ovsPool;
479 POVS_BUFFER_CONTEXT ctx;
483 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
487 realSize = MEM_ALIGN_SIZE(size + headRoom);
489 mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, realSize);
494 nbl = NdisAllocateNetBufferAndNetBufferList(ovsPool->zeroSizePool,
495 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
496 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL,
499 OvsFreeMDLAndData(mdl);
503 nbl->SourceHandle = ovsPool->ndisHandle;
504 status = context->NdisSwitchHandlers.
505 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
507 if (status != NDIS_STATUS_SUCCESS) {
509 * do we need to remove mdl from nbl XXX
511 OvsFreeMDLAndData(mdl);
512 NdisFreeNetBufferList(nbl);
516 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
518 info->IsPacketDataSafe = TRUE;
519 info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
520 status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
522 ASSERT(status == NDIS_STATUS_SUCCESS);
525 InterlockedIncrement((LONG volatile *)&ovsPool->zeroNBLCount);
526 OvsDumpNetBufferList(nbl);
527 OvsDumpForwardingDetails(nbl);
530 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
532 OvsInitNBLContext(ctx, OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
533 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT |
534 OVS_BUFFER_FROM_ZERO_SIZE_POOL,
535 size, OVS_DPPORT_NUMBER_INVALID);
537 OVS_LOG_LOUD("Allocate variable size NBL: %p", nbl);
543 * --------------------------------------------------------------------------
544 * OvsInitExternalNBLContext --
546 * For NBL not allocated by OVS, it will allocate and initialize
548 * --------------------------------------------------------------------------
551 OvsInitExternalNBLContext(PVOID ovsContext,
552 PNET_BUFFER_LIST nbl,
555 NDIS_HANDLE poolHandle;
556 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
557 POVS_BUFFER_CONTEXT ctx;
562 poolHandle = NdisGetPoolFromNetBufferList(nbl);
564 if (poolHandle == context->ovsPool.ndisHandle ||
565 nbl->SourceHandle == context->ovsPool.ndisHandle) {
566 return (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
568 status = NdisAllocateNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT),
569 OVS_DEFAULT_NBL_CONTEXT_FILL,
571 if (status != NDIS_STATUS_SUCCESS) {
575 OvsDumpNBLContext(nbl);
576 InterlockedIncrement((LONG volatile *)&context->ovsPool.sysNBLCount);
578 flags = isRecv ? OVS_BUFFER_RECV_BUFFER : OVS_BUFFER_SEND_BUFFER;
579 flags |= OVS_BUFFER_NEED_COMPLETE | OVS_BUFFER_PRIVATE_CONTEXT;
580 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
582 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
584 * we use first nb to decide whether we need advance or retreat during
587 OvsInitNBLContext(ctx, flags, NET_BUFFER_DATA_LENGTH(nb),
588 OVS_DPPORT_NUMBER_INVALID);
593 * --------------------------------------------------------------------------
594 * OvsAllocateNBLContext
596 * Create NBL buffer context and forwarding context.
597 * --------------------------------------------------------------------------
600 OvsAllocateNBLContext(POVS_SWITCH_CONTEXT context,
601 PNET_BUFFER_LIST nbl)
603 POVS_NBL_POOL ovsPool = &context->ovsPool;
606 status = NdisAllocateNetBufferListContext(nbl,
607 sizeof (OVS_BUFFER_CONTEXT),
608 OVS_DEFAULT_NBL_CONTEXT_FILL,
610 if (status != NDIS_STATUS_SUCCESS) {
611 return NDIS_STATUS_FAILURE;
614 nbl->SourceHandle = ovsPool->ndisHandle;
615 status = context->NdisSwitchHandlers.
616 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
618 if (status != NDIS_STATUS_SUCCESS) {
619 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
620 return NDIS_STATUS_FAILURE;
626 * --------------------------------------------------------------------------
629 * Free the NBL buffer context and forwarding context.
630 * --------------------------------------------------------------------------
633 OvsFreeNBLContext(POVS_SWITCH_CONTEXT context,
634 PNET_BUFFER_LIST nbl)
636 POVS_NBL_POOL ovsPool = &context->ovsPool;
638 context->NdisSwitchHandlers.
639 FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
640 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
642 return NDIS_STATUS_SUCCESS;
646 * --------------------------------------------------------------------------
649 * Copy NBL info from src to dst
650 * --------------------------------------------------------------------------
653 OvsCopyNBLInfo(PNET_BUFFER_LIST srcNbl, PNET_BUFFER_LIST dstNbl,
654 POVS_BUFFER_CONTEXT srcCtx, UINT32 copySize,
657 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO srcInfo, dstInfo;
658 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
660 srcInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(srcNbl);
661 dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(dstNbl);
663 #ifdef OVS_USE_COPY_NET_BUFFER_LIST_INFO
664 status = context->NdisSwitchHandlers.
665 CopyNetBufferListInfo(ovsPool->ndisContext, dstNbl, srcNbl, 0);
667 if (status != NDIS_STATUS_SUCCESS) {
671 dstInfo->SourcePortId = srcInfo->SourcePortId;
672 dstInfo->SourceNicIndex = srcInfo->SourceNicIndex;
674 if (srcCtx->flags & OVS_BUFFER_RECV_BUFFER) {
675 NdisCopyReceiveNetBufferListInfo(dstNbl, srcNbl);
676 } else if (srcCtx->flags & OVS_BUFFER_SEND_BUFFER) {
677 NdisCopySendNetBufferListInfo(dstNbl, srcNbl);
681 dstInfo->IsPacketDataSafe = srcInfo->IsPacketDataSafe;
682 if (!srcInfo->IsPacketDataSafe && copySize >
683 srcInfo->SafePacketDataSize) {
684 srcInfo->SafePacketDataSize = copySize;
688 * Assume all data are safe
690 dstInfo->IsPacketDataSafe = TRUE;
691 dstInfo->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
697 * --------------------------------------------------------------------------
698 * OvsPartialCopyNBL --
700 * Partial copy NBL, if there is multiple NB in NBL, each one will be
701 * copied. We also reserve headroom for the new NBL.
704 * NBL should have OVS_BUFFER_CONTEXT setup before calling
706 * The NBL should already have ref to itself so that during copy
707 * it will not be freed.
708 * --------------------------------------------------------------------------
711 OvsPartialCopyNBL(PVOID ovsContext,
712 PNET_BUFFER_LIST nbl,
717 PNET_BUFFER_LIST newNbl;
718 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
720 PNET_BUFFER srcNb, dstNb;
722 POVS_NBL_POOL ovsPool = &context->ovsPool;
723 POVS_BUFFER_CONTEXT srcCtx, dstCtx;
726 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
727 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
728 OVS_LOG_INFO("src nbl must have ctx initialized");
729 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
734 NdisAdvanceNetBufferListDataStart(nbl, copySize, FALSE, NULL);
736 newNbl = NdisAllocateCloneNetBufferList(nbl, ovsPool->nblOnlyPool,
739 status = NdisRetreatNetBufferListDataStart(nbl, copySize, 0,
741 ASSERT(status == NDIS_STATUS_SUCCESS);
744 if (newNbl == NULL) {
749 * Allocate private memory for copy
751 if (copySize + headRoom) {
752 status = NdisRetreatNetBufferListDataStart(newNbl, copySize + headRoom,
754 if (status != NDIS_STATUS_SUCCESS) {
759 NdisAdvanceNetBufferListDataStart(newNbl, headRoom, FALSE, NULL);
762 srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
763 dstNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
766 status = NdisCopyFromNetBufferToNetBuffer(dstNb, 0, copySize,
769 if (status != NDIS_STATUS_SUCCESS || copySize != byteCopied) {
770 goto nbl_context_error;
772 srcNb = NET_BUFFER_NEXT_NB(srcNb);
773 dstNb = NET_BUFFER_NEXT_NB(dstNb);
778 status = OvsAllocateNBLContext(context, newNbl);
779 if (status != NDIS_STATUS_SUCCESS) {
780 goto nbl_context_error;
783 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copySize, copyNblInfo);
784 if (status != NDIS_STATUS_SUCCESS) {
785 goto copy_list_info_error;
789 InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
792 newNbl->ParentNetBufferList = nbl;
794 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
795 ASSERT(dstCtx != NULL);
797 flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
799 flags |= OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_CONTEXT |
800 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;
802 srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
803 OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(srcNb) - copySize,
804 OVS_DPPORT_NUMBER_INVALID);
806 InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
809 OvsDumpNetBufferList(nbl);
810 OvsDumpForwardingDetails(nbl);
812 OvsDumpNetBufferList(newNbl);
813 OvsDumpForwardingDetails(newNbl);
816 OVS_LOG_LOUD("Partial Copy new NBL: %p", newNbl);
819 copy_list_info_error:
820 OvsFreeNBLContext(context, newNbl);
823 NdisAdvanceNetBufferListDataStart(newNbl, copySize, TRUE, NULL);
826 NdisFreeCloneNetBufferList(newNbl, 0);
831 * --------------------------------------------------------------------------
832 * OvsPartialCopyToMultipleNBLs --
834 * This is similar to OvsPartialCopyNBL() except that each NB will
836 * --------------------------------------------------------------------------
839 OvsPartialCopyToMultipleNBLs(PVOID ovsContext,
840 PNET_BUFFER_LIST nbl,
845 PNET_BUFFER nb, nextNb = NULL, firstNb, prevNb;
846 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
847 PNET_BUFFER_LIST firstNbl = NULL, newNbl, prevNbl = NULL;
849 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
850 if (NET_BUFFER_NEXT_NB(nb) == NULL) {
851 return OvsPartialCopyNBL(context, nbl, copySize, headRoom, copyNblInfo);
858 nextNb = NET_BUFFER_NEXT_NB(nb);
859 NET_BUFFER_NEXT_NB(nb) = NULL;
861 NET_BUFFER_LIST_FIRST_NB(nbl) = nb;
863 newNbl = OvsPartialCopyNBL(context, nbl, copySize, headRoom,
865 if (newNbl == NULL) {
868 if (prevNbl == NULL) {
871 NET_BUFFER_LIST_NEXT_NBL(prevNbl) = newNbl;
872 NET_BUFFER_NEXT_NB(prevNb) = nb;
878 NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;
882 NET_BUFFER_NEXT_NB(prevNb) = nb;
883 NET_BUFFER_NEXT_NB(nb) = nextNb;
884 NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;
888 firstNbl = NET_BUFFER_LIST_NEXT_NBL(newNbl);
889 NET_BUFFER_LIST_NEXT_NBL(newNbl) = NULL;
890 OvsCompleteNBL(context, newNbl, TRUE);
897 static PNET_BUFFER_LIST
898 OvsCopySinglePacketNBL(PVOID ovsContext,
899 PNET_BUFFER_LIST nbl,
906 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
907 PNET_BUFFER_LIST newNbl;
910 POVS_BUFFER_CONTEXT srcCtx, dstCtx;
912 size = NET_BUFFER_DATA_LENGTH(nb);
913 if ((size + headRoom) <= OVS_FIX_NBL_DATA_SIZE) {
914 newNbl = OvsAllocateFixSizeNBL(context, size, headRoom);
916 newNbl = OvsAllocateVariableSizeNBL(context, size, headRoom);
918 if (newNbl == NULL) {
921 newNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
922 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
925 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
926 if (status == NDIS_STATUS_SUCCESS) {
927 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copiedSize, copyNblInfo);
930 if (status != NDIS_STATUS_SUCCESS || copiedSize != size) {
931 OvsCompleteNBL(context, newNbl, TRUE);
935 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
936 ASSERT(dstCtx && srcCtx);
937 ASSERT(srcCtx->magic == OVS_CTX_MAGIC && dstCtx->magic == OVS_CTX_MAGIC);
939 dstCtx->flags |= srcCtx->flags & (OVS_BUFFER_RECV_BUFFER |
940 OVS_BUFFER_SEND_BUFFER);
942 OvsDumpNetBufferList(newNbl);
943 OvsDumpForwardingDetails(newNbl);
945 OVS_LOG_LOUD("Copy single nb to new NBL: %p", newNbl);
950 * --------------------------------------------------------------------------
953 * Copy the NBL to a new NBL including data.
956 * The NBL can have multiple NBs, but the final result is one NBL.
957 * --------------------------------------------------------------------------
960 OvsFullCopyNBL(PVOID ovsContext,
961 PNET_BUFFER_LIST nbl,
965 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
966 POVS_NBL_POOL ovsPool = &context->ovsPool;
967 PNET_BUFFER_LIST newNbl;
968 PNET_BUFFER nb, newNb, firstNb = NULL, prevNb = NULL;
969 POVS_BUFFER_CONTEXT dstCtx, srcCtx;
972 UINT32 size, totalSize;
975 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo;
977 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
978 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
979 OVS_LOG_INFO("src nbl must have ctx initialized");
980 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
984 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
986 if (NET_BUFFER_NEXT_NB(nb) == NULL) {
987 return OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
990 newNbl = NdisAllocateNetBufferList(ovsPool->nblOnlyPool,
991 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
992 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
993 if (newNbl == NULL) {
998 size = NET_BUFFER_DATA_LENGTH(nb);
999 totalSize = MEM_ALIGN_SIZE(size + headRoom);
1000 mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, totalSize);
1005 newNb = NdisAllocateNetBuffer(ovsPool->nbPool, mdl, totalSize, 0);
1006 if (newNb == NULL) {
1007 OvsFreeMDLAndData(mdl);
1010 if (firstNb == NULL) {
1013 NET_BUFFER_NEXT_NB(prevNb) = newNb;
1017 InterlockedIncrement((LONG volatile *)&ovsPool->nbCount);
1019 status = NdisRetreatNetBufferDataStart(newNb, size, 0, NULL);
1020 ASSERT(status == NDIS_STATUS_SUCCESS);
1022 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
1024 if (status != NDIS_STATUS_SUCCESS || size != copiedSize) {
1028 nb = NET_BUFFER_NEXT_NB(nb);
1031 NET_BUFFER_LIST_FIRST_NB(newNbl) = firstNb;
1033 newNbl->SourceHandle = ovsPool->ndisHandle;
1034 status = context->NdisSwitchHandlers.
1035 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, newNbl);
1037 if (status != NDIS_STATUS_SUCCESS) {
1041 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, 0, copyNblInfo);
1042 if (status != NDIS_STATUS_SUCCESS) {
1046 dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl);
1047 dstInfo->IsPacketDataSafe = TRUE;
1049 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
1051 flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
1053 flags |= OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
1054 OVS_BUFFER_PRIVATE_NET_BUFFER | OVS_BUFFER_FROM_NBL_ONLY_POOL |
1055 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;
1057 OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(firstNb),
1058 OVS_DPPORT_NUMBER_INVALID);
1061 OvsDumpNetBufferList(nbl);
1062 OvsDumpForwardingDetails(nbl);
1063 InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
1065 OVS_LOG_LOUD("newNbl: %p", newNbl);
1071 InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
1074 firstNb = NET_BUFFER_NEXT_NB(prevNb);
1075 mdl = NET_BUFFER_FIRST_MDL(prevNb);
1076 NET_BUFFER_FIRST_MDL(prevNb) = NULL;
1077 NdisFreeNetBuffer(prevNb);
1078 OvsFreeMDLAndData(mdl);
1080 NdisFreeNetBufferList(newNbl);
1081 OVS_LOG_ERROR("OvsFullCopyNBL failed");
1086 * --------------------------------------------------------------------------
1087 * GetSegmentHeaderInfo
1089 * Extract header size and sequence number for the segment.
1090 * --------------------------------------------------------------------------
1093 GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl,
1094 const POVS_PACKET_HDR_INFO hdrInfo,
1095 UINT32 *hdrSize, UINT32 *seqNumber)
1100 /* Parse the orginal Eth/IP/TCP header */
1101 tcp = OvsGetPacketBytes(nbl, sizeof *tcp, hdrInfo->l4Offset, &tcpStorage);
1103 return NDIS_STATUS_FAILURE;
1105 *seqNumber = ntohl(tcp->seq);
1106 *hdrSize = hdrInfo->l4Offset + TCP_HDR_LEN(tcp);
1108 return NDIS_STATUS_SUCCESS;
1113 * --------------------------------------------------------------------------
1116 * Fix IP length, IP checksum, TCP sequence number and TCP checksum
1118 * --------------------------------------------------------------------------
1121 FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
1122 BOOLEAN lastPacket, UINT16 packetCounter)
1130 mdl = NET_BUFFER_FIRST_MDL(nb);
1132 bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(mdl, LowPagePriority);
1134 return NDIS_STATUS_RESOURCES;
1136 dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb));
1137 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1138 >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr));
1139 dstIP = (IPHdr *)((PCHAR)dstEth + sizeof *dstEth);
1140 dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4);
1141 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1142 >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
1144 /* Fix IP length and checksum */
1145 ASSERT(dstIP->protocol == IPPROTO_TCP);
1146 dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
1147 dstIP->id += packetCounter;
1149 dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);
1151 /* Fix TCP checksum */
1152 dstTCP->seq = htonl(seqNumber);
1155 * Set the TCP FIN and PSH bit only for the last packet
1156 * More information can be found under:
1157 * https://msdn.microsoft.com/en-us/library/windows/hardware/ff568840%28v=vs.85%29.aspx
1160 dstTCP->fin = lastPacket;
1163 dstTCP->psh = lastPacket;
1166 UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP);
1167 dstTCP->check = IPPseudoChecksum(&dstIP->saddr,
1171 dstTCP->check = CalculateChecksumNB(nb,
1173 sizeof *dstEth + dstIP->ihl * 4);
1175 return STATUS_SUCCESS;
1179 * --------------------------------------------------------------------------
1180 * OvsTcpSegmentyNBL --
1182 * Segment TCP payload, and prepend each segment with ether/IP/TCP header.
1183 * Leave headRoom for additional encap.
1186 * NBL should have OVS_BUFFER_CONTEXT setup before calling
1188 * The NBL should already have ref to itself so that during copy
1189 * it will not be freed.
1190 * Currently this API assert there is only one NB in an NBL, it needs
1191 * to be fixed if we receive multiple NBs in an NBL.
1192 * --------------------------------------------------------------------------
1195 OvsTcpSegmentNBL(PVOID ovsContext,
1196 PNET_BUFFER_LIST nbl,
1197 POVS_PACKET_HDR_INFO hdrInfo,
1201 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
1203 POVS_NBL_POOL ovsPool = &context->ovsPool;
1205 POVS_BUFFER_CONTEXT dstCtx, srcCtx;
1206 UINT32 size, hdrSize, seqNumber;
1207 PNET_BUFFER_LIST newNbl;
1208 PNET_BUFFER nb, newNb;
1212 UINT16 packetCounter = 0;
1214 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1215 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
1216 OVS_LOG_INFO("src nbl must have ctx initialized");
1217 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
1221 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1222 ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL);
1224 /* Figure out the segment header size */
1225 status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber);
1226 if (status != NDIS_STATUS_SUCCESS) {
1227 OVS_LOG_INFO("Cannot parse NBL header");
1231 size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize;
1233 /* XXX add to ovsPool counters? */
1234 newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL,
1235 NULL, hdrSize, mss, hdrSize + headRoom , 0, 0);
1236 if (newNbl == NULL) {
1240 /* Now deal with TCP payload */
1241 for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL;
1242 newNb = NET_BUFFER_NEXT_NB(newNb)) {
1243 segmentSize = (size > mss ? mss : size) & 0xffff;
1245 NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL);
1248 /* Now copy the eth/IP/TCP header and fix up */
1249 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize, nb, 0,
1251 if (status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize) {
1255 status = FixSegmentHeader(newNb, segmentSize, seqNumber,
1256 NET_BUFFER_NEXT_NB(newNb) == NULL,
1258 if (status != NDIS_STATUS_SUCCESS) {
1263 /* Move on to the next segment */
1264 size -= segmentSize;
1265 seqNumber += segmentSize;
1269 status = OvsAllocateNBLContext(context, newNbl);
1270 if (status != NDIS_STATUS_SUCCESS) {
1274 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, hdrSize + headRoom, FALSE);
1275 if (status != NDIS_STATUS_SUCCESS) {
1276 goto nbl_context_error;
1279 newNbl->ParentNetBufferList = nbl;
1281 /* Remember it's a fragment NBL so we can free it properly */
1282 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
1283 ASSERT(dstCtx != NULL);
1284 dstCtx->flags = OVS_BUFFER_FRAGMENT | OVS_BUFFER_PRIVATE_CONTEXT |
1285 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | OVS_BUFFER_SEND_BUFFER;
1286 dstCtx->refCount = 1;
1287 dstCtx->magic = OVS_CTX_MAGIC;
1288 dstCtx->dataOffsetDelta = hdrSize + headRoom;
1290 InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
1292 InterlockedIncrement((LONG volatile *)&ovsPool->fragNBLCount);
1294 OvsDumpNetBufferList(nbl);
1295 OvsDumpForwardingDetails(nbl);
1297 OvsDumpNetBufferList(newNbl);
1298 OvsDumpForwardingDetails(newNbl);
1300 OVS_LOG_TRACE("Segment nbl %p to newNbl: %p", nbl, newNbl);
1304 OvsFreeNBLContext(context, newNbl);
1307 InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
1309 NdisFreeFragmentNetBufferList(newNbl, hdrSize + headRoom, 0);
1314 * --------------------------------------------------------------------------
1315 * OvsAllocateNBLFromBuffer --
1317 * This function allocates all the stuff necessary for creating an NBL from the
1318 * input buffer of specified length, namely, a nonpaged data buffer of size
1319 * length, an MDL from it, and a NB and NBL from it. It does not allocate an NBL
1320 * context yet. It also copies data from the specified buffer to the NBL.
1321 * --------------------------------------------------------------------------
1324 OvsAllocateNBLFromBuffer(PVOID context,
1328 POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)context;
1330 PNET_BUFFER_LIST nbl = NULL;
1334 if (length > OVS_DEFAULT_DATA_SIZE) {
1335 nbl = OvsAllocateVariableSizeNBL(switchContext, length,
1336 OVS_DEFAULT_HEADROOM_SIZE);
1339 nbl = OvsAllocateFixSizeNBL(switchContext, length,
1340 OVS_DEFAULT_HEADROOM_SIZE);
1346 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1347 mdl = NET_BUFFER_CURRENT_MDL(nb);
1348 data = (PUINT8)MmGetSystemAddressForMdlSafe(mdl, LowPagePriority) +
1349 NET_BUFFER_CURRENT_MDL_OFFSET(nb);
1351 OvsCompleteNBL(switchContext, nbl, TRUE);
1355 NdisMoveMemory(data, buffer, length);
1361 * --------------------------------------------------------------------------
1362 * OvsFullCopyToMultipleNBLs --
1364 * Copy NBL to multiple NBLs, each NB will have its own NBL
1365 * --------------------------------------------------------------------------
1368 OvsFullCopyToMultipleNBLs(PVOID ovsContext,
1369 PNET_BUFFER_LIST nbl,
1371 BOOLEAN copyNblInfo)
1374 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
1375 PNET_BUFFER_LIST firstNbl, currNbl, newNbl;
1377 POVS_BUFFER_CONTEXT srcCtx;
1379 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1380 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
1381 OVS_LOG_INFO("src nbl must have ctx initialized");
1382 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
1386 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1387 newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
1389 if (newNbl == NULL || NET_BUFFER_NEXT_NB(nb) == NULL) {
1397 newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom,
1399 if (newNbl == NULL) {
1400 goto copymultiple_error;
1402 NET_BUFFER_LIST_NEXT_NBL(currNbl) = newNbl;
1404 nb = NET_BUFFER_NEXT_NB(nb);
1411 firstNbl = NET_BUFFER_LIST_NEXT_NBL(firstNbl);
1412 NET_BUFFER_LIST_NEXT_NBL(currNbl) = NULL;
1413 OvsCompleteNBL(context, currNbl, TRUE);
1421 * --------------------------------------------------------------------------
1424 * This function tries to free the NBL allocated by OVS buffer
1425 * management module. If it trigger the completion of the parent
1426 * NBL, it will recursively call itself. If it trigger the completion
1427 * of external NBL, it will be returned to the caller. The caller
1428 * is responsible to call API to return to upper layer.
1429 * --------------------------------------------------------------------------
1432 OvsCompleteNBL(POVS_SWITCH_CONTEXT context,
1433 PNET_BUFFER_LIST nbl,
1436 POVS_BUFFER_CONTEXT ctx;
1438 PNET_BUFFER_LIST parent;
1440 NDIS_HANDLE poolHandle;
1442 POVS_NBL_POOL ovsPool = &context->ovsPool;
1446 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1448 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1450 OVS_LOG_TRACE("Enter: nbl: %p, ctx: %p, refCount: %d, updateRef:%d",
1451 nbl, ctx, ctx->refCount, updateRef);
1454 value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
1460 * This is a special case, the refCount must be zero
1462 ASSERT(ctx->refCount == 0);
1465 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1468 if (!(flags & OVS_BUFFER_FRAGMENT) &&
1469 NET_BUFFER_DATA_LENGTH(nb) != ctx->origDataLength) {
1471 if (NET_BUFFER_DATA_LENGTH(nb) < ctx->origDataLength) {
1472 diff = ctx->origDataLength -NET_BUFFER_DATA_LENGTH(nb);
1473 status = NdisRetreatNetBufferListDataStart(nbl, diff, 0,
1475 ASSERT(status == NDIS_STATUS_SUCCESS);
1477 diff = NET_BUFFER_DATA_LENGTH(nb) - ctx->origDataLength;
1478 NdisAdvanceNetBufferListDataStart(nbl, diff, TRUE, NULL);
1482 if (ctx->flags & OVS_BUFFER_PRIVATE_CONTEXT) {
1483 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
1486 if (flags & OVS_BUFFER_NEED_COMPLETE) {
1488 * return to caller for completion
1491 InterlockedDecrement((LONG volatile *)&ovsPool->sysNBLCount);
1496 if (flags & OVS_BUFFER_PRIVATE_FORWARD_CONTEXT) {
1497 context->NdisSwitchHandlers.
1498 FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
1501 if (flags & (OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA)) {
1502 PNET_BUFFER nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1504 PMDL mdl = NET_BUFFER_FIRST_MDL(nb);
1505 NET_BUFFER_FIRST_MDL(nb) = NULL;
1506 ASSERT(mdl->Next == NULL);
1507 OvsFreeMDLAndData(mdl);
1508 nb = NET_BUFFER_NEXT_NB(nb);
1512 if (flags & OVS_BUFFER_PRIVATE_NET_BUFFER) {
1513 PNET_BUFFER nb, nextNb;
1515 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1517 nextNb = NET_BUFFER_NEXT_NB(nb);
1518 NdisFreeNetBuffer(nb);
1520 InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
1524 NET_BUFFER_LIST_FIRST_NB(nbl) = NULL;
1527 parent = nbl->ParentNetBufferList;
1529 poolHandle = NdisGetPoolFromNetBufferList(nbl);
1530 if (flags & OVS_BUFFER_FROM_FIX_SIZE_POOL) {
1531 ASSERT(poolHandle == ovsPool->fixSizePool);
1533 InterlockedDecrement((LONG volatile *)&ovsPool->fixNBLCount);
1535 NdisFreeNetBufferList(nbl);
1536 } else if (flags & OVS_BUFFER_FROM_ZERO_SIZE_POOL) {
1537 ASSERT(poolHandle == ovsPool->zeroSizePool);
1539 InterlockedDecrement((LONG volatile *)&ovsPool->zeroNBLCount);
1541 NdisFreeNetBufferList(nbl);
1542 } else if (flags & OVS_BUFFER_FROM_NBL_ONLY_POOL) {
1543 ASSERT(poolHandle == ovsPool->nblOnlyPool);
1545 InterlockedDecrement((LONG volatile *)&ovsPool->nblOnlyCount);
1547 NdisFreeCloneNetBufferList(nbl, 0);
1548 } else if (flags & OVS_BUFFER_FRAGMENT) {
1549 OVS_LOG_TRACE("Free fragment %p parent %p", nbl, parent);
1551 InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
1553 NdisFreeFragmentNetBufferList(nbl, ctx->dataOffsetDelta, 0);
1556 if (parent != NULL) {
1557 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(parent);
1558 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1559 value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
1561 return OvsCompleteNBL(context, parent, FALSE);
1568 * --------------------------------------------------------------------------
1569 * OvsSetCtxSourcePortNo --
1570 * Setter function which stores the source port of an NBL in the NBL
1572 * --------------------------------------------------------------------------
1575 OvsSetCtxSourcePortNo(PNET_BUFFER_LIST nbl,
1578 POVS_BUFFER_CONTEXT ctx;
1579 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1581 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1582 return STATUS_INVALID_PARAMETER;
1585 ctx->srcPortNo = portNo;
1586 return NDIS_STATUS_SUCCESS;
1590 * --------------------------------------------------------------------------
1591 * OvsGetCtxSourcePortNo --
1592 * Get source port of an NBL from its Context Info.
1593 * --------------------------------------------------------------------------
1596 OvsGetCtxSourcePortNo(PNET_BUFFER_LIST nbl,
1599 POVS_BUFFER_CONTEXT ctx;
1600 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1601 if (ctx == NULL || portNo == NULL) {
1602 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1603 return STATUS_INVALID_PARAMETER;
1605 *portNo = ctx->srcPortNo;
1606 return NDIS_STATUS_SUCCESS;