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"
93 * --------------------------------------------------------------------------
94 * OvsInitBufferPool --
96 * Allocate NBL and NB pool
98 * XXX: more optimization may be done for buffer management include local cache
99 * of NBL, NB, data, context, MDL.
100 * --------------------------------------------------------------------------
103 OvsInitBufferPool(PVOID ovsContext)
105 POVS_NBL_POOL ovsPool;
106 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
107 NET_BUFFER_LIST_POOL_PARAMETERS nblParam;
108 NET_BUFFER_POOL_PARAMETERS nbParam;
110 C_ASSERT(MEMORY_ALLOCATION_ALIGNMENT >= 8);
112 OVS_LOG_TRACE("Enter: context: %p", context);
114 ovsPool = &context->ovsPool;
115 RtlZeroMemory(ovsPool, sizeof (OVS_NBL_POOL));
116 ovsPool->ndisHandle = context->NdisFilterHandle;
117 ovsPool->ndisContext = context->NdisSwitchContext;
119 * fix size NBL pool includes
120 * NBL + NB + MDL + DATA + Context
121 * This is mainly used for Packet execute or slow path when copy is
122 * required and size is less than OVS_DEFAULT_DATA_SIZE. We expect
123 * Most of packet from user space will use this Pool. (This is
124 * true for all bfd and cfm packet.
126 RtlZeroMemory(&nblParam, sizeof (nblParam));
127 OVS_INIT_OBJECT_HEADER(&nblParam.Header,
128 NDIS_OBJECT_TYPE_DEFAULT,
129 NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1,
130 NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1);
131 nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE;
132 nblParam.PoolTag = OVS_FIX_SIZE_NBL_POOL_TAG;
133 nblParam.fAllocateNetBuffer = TRUE;
134 nblParam.DataSize = OVS_DEFAULT_DATA_SIZE + OVS_DEFAULT_HEADROOM_SIZE;
136 ovsPool->fixSizePool =
137 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
138 if (ovsPool->fixSizePool == NULL) {
143 * Zero Size NBL Pool includes
145 * This is mainly for packet with large data Size, in this case MDL and
146 * Data will be allocate separately.
148 RtlZeroMemory(&nblParam, sizeof (nblParam));
149 OVS_INIT_OBJECT_HEADER(&nblParam.Header,
150 NDIS_OBJECT_TYPE_DEFAULT,
151 NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1,
152 NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1);
154 nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE;
155 nblParam.PoolTag = OVS_VARIABLE_SIZE_NBL_POOL_TAG;
156 nblParam.fAllocateNetBuffer = TRUE;
157 nblParam.DataSize = 0;
159 ovsPool->zeroSizePool =
160 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
161 if (ovsPool->zeroSizePool == NULL) {
166 * NBL only pool just includes
168 * This is mainly used for clone and partial copy
170 RtlZeroMemory(&nblParam, sizeof (nblParam));
171 OVS_INIT_OBJECT_HEADER(&nblParam.Header,
172 NDIS_OBJECT_TYPE_DEFAULT,
173 NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1,
174 NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1);
176 nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE;
177 nblParam.PoolTag = OVS_NBL_ONLY_POOL_TAG;
178 nblParam.fAllocateNetBuffer = FALSE;
179 nblParam.DataSize = 0;
181 ovsPool->nblOnlyPool =
182 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
183 if (ovsPool->nblOnlyPool == NULL) {
188 * NB only pool, used for copy
191 OVS_INIT_OBJECT_HEADER(&nbParam.Header,
192 NDIS_OBJECT_TYPE_DEFAULT,
193 NET_BUFFER_POOL_PARAMETERS_REVISION_1,
194 NDIS_SIZEOF_NET_BUFFER_POOL_PARAMETERS_REVISION_1);
195 nbParam.PoolTag = OVS_NET_BUFFER_POOL_TAG;
196 nbParam.DataSize = 0;
198 NdisAllocateNetBufferPool(context->NdisSwitchContext, &nbParam);
199 if (ovsPool->nbPool == NULL) {
202 OVS_LOG_TRACE("Exit: fixSizePool: %p zeroSizePool: %p nblOnlyPool: %p"
203 "nbPool: %p", ovsPool->fixSizePool, ovsPool->zeroSizePool,
204 ovsPool->nblOnlyPool, ovsPool->nbPool);
205 return NDIS_STATUS_SUCCESS;
208 OvsCleanupBufferPool(context);
209 OVS_LOG_TRACE("Exit: Fail to initialize ovs buffer pool");
210 return NDIS_STATUS_RESOURCES;
215 * --------------------------------------------------------------------------
216 * OvsCleanupBufferPool --
217 * Free Buffer pool for NBL and NB.
218 * --------------------------------------------------------------------------
221 OvsCleanupBufferPool(PVOID ovsContext)
223 POVS_NBL_POOL ovsPool;
224 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
225 ovsPool = &context->ovsPool;
226 OVS_LOG_TRACE("Enter: context: %p", context);
228 ASSERT(ovsPool->fixNBLCount == 0);
229 ASSERT(ovsPool->zeroNBLCount == 0);
230 ASSERT(ovsPool->nblOnlyCount == 0);
231 ASSERT(ovsPool->nbCount == 0);
232 ASSERT(ovsPool->sysNBLCount == 0);
233 ASSERT(ovsPool->fragNBLCount == 0);
236 if (ovsPool->fixSizePool) {
237 NdisFreeNetBufferListPool(ovsPool->fixSizePool);
238 ovsPool->fixSizePool = NULL;
240 if (ovsPool->zeroSizePool) {
241 NdisFreeNetBufferListPool(ovsPool->zeroSizePool);
242 ovsPool->zeroSizePool = NULL;
244 if (ovsPool->nblOnlyPool) {
245 NdisFreeNetBufferListPool(ovsPool->nblOnlyPool);
246 ovsPool->nblOnlyPool = NULL;
248 if (ovsPool->nbPool) {
249 NdisFreeNetBufferPool(ovsPool->nbPool);
250 ovsPool->nbPool = NULL;
252 OVS_LOG_TRACE("Exit: cleanup OVS Buffer pool");
257 OvsInitNBLContext(POVS_BUFFER_CONTEXT ctx,
259 UINT32 origDataLength,
262 ctx->magic = OVS_CTX_MAGIC;
265 ctx->srcPortNo = srcPortNo;
266 ctx->origDataLength = origDataLength;
271 OvsDumpForwardingDetails(PNET_BUFFER_LIST nbl)
273 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
274 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
278 OVS_LOG_INFO("nbl: %p, numAvailableDest: %d, srcId:%d, srcIndex: %d "
279 "isDataSafe: %s, safeDataSize: %d",
280 nbl, info->NumAvailableDestinations, info->SourcePortId,
281 info->SourceNicIndex,
282 info->IsPacketDataSafe ? "TRUE" : "FALSE",
283 info->IsPacketDataSafe ? 0 : info->SafePacketDataSize);
288 OvsDumpNBLContext(PNET_BUFFER_LIST nbl)
290 PNET_BUFFER_LIST_CONTEXT ctx = nbl->Context;
292 OVS_LOG_INFO("No Net Buffer List context");
296 OVS_LOG_INFO("nbl: %p, ctx: %p, TotalSize: %d, Offset: %d",
297 nbl, ctx, ctx->Size, ctx->Offset);
304 OvsDumpMDLChain(PMDL mdl)
309 OVS_LOG_INFO("MDL: %p, Size: %d, MappedSystemVa: %p, StartVa: %p"
310 " ByteCount: %d, ByteOffset: %d",
311 tmp, tmp->Size, tmp->MappedSystemVa,
312 tmp->StartVa, tmp->ByteCount, tmp->ByteOffset);
319 OvsDumpNetBuffer(PNET_BUFFER nb)
321 OVS_LOG_INFO("NET_BUFFER: %p, ChecksumBias: %d Handle: %p, MDLChain: %p "
322 "CurrMDL: %p, CurrOffset: %d, DataLen: %d, Offset: %d",
324 NET_BUFFER_CHECKSUM_BIAS(nb), nb->NdisPoolHandle,
325 NET_BUFFER_FIRST_MDL(nb),
326 NET_BUFFER_CURRENT_MDL(nb),
327 NET_BUFFER_CURRENT_MDL_OFFSET(nb),
328 NET_BUFFER_DATA_LENGTH(nb),
329 NET_BUFFER_DATA_OFFSET(nb));
330 OvsDumpMDLChain(NET_BUFFER_FIRST_MDL(nb));
335 OvsDumpNetBufferList(PNET_BUFFER_LIST nbl)
338 OVS_LOG_INFO("NBL: %p, parent: %p, SrcHandle: %p, ChildCount:%d "
340 nbl, nbl->ParentNetBufferList,
341 nbl->SourceHandle, nbl->ChildRefCount,
342 nbl->NdisPoolHandle);
343 OvsDumpNBLContext(nbl);
344 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
346 OvsDumpNetBuffer(nb);
347 nb = NET_BUFFER_NEXT_NB(nb);
352 * --------------------------------------------------------------------------
353 * OvsAllocateFixSizeNBL --
355 * Allocate fix size NBL which include
356 * NBL + NB + MBL + Data + Context
358 * * Forwarding Context is allocated, but forwarding detail information
359 * is not initailized.
360 * * The headroom can not be larger than OVS_DEFAULT_HEADROOM_SIZE(128
362 * --------------------------------------------------------------------------
365 OvsAllocateFixSizeNBL(PVOID ovsContext,
369 PNET_BUFFER_LIST nbl = NULL;
370 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
371 POVS_BUFFER_CONTEXT ctx;
372 POVS_NBL_POOL ovsPool = &context->ovsPool;
375 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
377 if ((headRoom + size) > OVS_FIX_NBL_DATA_SIZE || size == 0) {
382 nbl = NdisAllocateNetBufferList(ovsPool->fixSizePool,
383 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
384 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
391 nbl->SourceHandle = ovsPool->ndisHandle;
392 status = context->NdisSwitchHandlers.
393 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
395 if (status != NDIS_STATUS_SUCCESS) {
396 NdisFreeNetBufferList(nbl);
401 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
403 info->IsPacketDataSafe = TRUE;
404 info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
406 status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
408 ASSERT(status == NDIS_STATUS_SUCCESS);
411 InterlockedIncrement((LONG volatile *)&ovsPool->fixNBLCount);
412 OvsDumpNetBufferList(nbl);
413 OvsDumpForwardingDetails(nbl);
416 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
419 OvsInitNBLContext(ctx, OVS_BUFFER_FROM_FIX_SIZE_POOL |
420 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT, size,
421 OVS_DEFAULT_PORT_NO);
424 OVS_LOG_LOUD("Allocate Fix NBL: %p, line: %d", nbl, line);
430 OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle,
436 data = OvsAllocateMemoryWithTag(dataSize, OVS_MDL_POOL_TAG);
441 mdl = NdisAllocateMdl(ndisHandle, data, dataSize);
443 OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
451 OvsFreeMDLAndData(PMDL mdl)
455 data = MmGetMdlVirtualAddress(mdl);
457 OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
462 * --------------------------------------------------------------------------
463 * OvsAllocateVariableSizeNBL --
465 * Allocate variable size NBL, the NBL looks like
468 * --------------------------------------------------------------------------
471 OvsAllocateVariableSizeNBL(PVOID ovsContext,
475 PNET_BUFFER_LIST nbl = NULL;
476 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
477 POVS_NBL_POOL ovsPool = &context->ovsPool;
478 POVS_BUFFER_CONTEXT ctx;
482 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
486 realSize = MEM_ALIGN_SIZE(size + headRoom);
488 mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, realSize);
493 nbl = NdisAllocateNetBufferAndNetBufferList(ovsPool->zeroSizePool,
494 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
495 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL,
498 OvsFreeMDLAndData(mdl);
502 nbl->SourceHandle = ovsPool->ndisHandle;
503 status = context->NdisSwitchHandlers.
504 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
506 if (status != NDIS_STATUS_SUCCESS) {
508 * do we need to remove mdl from nbl XXX
510 OvsFreeMDLAndData(mdl);
511 NdisFreeNetBufferList(nbl);
515 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
517 info->IsPacketDataSafe = TRUE;
518 info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
519 status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
521 ASSERT(status == NDIS_STATUS_SUCCESS);
524 InterlockedIncrement((LONG volatile *)&ovsPool->zeroNBLCount);
525 OvsDumpNetBufferList(nbl);
526 OvsDumpForwardingDetails(nbl);
529 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
531 OvsInitNBLContext(ctx, OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
532 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT |
533 OVS_BUFFER_FROM_ZERO_SIZE_POOL,
534 size, OVS_DEFAULT_PORT_NO);
536 OVS_LOG_LOUD("Allocate variable size NBL: %p", nbl);
542 * --------------------------------------------------------------------------
543 * OvsInitExternalNBLContext --
545 * For NBL not allocated by OVS, it will allocate and initialize
547 * --------------------------------------------------------------------------
550 OvsInitExternalNBLContext(PVOID ovsContext,
551 PNET_BUFFER_LIST nbl,
554 NDIS_HANDLE poolHandle;
555 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
556 POVS_BUFFER_CONTEXT ctx;
561 poolHandle = NdisGetPoolFromNetBufferList(nbl);
563 if (poolHandle == context->ovsPool.ndisHandle) {
564 return (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
566 status = NdisAllocateNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT),
567 OVS_DEFAULT_NBL_CONTEXT_FILL,
569 if (status != NDIS_STATUS_SUCCESS) {
573 OvsDumpNBLContext(nbl);
574 InterlockedIncrement((LONG volatile *)&context->ovsPool.sysNBLCount);
576 flags = isRecv ? OVS_BUFFER_RECV_BUFFER : OVS_BUFFER_SEND_BUFFER;
577 flags |= OVS_BUFFER_NEED_COMPLETE | OVS_BUFFER_PRIVATE_CONTEXT;
578 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
580 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
582 * we use first nb to decide whether we need advance or retreat during
585 OvsInitNBLContext(ctx, flags, NET_BUFFER_DATA_LENGTH(nb), OVS_DEFAULT_PORT_NO);
590 * --------------------------------------------------------------------------
591 * OvsAllocateNBLContext
593 * Create NBL buffer context and forwarding context.
594 * --------------------------------------------------------------------------
597 OvsAllocateNBLContext(POVS_SWITCH_CONTEXT context,
598 PNET_BUFFER_LIST nbl)
600 POVS_NBL_POOL ovsPool = &context->ovsPool;
603 status = NdisAllocateNetBufferListContext(nbl,
604 sizeof (OVS_BUFFER_CONTEXT),
605 OVS_DEFAULT_NBL_CONTEXT_FILL,
607 if (status != NDIS_STATUS_SUCCESS) {
608 return NDIS_STATUS_FAILURE;
611 nbl->SourceHandle = ovsPool->ndisHandle;
612 status = context->NdisSwitchHandlers.
613 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
615 if (status != NDIS_STATUS_SUCCESS) {
616 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
617 return NDIS_STATUS_FAILURE;
623 * --------------------------------------------------------------------------
626 * Free the NBL buffer context and forwarding context.
627 * --------------------------------------------------------------------------
630 OvsFreeNBLContext(POVS_SWITCH_CONTEXT context,
631 PNET_BUFFER_LIST nbl)
633 POVS_NBL_POOL ovsPool = &context->ovsPool;
635 context->NdisSwitchHandlers.
636 FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
637 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
639 return NDIS_STATUS_SUCCESS;
643 * --------------------------------------------------------------------------
646 * Copy NBL info from src to dst
647 * --------------------------------------------------------------------------
650 OvsCopyNBLInfo(PNET_BUFFER_LIST srcNbl, PNET_BUFFER_LIST dstNbl,
651 POVS_BUFFER_CONTEXT srcCtx, UINT32 copySize,
654 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO srcInfo, dstInfo;
655 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
657 srcInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(srcNbl);
658 dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(dstNbl);
660 #ifdef OVS_USE_COPY_NET_BUFFER_LIST_INFO
661 status = context->NdisSwitchHandlers.
662 CopyNetBufferListInfo(ovsPool->ndisContext, dstNbl, srcNbl, 0);
664 if (status != NDIS_STATUS_SUCCESS) {
668 dstInfo->SourcePortId = srcInfo->SourcePortId;
669 dstInfo->SourceNicIndex = srcInfo->SourceNicIndex;
671 if (srcCtx->flags & OVS_BUFFER_RECV_BUFFER) {
672 NdisCopyReceiveNetBufferListInfo(dstNbl, srcNbl);
673 } else if (srcCtx->flags & OVS_BUFFER_SEND_BUFFER) {
674 NdisCopySendNetBufferListInfo(dstNbl, srcNbl);
678 dstInfo->IsPacketDataSafe = srcInfo->IsPacketDataSafe;
679 if (!srcInfo->IsPacketDataSafe && copySize >
680 srcInfo->SafePacketDataSize) {
681 srcInfo->SafePacketDataSize = copySize;
685 * Assume all data are safe
687 dstInfo->IsPacketDataSafe = TRUE;
688 dstInfo->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
694 * --------------------------------------------------------------------------
695 * OvsPartialCopyNBL --
697 * Partial copy NBL, if there is multiple NB in NBL, each one will be
698 * copied. We also reserve headroom for the new NBL.
701 * NBL should have OVS_BUFFER_CONTEXT setup before calling
703 * The NBL should already have ref to itself so that during copy
704 * it will not be freed.
705 * --------------------------------------------------------------------------
708 OvsPartialCopyNBL(PVOID ovsContext,
709 PNET_BUFFER_LIST nbl,
714 PNET_BUFFER_LIST newNbl;
715 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
717 PNET_BUFFER srcNb, dstNb;
719 POVS_NBL_POOL ovsPool = &context->ovsPool;
720 POVS_BUFFER_CONTEXT srcCtx, dstCtx;
723 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
724 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
725 OVS_LOG_INFO("src nbl must have ctx initialized");
726 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
731 NdisAdvanceNetBufferListDataStart(nbl, copySize, FALSE, NULL);
733 newNbl = NdisAllocateCloneNetBufferList(nbl, ovsPool->nblOnlyPool,
736 status = NdisRetreatNetBufferListDataStart(nbl, copySize, 0,
738 ASSERT(status == NDIS_STATUS_SUCCESS);
741 if (newNbl == NULL) {
746 * Allocate private memory for copy
748 if (copySize + headRoom) {
749 status = NdisRetreatNetBufferListDataStart(newNbl, copySize + headRoom,
751 if (status != NDIS_STATUS_SUCCESS) {
756 NdisAdvanceNetBufferListDataStart(newNbl, headRoom, FALSE, NULL);
759 srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
760 dstNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
763 status = NdisCopyFromNetBufferToNetBuffer(dstNb, 0, copySize,
766 if (status != NDIS_STATUS_SUCCESS || copySize != byteCopied) {
767 goto nbl_context_error;
769 srcNb = NET_BUFFER_NEXT_NB(srcNb);
770 dstNb = NET_BUFFER_NEXT_NB(dstNb);
775 status = OvsAllocateNBLContext(context, newNbl);
776 if (status != NDIS_STATUS_SUCCESS) {
777 goto nbl_context_error;
780 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copySize, copyNblInfo);
781 if (status != NDIS_STATUS_SUCCESS) {
782 goto copy_list_info_error;
786 InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
789 newNbl->ParentNetBufferList = nbl;
791 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
792 ASSERT(dstCtx != NULL);
794 flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
796 flags |= OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_CONTEXT |
797 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;
799 srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
800 OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(srcNb) - copySize,
801 OVS_DEFAULT_PORT_NO);
803 InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
805 OvsDumpNetBufferList(nbl);
806 OvsDumpForwardingDetails(nbl);
808 OvsDumpNetBufferList(newNbl);
809 OvsDumpForwardingDetails(newNbl);
811 OVS_LOG_LOUD("Partial Copy new NBL: %p", newNbl);
814 copy_list_info_error:
815 OvsFreeNBLContext(context, newNbl);
818 NdisAdvanceNetBufferListDataStart(newNbl, copySize, TRUE, NULL);
821 NdisFreeCloneNetBufferList(newNbl, 0);
826 * --------------------------------------------------------------------------
827 * OvsPartialCopyToMultipleNBLs --
829 * This is similar to OvsPartialCopyNBL() except that each NB will
831 * --------------------------------------------------------------------------
834 OvsPartialCopyToMultipleNBLs(PVOID ovsContext,
835 PNET_BUFFER_LIST nbl,
840 PNET_BUFFER nb, nextNb = NULL, firstNb, prevNb;
841 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
842 PNET_BUFFER_LIST firstNbl = NULL, newNbl, prevNbl = NULL;
844 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
845 if (NET_BUFFER_NEXT_NB(nb) == NULL) {
846 return OvsPartialCopyNBL(context, nbl, copySize, headRoom, copyNblInfo);
853 nextNb = NET_BUFFER_NEXT_NB(nb);
854 NET_BUFFER_NEXT_NB(nb) = NULL;
856 NET_BUFFER_LIST_FIRST_NB(nbl) = nb;
858 newNbl = OvsPartialCopyNBL(context, nbl, copySize, headRoom,
860 if (newNbl == NULL) {
863 if (prevNbl == NULL) {
866 NET_BUFFER_LIST_NEXT_NBL(prevNbl) = nbl;
867 NET_BUFFER_NEXT_NB(prevNb) = nb;
873 NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;
877 NET_BUFFER_NEXT_NB(prevNb) = nb;
878 NET_BUFFER_NEXT_NB(nb) = nextNb;
879 NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;
883 firstNbl = NET_BUFFER_LIST_NEXT_NBL(newNbl);
884 NET_BUFFER_LIST_NEXT_NBL(firstNbl) = NULL;
885 OvsCompleteNBL(context, newNbl, TRUE);
892 static PNET_BUFFER_LIST
893 OvsCopySinglePacketNBL(PVOID ovsContext,
894 PNET_BUFFER_LIST nbl,
901 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
902 PNET_BUFFER_LIST newNbl;
905 POVS_BUFFER_CONTEXT srcCtx, dstCtx;
907 size = NET_BUFFER_DATA_LENGTH(nb);
908 if ((size + headRoom) <= OVS_FIX_NBL_DATA_SIZE) {
909 newNbl = OvsAllocateFixSizeNBL(context, size, headRoom);
911 newNbl = OvsAllocateVariableSizeNBL(context, size, headRoom);
913 if (newNbl == NULL) {
916 newNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
917 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
920 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
921 if (status == NDIS_STATUS_SUCCESS) {
922 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copiedSize, copyNblInfo);
925 if (status != NDIS_STATUS_SUCCESS || copiedSize != size) {
926 OvsCompleteNBL(context, newNbl, TRUE);
930 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
931 ASSERT(dstCtx && srcCtx);
932 ASSERT(srcCtx->magic == OVS_CTX_MAGIC && dstCtx->magic == OVS_CTX_MAGIC);
934 dstCtx->flags |= srcCtx->flags & (OVS_BUFFER_RECV_BUFFER |
935 OVS_BUFFER_SEND_BUFFER);
937 OvsDumpNetBufferList(newNbl);
938 OvsDumpForwardingDetails(newNbl);
940 OVS_LOG_LOUD("Copy single nb to new NBL: %p", newNbl);
945 * --------------------------------------------------------------------------
948 * Copy the NBL to a new NBL including data.
951 * The NBL can have multiple NBs, but the final result is one NBL.
952 * --------------------------------------------------------------------------
955 OvsFullCopyNBL(PVOID ovsContext,
956 PNET_BUFFER_LIST nbl,
960 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
961 POVS_NBL_POOL ovsPool = &context->ovsPool;
962 PNET_BUFFER_LIST newNbl;
963 PNET_BUFFER nb, newNb, firstNb = NULL, prevNb = NULL;
964 POVS_BUFFER_CONTEXT dstCtx, srcCtx;
967 UINT32 size, totalSize;
970 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo;
972 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
973 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
974 OVS_LOG_INFO("src nbl must have ctx initialized");
975 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
979 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
981 if (NET_BUFFER_NEXT_NB(nb) == NULL) {
982 return OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
985 newNbl = NdisAllocateNetBufferList(ovsPool->nblOnlyPool,
986 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
987 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
988 if (newNbl == NULL) {
993 size = NET_BUFFER_DATA_LENGTH(nb);
994 totalSize = MEM_ALIGN_SIZE(size + headRoom);
995 mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, totalSize);
1000 newNb = NdisAllocateNetBuffer(ovsPool->nbPool, mdl, totalSize, 0);
1001 if (newNb == NULL) {
1002 OvsFreeMDLAndData(mdl);
1005 if (firstNb == NULL) {
1008 NET_BUFFER_NEXT_NB(prevNb) = newNb;
1012 InterlockedIncrement((LONG volatile *)&ovsPool->nbCount);
1014 status = NdisRetreatNetBufferDataStart(newNb, size, 0, NULL);
1015 ASSERT(status == NDIS_STATUS_SUCCESS);
1017 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
1019 if (status != NDIS_STATUS_SUCCESS || size != copiedSize) {
1023 nb = NET_BUFFER_NEXT_NB(nb);
1026 NET_BUFFER_LIST_FIRST_NB(newNbl) = firstNb;
1028 newNbl->SourceHandle = ovsPool->ndisHandle;
1029 status = context->NdisSwitchHandlers.
1030 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, newNbl);
1032 if (status != NDIS_STATUS_SUCCESS) {
1036 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, 0, copyNblInfo);
1037 if (status != NDIS_STATUS_SUCCESS) {
1041 dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl);
1042 dstInfo->IsPacketDataSafe = TRUE;
1044 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
1046 flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
1048 flags |= OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
1049 OVS_BUFFER_PRIVATE_NET_BUFFER | OVS_BUFFER_FROM_NBL_ONLY_POOL |
1050 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;
1052 OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(firstNb),
1053 OVS_DEFAULT_PORT_NO);
1056 OvsDumpNetBufferList(nbl);
1057 OvsDumpForwardingDetails(nbl);
1058 InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
1060 OVS_LOG_LOUD("newNbl: %p", newNbl);
1066 InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
1069 firstNb = NET_BUFFER_NEXT_NB(prevNb);
1070 mdl = NET_BUFFER_FIRST_MDL(prevNb);
1071 NET_BUFFER_FIRST_MDL(prevNb) = NULL;
1072 NdisFreeNetBuffer(prevNb);
1073 OvsFreeMDLAndData(mdl);
1075 NdisFreeNetBufferList(newNbl);
1076 OVS_LOG_ERROR("OvsFullCopyNBL failed");
1081 * --------------------------------------------------------------------------
1082 * GetSegmentHeaderInfo
1084 * Extract header size and sequence number for the segment.
1085 * --------------------------------------------------------------------------
1088 GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl,
1089 const POVS_PACKET_HDR_INFO hdrInfo,
1090 UINT32 *hdrSize, UINT32 *seqNumber)
1095 /* Parse the orginal Eth/IP/TCP header */
1096 tcp = OvsGetPacketBytes(nbl, sizeof *tcp, hdrInfo->l4Offset, &tcpStorage);
1098 return NDIS_STATUS_FAILURE;
1100 *seqNumber = ntohl(tcp->seq);
1101 *hdrSize = hdrInfo->l4Offset + TCP_HDR_LEN(tcp);
1103 return NDIS_STATUS_SUCCESS;
1108 * --------------------------------------------------------------------------
1111 * Fix IP length, IP checksum, TCP sequence number and TCP checksum
1113 * --------------------------------------------------------------------------
1116 FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber)
1124 mdl = NET_BUFFER_FIRST_MDL(nb);
1126 bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(mdl, LowPagePriority);
1128 return NDIS_STATUS_RESOURCES;
1130 dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb));
1131 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1132 >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr));
1133 dstIP = (IPHdr *)((PCHAR)dstEth + sizeof *dstEth);
1134 dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4);
1135 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1136 >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
1138 /* Fix IP length and checksum */
1139 ASSERT(dstIP->protocol == IPPROTO_TCP);
1140 dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
1142 dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);
1144 /* Fix TCP checksum */
1145 dstTCP->seq = htonl(seqNumber);
1147 IPPseudoChecksum((UINT32 *)&dstIP->saddr,
1148 (UINT32 *)&dstIP->daddr,
1149 IPPROTO_TCP, segmentSize + TCP_HDR_LEN(dstTCP));
1150 dstTCP->check = CalculateChecksumNB(nb,
1151 (UINT16)(NET_BUFFER_DATA_LENGTH(nb) - sizeof *dstEth - dstIP->ihl * 4),
1152 sizeof *dstEth + dstIP->ihl * 4);
1153 return STATUS_SUCCESS;
1157 * --------------------------------------------------------------------------
1158 * OvsTcpSegmentyNBL --
1160 * Segment TCP payload, and prepend each segment with ether/IP/TCP header.
1161 * Leave headRoom for additional encap.
1164 * NBL should have OVS_BUFFER_CONTEXT setup before calling
1166 * The NBL should already have ref to itself so that during copy
1167 * it will not be freed.
1168 * Currently this API assert there is only one NB in an NBL, it needs
1169 * to be fixed if we receive multiple NBs in an NBL.
1170 * --------------------------------------------------------------------------
1173 OvsTcpSegmentNBL(PVOID ovsContext,
1174 PNET_BUFFER_LIST nbl,
1175 POVS_PACKET_HDR_INFO hdrInfo,
1179 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
1181 POVS_NBL_POOL ovsPool = &context->ovsPool;
1183 POVS_BUFFER_CONTEXT dstCtx, srcCtx;
1184 UINT32 size, hdrSize, seqNumber;
1185 PNET_BUFFER_LIST newNbl;
1186 PNET_BUFFER nb, newNb;
1191 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1192 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
1193 OVS_LOG_INFO("src nbl must have ctx initialized");
1194 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
1198 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1199 ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL);
1201 /* Figure out the segment header size */
1202 status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber);
1203 if (status != NDIS_STATUS_SUCCESS) {
1204 OVS_LOG_INFO("Cannot parse NBL header");
1208 size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize;
1210 /* XXX add to ovsPool counters? */
1211 newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL,
1212 NULL, hdrSize, mss, hdrSize + headRoom , 0, 0);
1213 if (newNbl == NULL) {
1217 /* Now deal with TCP payload */
1218 for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL;
1219 newNb = NET_BUFFER_NEXT_NB(newNb)) {
1220 segmentSize = (size > mss ? mss : size) & 0xffff;
1222 NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL);
1225 /* Now copy the eth/IP/TCP header and fix up */
1226 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize, nb, 0,
1228 if (status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize) {
1232 status = FixSegmentHeader(newNb, segmentSize, seqNumber);
1233 if (status != NDIS_STATUS_SUCCESS) {
1238 /* Move on to the next segment */
1239 size -= segmentSize;
1240 seqNumber += segmentSize;
1243 status = OvsAllocateNBLContext(context, newNbl);
1244 if (status != NDIS_STATUS_SUCCESS) {
1248 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, hdrSize + headRoom, FALSE);
1249 if (status != NDIS_STATUS_SUCCESS) {
1250 goto nbl_context_error;
1253 newNbl->ParentNetBufferList = nbl;
1255 /* Remember it's a fragment NBL so we can free it properly */
1256 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
1257 ASSERT(dstCtx != NULL);
1258 dstCtx->flags = OVS_BUFFER_FRAGMENT | OVS_BUFFER_PRIVATE_CONTEXT |
1259 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | OVS_BUFFER_SEND_BUFFER;
1260 dstCtx->refCount = 1;
1261 dstCtx->magic = OVS_CTX_MAGIC;
1262 dstCtx->dataOffsetDelta = hdrSize + headRoom;
1264 InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
1266 InterlockedIncrement((LONG volatile *)&ovsPool->fragNBLCount);
1268 OvsDumpNetBufferList(nbl);
1269 OvsDumpForwardingDetails(nbl);
1271 OvsDumpNetBufferList(newNbl);
1272 OvsDumpForwardingDetails(newNbl);
1274 OVS_LOG_TRACE("Segment nbl %p to newNbl: %p", nbl, newNbl);
1278 OvsFreeNBLContext(context, newNbl);
1281 InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
1283 NdisFreeFragmentNetBufferList(newNbl, hdrSize + headRoom, 0);
1289 * --------------------------------------------------------------------------
1290 * OvsFullCopyToMultipleNBLs --
1292 * Copy NBL to multiple NBLs, each NB will have its own NBL
1293 * --------------------------------------------------------------------------
1296 OvsFullCopyToMultipleNBLs(PVOID ovsContext,
1297 PNET_BUFFER_LIST nbl,
1299 BOOLEAN copyNblInfo)
1302 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
1303 PNET_BUFFER_LIST firstNbl, currNbl, newNbl;
1305 POVS_BUFFER_CONTEXT srcCtx;
1307 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1308 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
1309 OVS_LOG_INFO("src nbl must have ctx initialized");
1310 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
1314 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1315 newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
1317 if (newNbl == NULL || NET_BUFFER_NEXT_NB(nb) == NULL) {
1325 newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom,
1327 if (newNbl == NULL) {
1328 goto copymultiple_error;
1330 NET_BUFFER_LIST_NEXT_NBL(currNbl) = newNbl;
1332 nb = NET_BUFFER_NEXT_NB(nb);
1339 firstNbl = NET_BUFFER_LIST_NEXT_NBL(firstNbl);
1340 NET_BUFFER_LIST_NEXT_NBL(currNbl) = NULL;
1341 OvsCompleteNBL(context, currNbl, TRUE);
1349 * --------------------------------------------------------------------------
1352 * This function tries to free the NBL allocated by OVS buffer
1353 * management module. If it trigger the completion of the parent
1354 * NBL, it will recursively call itself. If it trigger the completion
1355 * of external NBL, it will be returned to the caller. The caller
1356 * is responsible to call API to return to upper layer.
1357 * --------------------------------------------------------------------------
1360 OvsCompleteNBL(POVS_SWITCH_CONTEXT context,
1361 PNET_BUFFER_LIST nbl,
1364 POVS_BUFFER_CONTEXT ctx;
1366 PNET_BUFFER_LIST parent;
1368 NDIS_HANDLE poolHandle;
1370 POVS_NBL_POOL ovsPool = &context->ovsPool;
1374 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1376 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1378 OVS_LOG_TRACE("Enter: nbl: %p, ctx: %p, refCount: %d, updateRef:%d",
1379 nbl, ctx, ctx->refCount, updateRef);
1382 value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
1388 * This is a special case, the refCount must be zero
1390 ASSERT(ctx->refCount == 0);
1393 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1396 if (!(flags & OVS_BUFFER_FRAGMENT) &&
1397 NET_BUFFER_DATA_LENGTH(nb) != ctx->origDataLength) {
1399 if (NET_BUFFER_DATA_LENGTH(nb) < ctx->origDataLength) {
1400 diff = ctx->origDataLength -NET_BUFFER_DATA_LENGTH(nb);
1401 status = NdisRetreatNetBufferListDataStart(nbl, diff, 0,
1403 ASSERT(status == NDIS_STATUS_SUCCESS);
1405 diff = NET_BUFFER_DATA_LENGTH(nb) - ctx->origDataLength;
1406 NdisAdvanceNetBufferListDataStart(nbl, diff, TRUE, NULL);
1410 if (ctx->flags & OVS_BUFFER_PRIVATE_CONTEXT) {
1411 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
1414 if (flags & OVS_BUFFER_NEED_COMPLETE) {
1416 * return to caller for completion
1419 InterlockedDecrement((LONG volatile *)&ovsPool->sysNBLCount);
1424 if (flags & OVS_BUFFER_PRIVATE_FORWARD_CONTEXT) {
1425 context->NdisSwitchHandlers.
1426 FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
1429 if (flags & (OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA)) {
1430 PNET_BUFFER nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1432 PMDL mdl = NET_BUFFER_FIRST_MDL(nb);
1433 NET_BUFFER_FIRST_MDL(nb) = NULL;
1434 ASSERT(mdl->Next == NULL);
1435 OvsFreeMDLAndData(mdl);
1436 nb = NET_BUFFER_NEXT_NB(nb);
1440 if (flags & OVS_BUFFER_PRIVATE_NET_BUFFER) {
1441 PNET_BUFFER nb, nextNb;
1443 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1445 nextNb = NET_BUFFER_NEXT_NB(nb);
1446 NdisFreeNetBuffer(nb);
1448 InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
1452 NET_BUFFER_LIST_FIRST_NB(nbl) = NULL;
1455 parent = nbl->ParentNetBufferList;
1457 poolHandle = NdisGetPoolFromNetBufferList(nbl);
1458 if (flags & OVS_BUFFER_FROM_FIX_SIZE_POOL) {
1459 ASSERT(poolHandle == ovsPool->fixSizePool);
1461 InterlockedDecrement((LONG volatile *)&ovsPool->fixNBLCount);
1463 NdisFreeNetBufferList(nbl);
1464 } else if (flags & OVS_BUFFER_FROM_ZERO_SIZE_POOL) {
1465 ASSERT(poolHandle == ovsPool->zeroSizePool);
1467 InterlockedDecrement((LONG volatile *)&ovsPool->zeroNBLCount);
1469 NdisFreeNetBufferList(nbl);
1470 } else if (flags & OVS_BUFFER_FROM_NBL_ONLY_POOL) {
1471 ASSERT(poolHandle == ovsPool->nblOnlyPool);
1473 InterlockedDecrement((LONG volatile *)&ovsPool->nblOnlyCount);
1475 NdisFreeCloneNetBufferList(nbl, 0);
1476 } else if (flags & OVS_BUFFER_FRAGMENT) {
1477 OVS_LOG_TRACE("Free fragment %p parent %p", nbl, parent);
1479 InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
1481 NdisFreeFragmentNetBufferList(nbl, ctx->dataOffsetDelta, 0);
1484 if (parent != NULL) {
1485 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(parent);
1486 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1487 value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
1489 return OvsCompleteNBL(context, parent, FALSE);
1496 * --------------------------------------------------------------------------
1497 * OvsSetCtxSourcePortNo --
1498 * Setter function which stores the source port of an NBL in the NBL
1500 * --------------------------------------------------------------------------
1503 OvsSetCtxSourcePortNo(PNET_BUFFER_LIST nbl,
1506 POVS_BUFFER_CONTEXT ctx;
1507 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1509 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1510 return STATUS_INVALID_PARAMETER;
1513 ctx->srcPortNo = portNo;
1514 return NDIS_STATUS_SUCCESS;
1518 * --------------------------------------------------------------------------
1519 * OvsGetCtxSourcePortNo --
1520 * Get source port of an NBL from its Context Info.
1521 * --------------------------------------------------------------------------
1524 OvsGetCtxSourcePortNo(PNET_BUFFER_LIST nbl,
1527 POVS_BUFFER_CONTEXT ctx;
1528 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1529 if (ctx == NULL || portNo == NULL) {
1530 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1531 return STATUS_INVALID_PARAMETER;
1533 *portNo = ctx->srcPortNo;
1534 return NDIS_STATUS_SUCCESS;