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
;
274 OvsDumpForwardingDetails(PNET_BUFFER_LIST nbl
)
276 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info
;
277 info
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl
);
281 OVS_LOG_INFO("nbl: %p, numAvailableDest: %d, srcId:%d, srcIndex: %d "
282 "isDataSafe: %s, safeDataSize: %d",
283 nbl
, info
->NumAvailableDestinations
, info
->SourcePortId
,
284 info
->SourceNicIndex
,
285 info
->IsPacketDataSafe
? "TRUE" : "FALSE",
286 info
->IsPacketDataSafe
? 0 : info
->SafePacketDataSize
);
291 OvsDumpNBLContext(PNET_BUFFER_LIST nbl
)
293 PNET_BUFFER_LIST_CONTEXT ctx
= nbl
->Context
;
295 OVS_LOG_INFO("No Net Buffer List context");
299 OVS_LOG_INFO("nbl: %p, ctx: %p, TotalSize: %d, Offset: %d",
300 nbl
, ctx
, ctx
->Size
, ctx
->Offset
);
307 OvsDumpMDLChain(PMDL mdl
)
312 OVS_LOG_INFO("MDL: %p, Size: %d, MappedSystemVa: %p, StartVa: %p"
313 " ByteCount: %d, ByteOffset: %d",
314 tmp
, tmp
->Size
, tmp
->MappedSystemVa
,
315 tmp
->StartVa
, tmp
->ByteCount
, tmp
->ByteOffset
);
322 OvsDumpNetBuffer(PNET_BUFFER nb
)
324 OVS_LOG_INFO("NET_BUFFER: %p, ChecksumBias: %d Handle: %p, MDLChain: %p "
325 "CurrMDL: %p, CurrOffset: %d, DataLen: %d, Offset: %d",
327 NET_BUFFER_CHECKSUM_BIAS(nb
), nb
->NdisPoolHandle
,
328 NET_BUFFER_FIRST_MDL(nb
),
329 NET_BUFFER_CURRENT_MDL(nb
),
330 NET_BUFFER_CURRENT_MDL_OFFSET(nb
),
331 NET_BUFFER_DATA_LENGTH(nb
),
332 NET_BUFFER_DATA_OFFSET(nb
));
333 OvsDumpMDLChain(NET_BUFFER_FIRST_MDL(nb
));
338 OvsDumpNetBufferList(PNET_BUFFER_LIST nbl
)
341 OVS_LOG_INFO("NBL: %p, parent: %p, SrcHandle: %p, ChildCount:%d "
343 nbl
, nbl
->ParentNetBufferList
,
344 nbl
->SourceHandle
, nbl
->ChildRefCount
,
345 nbl
->NdisPoolHandle
);
346 OvsDumpNBLContext(nbl
);
347 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
349 OvsDumpNetBuffer(nb
);
350 nb
= NET_BUFFER_NEXT_NB(nb
);
355 * --------------------------------------------------------------------------
356 * OvsAllocateFixSizeNBL --
358 * Allocate fix size NBL which include
359 * NBL + NB + MBL + Data + Context
361 * * Forwarding Context is allocated, but forwarding detail information
362 * is not initailized.
363 * * The headroom can not be larger than OVS_DEFAULT_HEADROOM_SIZE(128
365 * --------------------------------------------------------------------------
368 OvsAllocateFixSizeNBL(PVOID ovsContext
,
372 PNET_BUFFER_LIST nbl
= NULL
;
373 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
374 POVS_BUFFER_CONTEXT ctx
;
375 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
378 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info
;
380 if ((headRoom
+ size
) > OVS_FIX_NBL_DATA_SIZE
|| size
== 0) {
385 nbl
= NdisAllocateNetBufferList(ovsPool
->fixSizePool
,
386 (UINT16
)sizeof (OVS_BUFFER_CONTEXT
),
387 (UINT16
)OVS_DEFAULT_NBL_CONTEXT_FILL
);
394 nbl
->SourceHandle
= ovsPool
->ndisHandle
;
395 status
= context
->NdisSwitchHandlers
.
396 AllocateNetBufferListForwardingContext(ovsPool
->ndisContext
, nbl
);
398 if (status
!= NDIS_STATUS_SUCCESS
) {
399 NdisFreeNetBufferList(nbl
);
404 info
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl
);
406 info
->IsPacketDataSafe
= TRUE
;
407 info
->SourcePortId
= NDIS_SWITCH_DEFAULT_PORT_ID
;
409 status
= NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl
),
411 ASSERT(status
== NDIS_STATUS_SUCCESS
);
414 InterlockedIncrement((LONG
volatile *)&ovsPool
->fixNBLCount
);
415 OvsDumpNetBufferList(nbl
);
416 OvsDumpForwardingDetails(nbl
);
419 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
422 OvsInitNBLContext(ctx
, OVS_BUFFER_FROM_FIX_SIZE_POOL
|
423 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
, size
,
424 OVS_DPPORT_NUMBER_INVALID
);
427 OVS_LOG_LOUD("Allocate Fix NBL: %p, line: %d", nbl
, line
);
433 OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle
,
439 data
= OvsAllocateMemoryWithTag(dataSize
, OVS_MDL_POOL_TAG
);
444 mdl
= NdisAllocateMdl(ndisHandle
, data
, dataSize
);
446 OvsFreeMemoryWithTag(data
, OVS_MDL_POOL_TAG
);
454 OvsFreeMDLAndData(PMDL mdl
)
458 data
= MmGetMdlVirtualAddress(mdl
);
460 OvsFreeMemoryWithTag(data
, OVS_MDL_POOL_TAG
);
465 * --------------------------------------------------------------------------
466 * OvsAllocateVariableSizeNBL --
468 * Allocate variable size NBL, the NBL looks like
471 * --------------------------------------------------------------------------
474 OvsAllocateVariableSizeNBL(PVOID ovsContext
,
478 PNET_BUFFER_LIST nbl
= NULL
;
479 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
480 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
481 POVS_BUFFER_CONTEXT ctx
;
485 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info
;
489 realSize
= MEM_ALIGN_SIZE(size
+ headRoom
);
491 mdl
= OvsAllocateMDLAndData(ovsPool
->ndisHandle
, realSize
);
496 nbl
= NdisAllocateNetBufferAndNetBufferList(ovsPool
->zeroSizePool
,
497 (UINT16
)sizeof (OVS_BUFFER_CONTEXT
),
498 (UINT16
)OVS_DEFAULT_NBL_CONTEXT_FILL
,
501 OvsFreeMDLAndData(mdl
);
505 nbl
->SourceHandle
= ovsPool
->ndisHandle
;
506 status
= context
->NdisSwitchHandlers
.
507 AllocateNetBufferListForwardingContext(ovsPool
->ndisContext
, nbl
);
509 if (status
!= NDIS_STATUS_SUCCESS
) {
511 * do we need to remove mdl from nbl XXX
513 OvsFreeMDLAndData(mdl
);
514 NdisFreeNetBufferList(nbl
);
518 info
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl
);
520 info
->IsPacketDataSafe
= TRUE
;
521 info
->SourcePortId
= NDIS_SWITCH_DEFAULT_PORT_ID
;
522 status
= NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl
),
524 ASSERT(status
== NDIS_STATUS_SUCCESS
);
527 InterlockedIncrement((LONG
volatile *)&ovsPool
->zeroNBLCount
);
528 OvsDumpNetBufferList(nbl
);
529 OvsDumpForwardingDetails(nbl
);
532 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
534 OvsInitNBLContext(ctx
, OVS_BUFFER_PRIVATE_MDL
| OVS_BUFFER_PRIVATE_DATA
|
535 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
|
536 OVS_BUFFER_FROM_ZERO_SIZE_POOL
,
537 size
, OVS_DPPORT_NUMBER_INVALID
);
539 OVS_LOG_LOUD("Allocate variable size NBL: %p", nbl
);
545 * --------------------------------------------------------------------------
546 * OvsInitExternalNBLContext --
548 * For NBL not allocated by OVS, it will allocate and initialize
550 * --------------------------------------------------------------------------
553 OvsInitExternalNBLContext(PVOID ovsContext
,
554 PNET_BUFFER_LIST nbl
,
557 NDIS_HANDLE poolHandle
;
558 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
559 POVS_BUFFER_CONTEXT ctx
;
564 poolHandle
= NdisGetPoolFromNetBufferList(nbl
);
566 if (poolHandle
== context
->ovsPool
.ndisHandle
||
567 nbl
->SourceHandle
== context
->ovsPool
.ndisHandle
) {
568 return (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
570 status
= NdisAllocateNetBufferListContext(nbl
, sizeof (OVS_BUFFER_CONTEXT
),
571 OVS_DEFAULT_NBL_CONTEXT_FILL
,
573 if (status
!= NDIS_STATUS_SUCCESS
) {
577 OvsDumpNBLContext(nbl
);
578 InterlockedIncrement((LONG
volatile *)&context
->ovsPool
.sysNBLCount
);
580 flags
= isRecv
? OVS_BUFFER_RECV_BUFFER
: OVS_BUFFER_SEND_BUFFER
;
581 flags
|= OVS_BUFFER_NEED_COMPLETE
| OVS_BUFFER_PRIVATE_CONTEXT
;
582 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
584 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
586 * we use first nb to decide whether we need advance or retreat during
589 OvsInitNBLContext(ctx
, flags
, NET_BUFFER_DATA_LENGTH(nb
),
590 OVS_DPPORT_NUMBER_INVALID
);
595 * --------------------------------------------------------------------------
596 * OvsAllocateNBLContext
598 * Create NBL buffer context and forwarding context.
599 * --------------------------------------------------------------------------
602 OvsAllocateNBLContext(POVS_SWITCH_CONTEXT context
,
603 PNET_BUFFER_LIST nbl
)
605 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
608 status
= NdisAllocateNetBufferListContext(nbl
,
609 sizeof (OVS_BUFFER_CONTEXT
),
610 OVS_DEFAULT_NBL_CONTEXT_FILL
,
612 if (status
!= NDIS_STATUS_SUCCESS
) {
613 return NDIS_STATUS_FAILURE
;
616 nbl
->SourceHandle
= ovsPool
->ndisHandle
;
617 status
= context
->NdisSwitchHandlers
.
618 AllocateNetBufferListForwardingContext(ovsPool
->ndisContext
, nbl
);
620 if (status
!= NDIS_STATUS_SUCCESS
) {
621 NdisFreeNetBufferListContext(nbl
, sizeof (OVS_BUFFER_CONTEXT
));
622 return NDIS_STATUS_FAILURE
;
628 * --------------------------------------------------------------------------
631 * Free the NBL buffer context and forwarding context.
632 * --------------------------------------------------------------------------
635 OvsFreeNBLContext(POVS_SWITCH_CONTEXT context
,
636 PNET_BUFFER_LIST nbl
)
638 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
640 context
->NdisSwitchHandlers
.
641 FreeNetBufferListForwardingContext(ovsPool
->ndisContext
, nbl
);
642 NdisFreeNetBufferListContext(nbl
, sizeof (OVS_BUFFER_CONTEXT
));
644 return NDIS_STATUS_SUCCESS
;
648 * --------------------------------------------------------------------------
651 * Copy NBL info from src to dst
652 * --------------------------------------------------------------------------
655 OvsCopyNBLInfo(PNET_BUFFER_LIST srcNbl
, PNET_BUFFER_LIST dstNbl
,
656 POVS_BUFFER_CONTEXT srcCtx
, UINT32 copySize
,
659 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO srcInfo
, dstInfo
;
660 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
662 srcInfo
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(srcNbl
);
663 dstInfo
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(dstNbl
);
665 #ifdef OVS_USE_COPY_NET_BUFFER_LIST_INFO
666 status
= context
->NdisSwitchHandlers
.
667 CopyNetBufferListInfo(ovsPool
->ndisContext
, dstNbl
, srcNbl
, 0);
669 if (status
!= NDIS_STATUS_SUCCESS
) {
673 dstInfo
->SourcePortId
= srcInfo
->SourcePortId
;
674 dstInfo
->SourceNicIndex
= srcInfo
->SourceNicIndex
;
676 if (srcCtx
->flags
& OVS_BUFFER_RECV_BUFFER
) {
677 NdisCopyReceiveNetBufferListInfo(dstNbl
, srcNbl
);
678 } else if (srcCtx
->flags
& OVS_BUFFER_SEND_BUFFER
) {
679 NdisCopySendNetBufferListInfo(dstNbl
, srcNbl
);
683 dstInfo
->IsPacketDataSafe
= srcInfo
->IsPacketDataSafe
;
684 if (!srcInfo
->IsPacketDataSafe
&& copySize
>
685 srcInfo
->SafePacketDataSize
) {
686 srcInfo
->SafePacketDataSize
= copySize
;
690 * Assume all data are safe
692 dstInfo
->IsPacketDataSafe
= TRUE
;
693 dstInfo
->SourcePortId
= NDIS_SWITCH_DEFAULT_PORT_ID
;
699 * --------------------------------------------------------------------------
700 * OvsPartialCopyNBL --
702 * Partial copy NBL, if there is multiple NB in NBL, each one will be
703 * copied. We also reserve headroom for the new NBL.
706 * NBL should have OVS_BUFFER_CONTEXT setup before calling
708 * The NBL should already have ref to itself so that during copy
709 * it will not be freed.
710 * --------------------------------------------------------------------------
713 OvsPartialCopyNBL(PVOID ovsContext
,
714 PNET_BUFFER_LIST nbl
,
719 PNET_BUFFER_LIST newNbl
;
720 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
722 PNET_BUFFER srcNb
, dstNb
;
724 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
725 POVS_BUFFER_CONTEXT srcCtx
, dstCtx
;
728 srcCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
729 if (srcCtx
== NULL
|| srcCtx
->magic
!= OVS_CTX_MAGIC
) {
730 OVS_LOG_INFO("src nbl must have ctx initialized");
731 ASSERT(srcCtx
&& srcCtx
->magic
== OVS_CTX_MAGIC
);
736 NdisAdvanceNetBufferListDataStart(nbl
, copySize
, FALSE
, NULL
);
738 newNbl
= NdisAllocateCloneNetBufferList(nbl
, ovsPool
->nblOnlyPool
,
741 status
= NdisRetreatNetBufferListDataStart(nbl
, copySize
, 0,
743 ASSERT(status
== NDIS_STATUS_SUCCESS
);
746 if (newNbl
== NULL
) {
751 * Allocate private memory for copy
753 if (copySize
+ headRoom
) {
754 status
= NdisRetreatNetBufferListDataStart(newNbl
, copySize
+ headRoom
,
756 if (status
!= NDIS_STATUS_SUCCESS
) {
761 NdisAdvanceNetBufferListDataStart(newNbl
, headRoom
, FALSE
, NULL
);
764 srcNb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
765 dstNb
= NET_BUFFER_LIST_FIRST_NB(newNbl
);
768 status
= NdisCopyFromNetBufferToNetBuffer(dstNb
, 0, copySize
,
771 if (status
!= NDIS_STATUS_SUCCESS
|| copySize
!= byteCopied
) {
772 goto nbl_context_error
;
774 srcNb
= NET_BUFFER_NEXT_NB(srcNb
);
775 dstNb
= NET_BUFFER_NEXT_NB(dstNb
);
780 status
= OvsAllocateNBLContext(context
, newNbl
);
781 if (status
!= NDIS_STATUS_SUCCESS
) {
782 goto nbl_context_error
;
785 status
= OvsCopyNBLInfo(nbl
, newNbl
, srcCtx
, copySize
, copyNblInfo
);
786 if (status
!= NDIS_STATUS_SUCCESS
) {
787 goto copy_list_info_error
;
791 InterlockedIncrement((LONG
volatile *)&ovsPool
->nblOnlyCount
);
794 newNbl
->ParentNetBufferList
= nbl
;
796 dstCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl
);
797 ASSERT(dstCtx
!= NULL
);
799 flags
= srcCtx
->flags
& (OVS_BUFFER_RECV_BUFFER
| OVS_BUFFER_SEND_BUFFER
);
801 flags
|= OVS_BUFFER_FROM_NBL_ONLY_POOL
| OVS_BUFFER_PRIVATE_CONTEXT
|
802 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
;
804 srcNb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
806 OvsInitNBLContext(dstCtx
, flags
, NET_BUFFER_DATA_LENGTH(srcNb
) - copySize
,
807 OVS_DPPORT_NUMBER_INVALID
);
809 InterlockedIncrement((LONG
volatile *)&srcCtx
->refCount
);
812 OvsDumpNetBufferList(nbl
);
813 OvsDumpForwardingDetails(nbl
);
815 OvsDumpNetBufferList(newNbl
);
816 OvsDumpForwardingDetails(newNbl
);
819 OVS_LOG_LOUD("Partial Copy new NBL: %p", newNbl
);
822 copy_list_info_error
:
823 OvsFreeNBLContext(context
, newNbl
);
826 NdisAdvanceNetBufferListDataStart(newNbl
, copySize
, TRUE
, NULL
);
829 NdisFreeCloneNetBufferList(newNbl
, 0);
834 * --------------------------------------------------------------------------
835 * OvsPartialCopyToMultipleNBLs --
837 * This is similar to OvsPartialCopyNBL() except that each NB will
839 * --------------------------------------------------------------------------
842 OvsPartialCopyToMultipleNBLs(PVOID ovsContext
,
843 PNET_BUFFER_LIST nbl
,
848 PNET_BUFFER nb
, nextNb
= NULL
, firstNb
, prevNb
;
849 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
850 PNET_BUFFER_LIST firstNbl
= NULL
, newNbl
, prevNbl
= NULL
;
852 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
853 if (NET_BUFFER_NEXT_NB(nb
) == NULL
) {
854 return OvsPartialCopyNBL(context
, nbl
, copySize
, headRoom
, copyNblInfo
);
861 nextNb
= NET_BUFFER_NEXT_NB(nb
);
862 NET_BUFFER_NEXT_NB(nb
) = NULL
;
864 NET_BUFFER_LIST_FIRST_NB(nbl
) = nb
;
866 newNbl
= OvsPartialCopyNBL(context
, nbl
, copySize
, headRoom
,
868 if (newNbl
== NULL
) {
871 if (prevNbl
== NULL
) {
874 NET_BUFFER_LIST_NEXT_NBL(prevNbl
) = newNbl
;
875 NET_BUFFER_NEXT_NB(prevNb
) = nb
;
881 NET_BUFFER_LIST_FIRST_NB(nbl
) = firstNb
;
885 NET_BUFFER_NEXT_NB(prevNb
) = nb
;
886 NET_BUFFER_NEXT_NB(nb
) = nextNb
;
887 NET_BUFFER_LIST_FIRST_NB(nbl
) = firstNb
;
891 firstNbl
= NET_BUFFER_LIST_NEXT_NBL(newNbl
);
892 NET_BUFFER_LIST_NEXT_NBL(newNbl
) = NULL
;
893 OvsCompleteNBL(context
, newNbl
, TRUE
);
900 static PNET_BUFFER_LIST
901 OvsCopySinglePacketNBL(PVOID ovsContext
,
902 PNET_BUFFER_LIST nbl
,
909 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
910 PNET_BUFFER_LIST newNbl
;
913 POVS_BUFFER_CONTEXT srcCtx
, dstCtx
;
915 size
= NET_BUFFER_DATA_LENGTH(nb
);
916 if ((size
+ headRoom
) <= OVS_FIX_NBL_DATA_SIZE
) {
917 newNbl
= OvsAllocateFixSizeNBL(context
, size
, headRoom
);
919 newNbl
= OvsAllocateVariableSizeNBL(context
, size
, headRoom
);
921 if (newNbl
== NULL
) {
924 newNb
= NET_BUFFER_LIST_FIRST_NB(newNbl
);
925 status
= NdisCopyFromNetBufferToNetBuffer(newNb
, 0, size
, nb
, 0,
928 srcCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
929 if (status
== NDIS_STATUS_SUCCESS
) {
930 status
= OvsCopyNBLInfo(nbl
, newNbl
, srcCtx
, copiedSize
, copyNblInfo
);
933 if (status
!= NDIS_STATUS_SUCCESS
|| copiedSize
!= size
) {
934 OvsCompleteNBL(context
, newNbl
, TRUE
);
938 dstCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl
);
939 ASSERT(dstCtx
&& srcCtx
);
940 ASSERT(srcCtx
->magic
== OVS_CTX_MAGIC
&& dstCtx
->magic
== OVS_CTX_MAGIC
);
942 dstCtx
->flags
|= srcCtx
->flags
& (OVS_BUFFER_RECV_BUFFER
|
943 OVS_BUFFER_SEND_BUFFER
);
945 OvsDumpNetBufferList(newNbl
);
946 OvsDumpForwardingDetails(newNbl
);
948 OVS_LOG_LOUD("Copy single nb to new NBL: %p", newNbl
);
953 * --------------------------------------------------------------------------
956 * Copy the NBL to a new NBL including data.
959 * The NBL can have multiple NBs, but the final result is one NBL.
960 * --------------------------------------------------------------------------
963 OvsFullCopyNBL(PVOID ovsContext
,
964 PNET_BUFFER_LIST nbl
,
968 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
969 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
970 PNET_BUFFER_LIST newNbl
;
971 PNET_BUFFER nb
, newNb
, firstNb
= NULL
, prevNb
= NULL
;
972 POVS_BUFFER_CONTEXT dstCtx
, srcCtx
;
975 UINT32 size
, totalSize
;
978 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo
;
980 srcCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
981 if (srcCtx
== NULL
|| srcCtx
->magic
!= OVS_CTX_MAGIC
) {
982 OVS_LOG_INFO("src nbl must have ctx initialized");
983 ASSERT(srcCtx
&& srcCtx
->magic
== OVS_CTX_MAGIC
);
987 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
992 if (NET_BUFFER_NEXT_NB(nb
) == NULL
) {
993 return OvsCopySinglePacketNBL(context
, nbl
, nb
, headRoom
, copyNblInfo
);
996 newNbl
= NdisAllocateNetBufferList(ovsPool
->nblOnlyPool
,
997 (UINT16
)sizeof (OVS_BUFFER_CONTEXT
),
998 (UINT16
)OVS_DEFAULT_NBL_CONTEXT_FILL
);
999 if (newNbl
== NULL
) {
1004 size
= NET_BUFFER_DATA_LENGTH(nb
);
1005 totalSize
= MEM_ALIGN_SIZE(size
+ headRoom
);
1006 mdl
= OvsAllocateMDLAndData(ovsPool
->ndisHandle
, totalSize
);
1011 newNb
= NdisAllocateNetBuffer(ovsPool
->nbPool
, mdl
, totalSize
, 0);
1012 if (newNb
== NULL
) {
1013 OvsFreeMDLAndData(mdl
);
1016 if (firstNb
== NULL
) {
1019 NET_BUFFER_NEXT_NB(prevNb
) = newNb
;
1023 InterlockedIncrement((LONG
volatile *)&ovsPool
->nbCount
);
1025 status
= NdisRetreatNetBufferDataStart(newNb
, size
, 0, NULL
);
1026 ASSERT(status
== NDIS_STATUS_SUCCESS
);
1028 status
= NdisCopyFromNetBufferToNetBuffer(newNb
, 0, size
, nb
, 0,
1030 if (status
!= NDIS_STATUS_SUCCESS
|| size
!= copiedSize
) {
1034 nb
= NET_BUFFER_NEXT_NB(nb
);
1037 NET_BUFFER_LIST_FIRST_NB(newNbl
) = firstNb
;
1039 newNbl
->SourceHandle
= ovsPool
->ndisHandle
;
1040 status
= context
->NdisSwitchHandlers
.
1041 AllocateNetBufferListForwardingContext(ovsPool
->ndisContext
, newNbl
);
1043 if (status
!= NDIS_STATUS_SUCCESS
) {
1047 status
= OvsCopyNBLInfo(nbl
, newNbl
, srcCtx
, 0, copyNblInfo
);
1048 if (status
!= NDIS_STATUS_SUCCESS
) {
1052 dstInfo
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl
);
1053 dstInfo
->IsPacketDataSafe
= TRUE
;
1055 dstCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl
);
1057 flags
= srcCtx
->flags
& (OVS_BUFFER_RECV_BUFFER
| OVS_BUFFER_SEND_BUFFER
);
1059 flags
|= OVS_BUFFER_PRIVATE_MDL
| OVS_BUFFER_PRIVATE_DATA
|
1060 OVS_BUFFER_PRIVATE_NET_BUFFER
| OVS_BUFFER_FROM_NBL_ONLY_POOL
|
1061 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
;
1063 OvsInitNBLContext(dstCtx
, flags
, NET_BUFFER_DATA_LENGTH(firstNb
),
1064 OVS_DPPORT_NUMBER_INVALID
);
1067 OvsDumpNetBufferList(nbl
);
1068 OvsDumpForwardingDetails(nbl
);
1069 InterlockedIncrement((LONG
volatile *)&ovsPool
->nblOnlyCount
);
1071 OVS_LOG_LOUD("newNbl: %p", newNbl
);
1077 InterlockedDecrement((LONG
volatile *)&ovsPool
->nbCount
);
1080 firstNb
= NET_BUFFER_NEXT_NB(prevNb
);
1081 mdl
= NET_BUFFER_FIRST_MDL(prevNb
);
1082 NET_BUFFER_FIRST_MDL(prevNb
) = NULL
;
1083 NdisFreeNetBuffer(prevNb
);
1084 OvsFreeMDLAndData(mdl
);
1086 NdisFreeNetBufferList(newNbl
);
1087 OVS_LOG_ERROR("OvsFullCopyNBL failed");
1092 GetIpHeaderInfo(PNET_BUFFER_LIST curNbl
,
1095 CHAR
*ethBuf
[sizeof(EthHdr
)];
1100 curNb
= NET_BUFFER_LIST_FIRST_NB(curNbl
);
1101 ASSERT(NET_BUFFER_NEXT_NB(curNb
) == NULL
);
1103 eth
= (EthHdr
*)NdisGetDataBuffer(curNb
, ETH_HEADER_LENGTH
,
1104 (PVOID
)ðBuf
, 1, 0);
1106 return NDIS_STATUS_INVALID_PACKET
;
1108 ipHdr
= (IPHdr
*)((PCHAR
)eth
+ ETH_HEADER_LENGTH
);
1109 if (ipHdr
== NULL
) {
1110 return NDIS_STATUS_INVALID_PACKET
;
1112 *hdrSize
= (UINT32
)(ETH_HEADER_LENGTH
+ (ipHdr
->ihl
* 4));
1113 return NDIS_STATUS_SUCCESS
;
1117 * --------------------------------------------------------------------------
1118 * GetSegmentHeaderInfo
1120 * Extract header size and sequence number for the segment.
1121 * --------------------------------------------------------------------------
1124 GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl
,
1125 const POVS_PACKET_HDR_INFO hdrInfo
,
1126 UINT32
*hdrSize
, UINT32
*seqNumber
)
1131 /* Parse the orginal Eth/IP/TCP header */
1132 tcp
= OvsGetPacketBytes(nbl
, sizeof *tcp
, hdrInfo
->l4Offset
, &tcpStorage
);
1134 return NDIS_STATUS_FAILURE
;
1136 *seqNumber
= ntohl(tcp
->seq
);
1137 *hdrSize
= hdrInfo
->l4Offset
+ TCP_HDR_LEN(tcp
);
1139 return NDIS_STATUS_SUCCESS
;
1143 * --------------------------------------------------------------------------
1146 * Fix IP length, Offset, IP checksum.
1147 * XXX - Support IpV6 Fragments
1148 * --------------------------------------------------------------------------
1151 FixFragmentHeader(PNET_BUFFER nb
, UINT16 fragmentSize
,
1152 BOOLEAN lastPacket
, UINT16 offset
)
1154 EthHdr
*dstEth
= NULL
;
1156 PUINT8 bufferStart
= NULL
;
1158 mdl
= NET_BUFFER_FIRST_MDL(nb
);
1160 bufferStart
= (PUINT8
)MmGetSystemAddressForMdlSafe(mdl
, LowPagePriority
);
1162 return NDIS_STATUS_RESOURCES
;
1164 dstEth
= (EthHdr
*)(bufferStart
+ NET_BUFFER_CURRENT_MDL_OFFSET(nb
));
1166 switch (dstEth
->Type
) {
1167 case ETH_TYPE_IPV4_NBO
:
1169 IPHdr
*dstIP
= NULL
;
1170 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1171 >= sizeof(EthHdr
) + sizeof(IPHdr
));
1173 dstIP
= (IPHdr
*)((PCHAR
)dstEth
+ sizeof(*dstEth
));
1174 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1175 >= sizeof(EthHdr
) + dstIP
->ihl
* 4);
1176 dstIP
->tot_len
= htons(fragmentSize
+ dstIP
->ihl
* 4);
1178 dstIP
->frag_off
= htons(offset
& IP_OFFSET
);
1180 dstIP
->frag_off
= htons((offset
& IP_OFFSET
) | IP_MF
);
1184 dstIP
->check
= IPChecksum((UINT8
*)dstIP
, dstIP
->ihl
* 4, 0);
1187 case ETH_TYPE_IPV6_NBO
:
1189 return NDIS_STATUS_NOT_SUPPORTED
;
1192 OVS_LOG_ERROR("Invalid eth type: %d\n", dstEth
->Type
);
1193 ASSERT(! "Invalid eth type");
1196 return STATUS_SUCCESS
;
1200 * --------------------------------------------------------------------------
1203 * Fix IP length, IP checksum, TCP sequence number and TCP checksum
1205 * --------------------------------------------------------------------------
1208 FixSegmentHeader(PNET_BUFFER nb
, UINT16 segmentSize
, UINT32 seqNumber
,
1209 BOOLEAN lastPacket
, UINT16 packetCounter
)
1211 EthHdr
*dstEth
= NULL
;
1212 TCPHdr
*dstTCP
= NULL
;
1214 PUINT8 bufferStart
= NULL
;
1216 mdl
= NET_BUFFER_FIRST_MDL(nb
);
1218 bufferStart
= (PUINT8
)MmGetSystemAddressForMdlSafe(mdl
, LowPagePriority
);
1220 return NDIS_STATUS_RESOURCES
;
1222 dstEth
= (EthHdr
*)(bufferStart
+ NET_BUFFER_CURRENT_MDL_OFFSET(nb
));
1224 switch (dstEth
->Type
) {
1225 case ETH_TYPE_IPV4_NBO
:
1227 IPHdr
*dstIP
= NULL
;
1229 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1230 >= sizeof(EthHdr
) + sizeof(IPHdr
) + sizeof(TCPHdr
));
1231 dstIP
= (IPHdr
*)((PCHAR
)dstEth
+ sizeof(*dstEth
));
1232 dstTCP
= (TCPHdr
*)((PCHAR
)dstIP
+ dstIP
->ihl
* 4);
1233 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1234 >= sizeof(EthHdr
) + dstIP
->ihl
* 4 + TCP_HDR_LEN(dstTCP
));
1236 /* Fix IP length and checksum */
1237 ASSERT(dstIP
->protocol
== IPPROTO_TCP
);
1238 dstIP
->tot_len
= htons(segmentSize
+ dstIP
->ihl
* 4 + TCP_HDR_LEN(dstTCP
));
1239 dstIP
->id
+= packetCounter
;
1241 dstIP
->check
= IPChecksum((UINT8
*)dstIP
, dstIP
->ihl
* 4, 0);
1242 dstTCP
->seq
= htonl(seqNumber
);
1245 * Set the TCP FIN and PSH bit only for the last packet
1246 * More information can be found under:
1247 * https://msdn.microsoft.com/en-us/library/windows/hardware/ff568840%28v=vs.85%29.aspx
1250 dstTCP
->fin
= lastPacket
;
1253 dstTCP
->psh
= lastPacket
;
1255 UINT16 csumLength
= segmentSize
+ TCP_HDR_LEN(dstTCP
);
1256 dstTCP
->check
= IPPseudoChecksum(&dstIP
->saddr
,
1260 dstTCP
->check
= CalculateChecksumNB(nb
,
1262 sizeof(*dstEth
) + dstIP
->ihl
* 4);
1265 case ETH_TYPE_IPV6_NBO
:
1267 IPv6Hdr
*dstIP
= NULL
;
1269 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1270 >= sizeof(EthHdr
) + sizeof(IPv6Hdr
) + sizeof(TCPHdr
));
1271 dstIP
= (IPv6Hdr
*)((PCHAR
)dstEth
+ sizeof(*dstEth
));
1272 dstTCP
= (TCPHdr
*)((PCHAR
)dstIP
+ sizeof(IPv6Hdr
));
1273 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1274 >= sizeof(EthHdr
) + sizeof(IPv6Hdr
) + TCP_HDR_LEN(dstTCP
));
1277 ASSERT(dstIP
->nexthdr
== IPPROTO_TCP
);
1278 dstIP
->payload_len
= htons(segmentSize
+ sizeof(IPv6Hdr
) + TCP_HDR_LEN(dstTCP
));
1280 dstTCP
->seq
= htonl(seqNumber
);
1282 dstTCP
->fin
= lastPacket
;
1285 dstTCP
->psh
= lastPacket
;
1288 UINT16 csumLength
= segmentSize
+ TCP_HDR_LEN(dstTCP
);
1289 dstTCP
->check
= IPv6PseudoChecksum((UINT32
*)&dstIP
->saddr
,
1290 (UINT32
*)&dstIP
->daddr
,
1293 dstTCP
->check
= CalculateChecksumNB(nb
,
1295 sizeof(*dstEth
) + sizeof(IPv6Hdr
));
1299 OVS_LOG_ERROR("Invalid eth type: %d\n", dstEth
->Type
);
1300 ASSERT(! "Invalid eth type");
1303 return STATUS_SUCCESS
;
1306 * --------------------------------------------------------------------------
1307 * OvsTcpSegmentNBL --
1308 * Wrapper function to Fragment a given NBL based on MSS
1309 * --------------------------------------------------------------------------
1312 OvsTcpSegmentNBL(PVOID ovsContext
,
1313 PNET_BUFFER_LIST nbl
,
1314 POVS_PACKET_HDR_INFO hdrInfo
,
1317 BOOLEAN isIpFragment
)
1319 return OvsFragmentNBL(ovsContext
, nbl
, hdrInfo
, mss
, headRoom
, isIpFragment
);
1324 * --------------------------------------------------------------------------
1327 * Fragment NBL payload, and prepend each segment with Ether/IP/TCP header.
1328 * Leave headRoom for additional encap.
1331 * NBL should have OVS_BUFFER_CONTEXT setup before calling
1333 * The NBL should already have ref to itself so that during copy
1334 * it will not be freed.
1335 * Currently this API assert there is only one NB in an NBL, it needs
1336 * to be fixed if we receive multiple NBs in an NBL.
1337 * --------------------------------------------------------------------------
1340 OvsFragmentNBL(PVOID ovsContext
,
1341 PNET_BUFFER_LIST nbl
,
1342 POVS_PACKET_HDR_INFO hdrInfo
,
1343 UINT32 fragmentSize
,
1345 BOOLEAN isIpFragment
)
1347 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
1349 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
1351 POVS_BUFFER_CONTEXT dstCtx
, srcCtx
;
1352 UINT32 size
, hdrSize
, nblSize
, seqNumber
= 0;
1353 PNET_BUFFER_LIST newNbl
;
1354 PNET_BUFFER nb
, newNb
;
1358 UINT16 offset
= 0, packetCounter
= 0;
1360 srcCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
1361 if (srcCtx
== NULL
|| srcCtx
->magic
!= OVS_CTX_MAGIC
) {
1362 OVS_LOG_INFO("src nbl must have ctx initialized");
1363 ASSERT(srcCtx
&& srcCtx
->magic
== OVS_CTX_MAGIC
);
1367 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1368 ASSERT(NET_BUFFER_NEXT_NB(nb
) == NULL
);
1370 /* Figure out the header size */
1372 status
= GetIpHeaderInfo(nbl
, &hdrSize
);
1374 status
= GetSegmentHeaderInfo(nbl
, hdrInfo
, &hdrSize
, &seqNumber
);
1376 if (status
!= NDIS_STATUS_SUCCESS
) {
1377 OVS_LOG_INFO("Cannot parse NBL header");
1380 /* Get the NBL size. */
1382 nblSize
= fragmentSize
- hdrSize
;
1384 nblSize
= fragmentSize
;
1386 size
= NET_BUFFER_DATA_LENGTH(nb
) - hdrSize
;
1388 /* XXX add to ovsPool counters? */
1389 newNbl
= NdisAllocateFragmentNetBufferList(nbl
, NULL
, NULL
, hdrSize
,
1390 nblSize
, hdrSize
+ headRoom
,
1392 if (newNbl
== NULL
) {
1396 /* Now deal with TCP payload */
1397 for (newNb
= NET_BUFFER_LIST_FIRST_NB(newNbl
); newNb
!= NULL
;
1398 newNb
= NET_BUFFER_NEXT_NB(newNb
)) {
1399 segmentSize
= (size
> nblSize
? nblSize
: size
) & 0xffff;
1401 NdisAdvanceNetBufferDataStart(newNb
, headRoom
, FALSE
, NULL
);
1404 /* Now copy the eth/IP/TCP header and fix up */
1405 status
= NdisCopyFromNetBufferToNetBuffer(newNb
, 0, hdrSize
, nb
, 0,
1407 if (status
!= NDIS_STATUS_SUCCESS
|| hdrSize
!= copiedSize
) {
1412 status
= FixFragmentHeader(newNb
, segmentSize
,
1413 NET_BUFFER_NEXT_NB(newNb
) == NULL
,
1416 status
= FixSegmentHeader(newNb
, segmentSize
, seqNumber
,
1417 NET_BUFFER_NEXT_NB(newNb
) == NULL
,
1421 if (status
!= NDIS_STATUS_SUCCESS
) {
1425 /* Move on to the next segment */
1427 offset
+= (segmentSize
) / 8;
1429 seqNumber
+= segmentSize
;
1431 size
-= segmentSize
;
1435 status
= OvsAllocateNBLContext(context
, newNbl
);
1436 if (status
!= NDIS_STATUS_SUCCESS
) {
1440 status
= OvsCopyNBLInfo(nbl
, newNbl
, srcCtx
, hdrSize
+ headRoom
, FALSE
);
1441 if (status
!= NDIS_STATUS_SUCCESS
) {
1442 goto nbl_context_error
;
1446 /*Copy with Flag - NDIS_SWITCH_COPY_NBL_INFO_FLAGS_PRESERVE_DESTINATIONS.*/
1447 status
= context
->NdisSwitchHandlers
.
1448 CopyNetBufferListInfo(context
->ovsPool
.ndisContext
, newNbl
, nbl
, 1);
1450 if (status
!= NDIS_STATUS_SUCCESS
) {
1451 goto nbl_context_error
;
1454 newNbl
->ParentNetBufferList
= nbl
;
1456 /* Remember it's a fragment NBL so we can free it properly */
1457 dstCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl
);
1458 ASSERT(dstCtx
!= NULL
);
1459 dstCtx
->flags
= OVS_BUFFER_FRAGMENT
| OVS_BUFFER_PRIVATE_CONTEXT
|
1460 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
| OVS_BUFFER_SEND_BUFFER
;
1461 dstCtx
->refCount
= 1;
1462 dstCtx
->magic
= OVS_CTX_MAGIC
;
1463 dstCtx
->dataOffsetDelta
= hdrSize
+ headRoom
;
1466 InterlockedIncrement((LONG
volatile *)&srcCtx
->refCount
);
1468 InterlockedIncrement((LONG
volatile *)&ovsPool
->fragNBLCount
);
1470 OvsDumpNetBufferList(nbl
);
1471 OvsDumpForwardingDetails(nbl
);
1473 OvsDumpNetBufferList(newNbl
);
1474 OvsDumpForwardingDetails(newNbl
);
1476 OVS_LOG_TRACE("Fragment nbl %p to newNbl: %p", nbl
, newNbl
);
1480 OvsFreeNBLContext(context
, newNbl
);
1483 InterlockedDecrement((LONG
volatile *)&ovsPool
->fragNBLCount
);
1485 NdisFreeFragmentNetBufferList(newNbl
, hdrSize
+ headRoom
, 0);
1490 * --------------------------------------------------------------------------
1491 * OvsAllocateNBLFromBuffer --
1493 * This function allocates all the stuff necessary for creating an NBL from the
1494 * input buffer of specified length, namely, a nonpaged data buffer of size
1495 * length, an MDL from it, and a NB and NBL from it. It does not allocate an NBL
1496 * context yet. It also copies data from the specified buffer to the NBL.
1497 * --------------------------------------------------------------------------
1500 OvsAllocateNBLFromBuffer(PVOID context
,
1504 POVS_SWITCH_CONTEXT switchContext
= (POVS_SWITCH_CONTEXT
)context
;
1506 PNET_BUFFER_LIST nbl
= NULL
;
1510 if (length
> OVS_DEFAULT_DATA_SIZE
) {
1511 nbl
= OvsAllocateVariableSizeNBL(switchContext
, length
,
1512 OVS_DEFAULT_HEADROOM_SIZE
);
1515 nbl
= OvsAllocateFixSizeNBL(switchContext
, length
,
1516 OVS_DEFAULT_HEADROOM_SIZE
);
1522 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1523 mdl
= NET_BUFFER_CURRENT_MDL(nb
);
1524 data
= (PUINT8
)MmGetSystemAddressForMdlSafe(mdl
, LowPagePriority
) +
1525 NET_BUFFER_CURRENT_MDL_OFFSET(nb
);
1527 OvsCompleteNBL(switchContext
, nbl
, TRUE
);
1531 NdisMoveMemory(data
, buffer
, length
);
1537 * --------------------------------------------------------------------------
1538 * OvsFullCopyToMultipleNBLs --
1540 * Copy NBL to multiple NBLs, each NB will have its own NBL
1541 * --------------------------------------------------------------------------
1544 OvsFullCopyToMultipleNBLs(PVOID ovsContext
,
1545 PNET_BUFFER_LIST nbl
,
1547 BOOLEAN copyNblInfo
)
1550 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
1551 PNET_BUFFER_LIST firstNbl
, currNbl
, newNbl
;
1553 POVS_BUFFER_CONTEXT srcCtx
;
1555 srcCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
1556 if (srcCtx
== NULL
|| srcCtx
->magic
!= OVS_CTX_MAGIC
) {
1557 OVS_LOG_INFO("src nbl must have ctx initialized");
1558 ASSERT(srcCtx
&& srcCtx
->magic
== OVS_CTX_MAGIC
);
1562 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1563 newNbl
= OvsCopySinglePacketNBL(context
, nbl
, nb
, headRoom
, copyNblInfo
);
1565 if (newNbl
== NULL
|| NET_BUFFER_NEXT_NB(nb
) == NULL
) {
1573 newNbl
= OvsCopySinglePacketNBL(context
, nbl
, nb
, headRoom
,
1575 if (newNbl
== NULL
) {
1576 goto copymultiple_error
;
1578 NET_BUFFER_LIST_NEXT_NBL(currNbl
) = newNbl
;
1580 nb
= NET_BUFFER_NEXT_NB(nb
);
1587 firstNbl
= NET_BUFFER_LIST_NEXT_NBL(firstNbl
);
1588 NET_BUFFER_LIST_NEXT_NBL(currNbl
) = NULL
;
1589 OvsCompleteNBL(context
, currNbl
, TRUE
);
1597 * --------------------------------------------------------------------------
1600 * This function tries to free the NBL allocated by OVS buffer
1601 * management module. If it trigger the completion of the parent
1602 * NBL, it will recursively call itself. If it trigger the completion
1603 * of external NBL, it will be returned to the caller. The caller
1604 * is responsible to call API to return to upper layer.
1605 * --------------------------------------------------------------------------
1608 OvsCompleteNBL(POVS_SWITCH_CONTEXT context
,
1609 PNET_BUFFER_LIST nbl
,
1612 POVS_BUFFER_CONTEXT ctx
;
1614 PNET_BUFFER_LIST parent
;
1616 NDIS_HANDLE poolHandle
;
1618 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
1622 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
1624 ASSERT(ctx
&& ctx
->magic
== OVS_CTX_MAGIC
);
1626 OVS_LOG_TRACE("Enter: nbl: %p, ctx: %p, refCount: %d, updateRef:%d",
1627 nbl
, ctx
, ctx
->refCount
, updateRef
);
1630 value
= InterlockedDecrement((LONG
volatile *)&ctx
->refCount
);
1636 * This is a special case, the refCount must be zero
1638 ASSERT(ctx
->refCount
== 0);
1641 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1644 if (!(flags
& OVS_BUFFER_FRAGMENT
) &&
1645 NET_BUFFER_DATA_LENGTH(nb
) != ctx
->origDataLength
) {
1647 if (NET_BUFFER_DATA_LENGTH(nb
) < ctx
->origDataLength
) {
1648 diff
= ctx
->origDataLength
-NET_BUFFER_DATA_LENGTH(nb
);
1649 status
= NdisRetreatNetBufferListDataStart(nbl
, diff
, 0,
1651 ASSERT(status
== NDIS_STATUS_SUCCESS
);
1653 diff
= NET_BUFFER_DATA_LENGTH(nb
) - ctx
->origDataLength
;
1654 NdisAdvanceNetBufferListDataStart(nbl
, diff
, TRUE
, NULL
);
1658 if (ctx
->flags
& OVS_BUFFER_PRIVATE_CONTEXT
) {
1659 NdisFreeNetBufferListContext(nbl
, sizeof (OVS_BUFFER_CONTEXT
));
1662 if (flags
& OVS_BUFFER_NEED_COMPLETE
) {
1664 * return to caller for completion
1667 InterlockedDecrement((LONG
volatile *)&ovsPool
->sysNBLCount
);
1672 if (flags
& OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
) {
1673 context
->NdisSwitchHandlers
.
1674 FreeNetBufferListForwardingContext(ovsPool
->ndisContext
, nbl
);
1677 if (flags
& (OVS_BUFFER_PRIVATE_MDL
| OVS_BUFFER_PRIVATE_DATA
)) {
1678 PNET_BUFFER nbTemp
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1680 PMDL mdl
= NET_BUFFER_FIRST_MDL(nbTemp
);
1682 ASSERT(mdl
->Next
== NULL
);
1683 OvsFreeMDLAndData(mdl
);
1685 NET_BUFFER_FIRST_MDL(nbTemp
) = NULL
;
1686 nbTemp
= NET_BUFFER_NEXT_NB(nbTemp
);
1690 if (flags
& OVS_BUFFER_PRIVATE_NET_BUFFER
) {
1691 PNET_BUFFER nbTemp
, nextNb
;
1693 nbTemp
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1695 nextNb
= NET_BUFFER_NEXT_NB(nbTemp
);
1696 NdisFreeNetBuffer(nbTemp
);
1698 InterlockedDecrement((LONG
volatile *)&ovsPool
->nbCount
);
1702 NET_BUFFER_LIST_FIRST_NB(nbl
) = NULL
;
1705 parent
= nbl
->ParentNetBufferList
;
1707 poolHandle
= NdisGetPoolFromNetBufferList(nbl
);
1708 if (flags
& OVS_BUFFER_FROM_FIX_SIZE_POOL
) {
1709 ASSERT(poolHandle
== ovsPool
->fixSizePool
);
1711 InterlockedDecrement((LONG
volatile *)&ovsPool
->fixNBLCount
);
1713 NdisFreeNetBufferList(nbl
);
1714 } else if (flags
& OVS_BUFFER_FROM_ZERO_SIZE_POOL
) {
1715 ASSERT(poolHandle
== ovsPool
->zeroSizePool
);
1717 InterlockedDecrement((LONG
volatile *)&ovsPool
->zeroNBLCount
);
1719 NdisFreeNetBufferList(nbl
);
1720 } else if (flags
& OVS_BUFFER_FROM_NBL_ONLY_POOL
) {
1721 ASSERT(poolHandle
== ovsPool
->nblOnlyPool
);
1723 InterlockedDecrement((LONG
volatile *)&ovsPool
->nblOnlyCount
);
1725 NdisFreeCloneNetBufferList(nbl
, 0);
1726 } else if (flags
& OVS_BUFFER_FRAGMENT
) {
1727 OVS_LOG_TRACE("Free fragment %p parent %p", nbl
, parent
);
1729 InterlockedDecrement((LONG
volatile *)&ovsPool
->fragNBLCount
);
1731 NdisFreeFragmentNetBufferList(nbl
, ctx
->dataOffsetDelta
, 0);
1734 if (parent
!= NULL
) {
1735 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(parent
);
1736 ASSERT(ctx
&& ctx
->magic
== OVS_CTX_MAGIC
);
1737 value
= InterlockedDecrement((LONG
volatile *)&ctx
->refCount
);
1739 return OvsCompleteNBL(context
, parent
, FALSE
);
1746 * --------------------------------------------------------------------------
1747 * OvsSetCtxSourcePortNo --
1748 * Setter function which stores the source port of an NBL in the NBL
1750 * --------------------------------------------------------------------------
1753 OvsSetCtxSourcePortNo(PNET_BUFFER_LIST nbl
,
1756 POVS_BUFFER_CONTEXT ctx
;
1757 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
1759 ASSERT(ctx
&& ctx
->magic
== OVS_CTX_MAGIC
);
1760 return STATUS_INVALID_PARAMETER
;
1763 ctx
->srcPortNo
= portNo
;
1764 return NDIS_STATUS_SUCCESS
;
1768 * --------------------------------------------------------------------------
1769 * OvsGetCtxSourcePortNo --
1770 * Get source port of an NBL from its Context Info.
1771 * --------------------------------------------------------------------------
1774 OvsGetCtxSourcePortNo(PNET_BUFFER_LIST nbl
,
1777 POVS_BUFFER_CONTEXT ctx
;
1778 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
1779 if (ctx
== NULL
|| portNo
== NULL
) {
1780 ASSERT(ctx
&& ctx
->magic
== OVS_CTX_MAGIC
);
1781 return STATUS_INVALID_PARAMETER
;
1783 *portNo
= ctx
->srcPortNo
;
1784 return NDIS_STATUS_SUCCESS
;