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 #if OVS_DBG_DEFAULT >= OVS_DBG_LOUD
277 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info
;
278 info
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl
);
282 OVS_LOG_INFO("nbl: %p, numAvailableDest: %d, srcId:%d, srcIndex: %d "
283 "isDataSafe: %s, safeDataSize: %d",
284 nbl
, info
->NumAvailableDestinations
, info
->SourcePortId
,
285 info
->SourceNicIndex
,
286 info
->IsPacketDataSafe
? "TRUE" : "FALSE",
287 info
->IsPacketDataSafe
? 0 : info
->SafePacketDataSize
);
289 UNREFERENCED_PARAMETER(nbl
);
294 OvsDumpNBLContext(PNET_BUFFER_LIST nbl
)
296 #if OVS_DBG_DEFAULT >= OVS_DBG_LOUD
297 PNET_BUFFER_LIST_CONTEXT ctx
= nbl
->Context
;
299 OVS_LOG_INFO("No Net Buffer List context");
303 OVS_LOG_INFO("nbl: %p, ctx: %p, TotalSize: %d, Offset: %d",
304 nbl
, ctx
, ctx
->Size
, ctx
->Offset
);
308 UNREFERENCED_PARAMETER(nbl
);
314 OvsDumpMDLChain(PMDL mdl
)
319 OVS_LOG_INFO("MDL: %p, Size: %d, MappedSystemVa: %p, StartVa: %p"
320 " ByteCount: %d, ByteOffset: %d",
321 tmp
, tmp
->Size
, tmp
->MappedSystemVa
,
322 tmp
->StartVa
, tmp
->ByteCount
, tmp
->ByteOffset
);
329 OvsDumpNetBuffer(PNET_BUFFER nb
)
331 OVS_LOG_INFO("NET_BUFFER: %p, ChecksumBias: %d Handle: %p, MDLChain: %p "
332 "CurrMDL: %p, CurrOffset: %d, DataLen: %d, Offset: %d",
334 NET_BUFFER_CHECKSUM_BIAS(nb
), nb
->NdisPoolHandle
,
335 NET_BUFFER_FIRST_MDL(nb
),
336 NET_BUFFER_CURRENT_MDL(nb
),
337 NET_BUFFER_CURRENT_MDL_OFFSET(nb
),
338 NET_BUFFER_DATA_LENGTH(nb
),
339 NET_BUFFER_DATA_OFFSET(nb
));
340 OvsDumpMDLChain(NET_BUFFER_FIRST_MDL(nb
));
345 OvsDumpNetBufferList(PNET_BUFFER_LIST nbl
)
347 #if OVS_DBG_DEFAULT >= OVS_DBG_LOUD
349 OVS_LOG_INFO("NBL: %p, parent: %p, SrcHandle: %p, ChildCount:%d "
351 nbl
, nbl
->ParentNetBufferList
,
352 nbl
->SourceHandle
, nbl
->ChildRefCount
,
353 nbl
->NdisPoolHandle
);
354 OvsDumpNBLContext(nbl
);
355 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
357 OvsDumpNetBuffer(nb
);
358 nb
= NET_BUFFER_NEXT_NB(nb
);
361 UNREFERENCED_PARAMETER(nbl
);
366 * --------------------------------------------------------------------------
367 * OvsAllocateFixSizeNBL --
369 * Allocate fix size NBL which include
370 * NBL + NB + MBL + Data + Context
372 * * Forwarding Context is allocated, but forwarding detail information
373 * is not initailized.
374 * * The headroom can not be larger than OVS_DEFAULT_HEADROOM_SIZE(128
376 * --------------------------------------------------------------------------
379 OvsAllocateFixSizeNBL(PVOID ovsContext
,
383 PNET_BUFFER_LIST nbl
= NULL
;
384 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
385 POVS_BUFFER_CONTEXT ctx
;
386 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
389 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info
;
391 if ((headRoom
+ size
) > OVS_FIX_NBL_DATA_SIZE
|| size
== 0) {
396 nbl
= NdisAllocateNetBufferList(ovsPool
->fixSizePool
,
397 (UINT16
)sizeof (OVS_BUFFER_CONTEXT
),
398 (UINT16
)OVS_DEFAULT_NBL_CONTEXT_FILL
);
405 nbl
->SourceHandle
= ovsPool
->ndisHandle
;
406 status
= context
->NdisSwitchHandlers
.
407 AllocateNetBufferListForwardingContext(ovsPool
->ndisContext
, nbl
);
409 if (status
!= NDIS_STATUS_SUCCESS
) {
410 NdisFreeNetBufferList(nbl
);
415 info
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl
);
417 info
->IsPacketDataSafe
= TRUE
;
418 info
->SourcePortId
= NDIS_SWITCH_DEFAULT_PORT_ID
;
420 status
= NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl
),
422 ASSERT(status
== NDIS_STATUS_SUCCESS
);
425 InterlockedIncrement((LONG
volatile *)&ovsPool
->fixNBLCount
);
426 OvsDumpNetBufferList(nbl
);
427 OvsDumpForwardingDetails(nbl
);
430 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
433 OvsInitNBLContext(ctx
, OVS_BUFFER_FROM_FIX_SIZE_POOL
|
434 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
, size
,
435 OVS_DPPORT_NUMBER_INVALID
);
438 OVS_LOG_LOUD("Allocate Fix NBL: %p, line: %d", nbl
, line
);
444 OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle
,
450 data
= OvsAllocateMemoryWithTag(dataSize
, OVS_MDL_POOL_TAG
);
455 mdl
= NdisAllocateMdl(ndisHandle
, data
, dataSize
);
457 OvsFreeMemoryWithTag(data
, OVS_MDL_POOL_TAG
);
465 OvsFreeMDLAndData(PMDL mdl
)
469 data
= MmGetMdlVirtualAddress(mdl
);
471 OvsFreeMemoryWithTag(data
, OVS_MDL_POOL_TAG
);
476 * --------------------------------------------------------------------------
477 * OvsAllocateVariableSizeNBL --
479 * Allocate variable size NBL, the NBL looks like
482 * --------------------------------------------------------------------------
485 OvsAllocateVariableSizeNBL(PVOID ovsContext
,
489 PNET_BUFFER_LIST nbl
= NULL
;
490 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
491 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
492 POVS_BUFFER_CONTEXT ctx
;
496 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info
;
500 realSize
= MEM_ALIGN_SIZE(size
+ headRoom
);
502 mdl
= OvsAllocateMDLAndData(ovsPool
->ndisHandle
, realSize
);
507 nbl
= NdisAllocateNetBufferAndNetBufferList(ovsPool
->zeroSizePool
,
508 (UINT16
)sizeof (OVS_BUFFER_CONTEXT
),
509 (UINT16
)OVS_DEFAULT_NBL_CONTEXT_FILL
,
512 OvsFreeMDLAndData(mdl
);
516 nbl
->SourceHandle
= ovsPool
->ndisHandle
;
517 status
= context
->NdisSwitchHandlers
.
518 AllocateNetBufferListForwardingContext(ovsPool
->ndisContext
, nbl
);
520 if (status
!= NDIS_STATUS_SUCCESS
) {
522 * do we need to remove mdl from nbl XXX
524 OvsFreeMDLAndData(mdl
);
525 NdisFreeNetBufferList(nbl
);
529 info
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl
);
531 info
->IsPacketDataSafe
= TRUE
;
532 info
->SourcePortId
= NDIS_SWITCH_DEFAULT_PORT_ID
;
533 status
= NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl
),
535 ASSERT(status
== NDIS_STATUS_SUCCESS
);
538 InterlockedIncrement((LONG
volatile *)&ovsPool
->zeroNBLCount
);
539 OvsDumpNetBufferList(nbl
);
540 OvsDumpForwardingDetails(nbl
);
543 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
545 OvsInitNBLContext(ctx
, OVS_BUFFER_PRIVATE_MDL
| OVS_BUFFER_PRIVATE_DATA
|
546 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
|
547 OVS_BUFFER_FROM_ZERO_SIZE_POOL
,
548 size
, OVS_DPPORT_NUMBER_INVALID
);
550 OVS_LOG_LOUD("Allocate variable size NBL: %p", nbl
);
556 * --------------------------------------------------------------------------
557 * OvsInitExternalNBLContext --
559 * For NBL not allocated by OVS, it will allocate and initialize
561 * --------------------------------------------------------------------------
564 OvsInitExternalNBLContext(PVOID ovsContext
,
565 PNET_BUFFER_LIST nbl
,
568 NDIS_HANDLE poolHandle
;
569 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
570 POVS_BUFFER_CONTEXT ctx
;
575 poolHandle
= NdisGetPoolFromNetBufferList(nbl
);
577 if (poolHandle
== context
->ovsPool
.ndisHandle
||
578 nbl
->SourceHandle
== context
->ovsPool
.ndisHandle
) {
579 return (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
581 status
= NdisAllocateNetBufferListContext(nbl
, sizeof (OVS_BUFFER_CONTEXT
),
582 OVS_DEFAULT_NBL_CONTEXT_FILL
,
584 if (status
!= NDIS_STATUS_SUCCESS
) {
588 OvsDumpNBLContext(nbl
);
589 InterlockedIncrement((LONG
volatile *)&context
->ovsPool
.sysNBLCount
);
591 flags
= isRecv
? OVS_BUFFER_RECV_BUFFER
: OVS_BUFFER_SEND_BUFFER
;
592 flags
|= OVS_BUFFER_NEED_COMPLETE
| OVS_BUFFER_PRIVATE_CONTEXT
;
593 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
595 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
597 * we use first nb to decide whether we need advance or retreat during
600 OvsInitNBLContext(ctx
, flags
, NET_BUFFER_DATA_LENGTH(nb
),
601 OVS_DPPORT_NUMBER_INVALID
);
606 * --------------------------------------------------------------------------
607 * OvsAllocateNBLContext
609 * Create NBL buffer context and forwarding context.
610 * --------------------------------------------------------------------------
613 OvsAllocateNBLContext(POVS_SWITCH_CONTEXT context
,
614 PNET_BUFFER_LIST nbl
)
616 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
619 status
= NdisAllocateNetBufferListContext(nbl
,
620 sizeof (OVS_BUFFER_CONTEXT
),
621 OVS_DEFAULT_NBL_CONTEXT_FILL
,
623 if (status
!= NDIS_STATUS_SUCCESS
) {
624 return NDIS_STATUS_FAILURE
;
627 nbl
->SourceHandle
= ovsPool
->ndisHandle
;
628 status
= context
->NdisSwitchHandlers
.
629 AllocateNetBufferListForwardingContext(ovsPool
->ndisContext
, nbl
);
631 if (status
!= NDIS_STATUS_SUCCESS
) {
632 NdisFreeNetBufferListContext(nbl
, sizeof (OVS_BUFFER_CONTEXT
));
633 return NDIS_STATUS_FAILURE
;
639 * --------------------------------------------------------------------------
642 * Free the NBL buffer context and forwarding context.
643 * --------------------------------------------------------------------------
646 OvsFreeNBLContext(POVS_SWITCH_CONTEXT context
,
647 PNET_BUFFER_LIST nbl
)
649 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
651 context
->NdisSwitchHandlers
.
652 FreeNetBufferListForwardingContext(ovsPool
->ndisContext
, nbl
);
653 NdisFreeNetBufferListContext(nbl
, sizeof (OVS_BUFFER_CONTEXT
));
655 return NDIS_STATUS_SUCCESS
;
659 * --------------------------------------------------------------------------
662 * Copy NBL info from src to dst
663 * --------------------------------------------------------------------------
666 OvsCopyNBLInfo(PNET_BUFFER_LIST srcNbl
, PNET_BUFFER_LIST dstNbl
,
667 POVS_BUFFER_CONTEXT srcCtx
, UINT32 copySize
,
670 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO srcInfo
, dstInfo
;
671 NDIS_STATUS status
= NDIS_STATUS_SUCCESS
;
673 srcInfo
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(srcNbl
);
674 dstInfo
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(dstNbl
);
676 #ifdef OVS_USE_COPY_NET_BUFFER_LIST_INFO
677 status
= context
->NdisSwitchHandlers
.
678 CopyNetBufferListInfo(ovsPool
->ndisContext
, dstNbl
, srcNbl
, 0);
680 if (status
!= NDIS_STATUS_SUCCESS
) {
684 dstInfo
->SourcePortId
= srcInfo
->SourcePortId
;
685 dstInfo
->SourceNicIndex
= srcInfo
->SourceNicIndex
;
687 if (srcCtx
->flags
& OVS_BUFFER_RECV_BUFFER
) {
688 NdisCopyReceiveNetBufferListInfo(dstNbl
, srcNbl
);
689 } else if (srcCtx
->flags
& OVS_BUFFER_SEND_BUFFER
) {
690 NdisCopySendNetBufferListInfo(dstNbl
, srcNbl
);
694 dstInfo
->IsPacketDataSafe
= srcInfo
->IsPacketDataSafe
;
695 if (!srcInfo
->IsPacketDataSafe
&& copySize
>
696 srcInfo
->SafePacketDataSize
) {
697 srcInfo
->SafePacketDataSize
= copySize
;
701 * Assume all data are safe
703 dstInfo
->IsPacketDataSafe
= TRUE
;
704 dstInfo
->SourcePortId
= NDIS_SWITCH_DEFAULT_PORT_ID
;
710 * --------------------------------------------------------------------------
711 * OvsPartialCopyNBL --
713 * Partial copy NBL, if there is multiple NB in NBL, each one will be
714 * copied. We also reserve headroom for the new NBL.
717 * NBL should have OVS_BUFFER_CONTEXT setup before calling
719 * The NBL should already have ref to itself so that during copy
720 * it will not be freed.
721 * --------------------------------------------------------------------------
724 OvsPartialCopyNBL(PVOID ovsContext
,
725 PNET_BUFFER_LIST nbl
,
730 PNET_BUFFER_LIST newNbl
;
731 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
733 PNET_BUFFER srcNb
, dstNb
;
735 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
736 POVS_BUFFER_CONTEXT srcCtx
, dstCtx
;
739 srcCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
740 if (srcCtx
== NULL
|| srcCtx
->magic
!= OVS_CTX_MAGIC
) {
741 OVS_LOG_INFO("src nbl must have ctx initialized");
742 ASSERT(srcCtx
&& srcCtx
->magic
== OVS_CTX_MAGIC
);
747 NdisAdvanceNetBufferListDataStart(nbl
, copySize
, FALSE
, NULL
);
749 newNbl
= NdisAllocateCloneNetBufferList(nbl
, ovsPool
->nblOnlyPool
,
752 status
= NdisRetreatNetBufferListDataStart(nbl
, copySize
, 0,
754 ASSERT(status
== NDIS_STATUS_SUCCESS
);
757 if (newNbl
== NULL
) {
762 * Allocate private memory for copy
764 if (copySize
+ headRoom
) {
765 status
= NdisRetreatNetBufferListDataStart(newNbl
, copySize
+ headRoom
,
767 if (status
!= NDIS_STATUS_SUCCESS
) {
772 NdisAdvanceNetBufferListDataStart(newNbl
, headRoom
, FALSE
, NULL
);
775 srcNb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
776 dstNb
= NET_BUFFER_LIST_FIRST_NB(newNbl
);
779 status
= NdisCopyFromNetBufferToNetBuffer(dstNb
, 0, copySize
,
782 if (status
!= NDIS_STATUS_SUCCESS
|| copySize
!= byteCopied
) {
783 goto nbl_context_error
;
785 srcNb
= NET_BUFFER_NEXT_NB(srcNb
);
786 dstNb
= NET_BUFFER_NEXT_NB(dstNb
);
791 status
= OvsAllocateNBLContext(context
, newNbl
);
792 if (status
!= NDIS_STATUS_SUCCESS
) {
793 goto nbl_context_error
;
796 status
= OvsCopyNBLInfo(nbl
, newNbl
, srcCtx
, copySize
, copyNblInfo
);
797 if (status
!= NDIS_STATUS_SUCCESS
) {
798 goto copy_list_info_error
;
802 InterlockedIncrement((LONG
volatile *)&ovsPool
->nblOnlyCount
);
805 newNbl
->ParentNetBufferList
= nbl
;
807 dstCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl
);
808 ASSERT(dstCtx
!= NULL
);
810 flags
= srcCtx
->flags
& (OVS_BUFFER_RECV_BUFFER
| OVS_BUFFER_SEND_BUFFER
);
812 flags
|= OVS_BUFFER_FROM_NBL_ONLY_POOL
| OVS_BUFFER_PRIVATE_CONTEXT
|
813 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
;
815 srcNb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
817 OvsInitNBLContext(dstCtx
, flags
, NET_BUFFER_DATA_LENGTH(srcNb
) - copySize
,
818 OVS_DPPORT_NUMBER_INVALID
);
820 InterlockedIncrement((LONG
volatile *)&srcCtx
->refCount
);
823 OvsDumpNetBufferList(nbl
);
824 OvsDumpForwardingDetails(nbl
);
826 OvsDumpNetBufferList(newNbl
);
827 OvsDumpForwardingDetails(newNbl
);
830 OVS_LOG_LOUD("Partial Copy new NBL: %p", newNbl
);
833 copy_list_info_error
:
834 OvsFreeNBLContext(context
, newNbl
);
837 NdisAdvanceNetBufferListDataStart(newNbl
, copySize
, TRUE
, NULL
);
840 NdisFreeCloneNetBufferList(newNbl
, 0);
845 * --------------------------------------------------------------------------
846 * OvsPartialCopyToMultipleNBLs --
848 * This is similar to OvsPartialCopyNBL() except that each NB will
850 * --------------------------------------------------------------------------
853 OvsPartialCopyToMultipleNBLs(PVOID ovsContext
,
854 PNET_BUFFER_LIST nbl
,
859 PNET_BUFFER nb
, nextNb
= NULL
, firstNb
, prevNb
;
860 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
861 PNET_BUFFER_LIST firstNbl
= NULL
, newNbl
, prevNbl
= NULL
;
863 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
864 if (NET_BUFFER_NEXT_NB(nb
) == NULL
) {
865 return OvsPartialCopyNBL(context
, nbl
, copySize
, headRoom
, copyNblInfo
);
872 nextNb
= NET_BUFFER_NEXT_NB(nb
);
873 NET_BUFFER_NEXT_NB(nb
) = NULL
;
875 NET_BUFFER_LIST_FIRST_NB(nbl
) = nb
;
877 newNbl
= OvsPartialCopyNBL(context
, nbl
, copySize
, headRoom
,
879 if (newNbl
== NULL
) {
882 if (prevNbl
== NULL
) {
885 NET_BUFFER_LIST_NEXT_NBL(prevNbl
) = newNbl
;
886 NET_BUFFER_NEXT_NB(prevNb
) = nb
;
892 NET_BUFFER_LIST_FIRST_NB(nbl
) = firstNb
;
896 NET_BUFFER_NEXT_NB(prevNb
) = nb
;
897 NET_BUFFER_NEXT_NB(nb
) = nextNb
;
898 NET_BUFFER_LIST_FIRST_NB(nbl
) = firstNb
;
902 firstNbl
= NET_BUFFER_LIST_NEXT_NBL(newNbl
);
903 NET_BUFFER_LIST_NEXT_NBL(newNbl
) = NULL
;
904 OvsCompleteNBL(context
, newNbl
, TRUE
);
911 static PNET_BUFFER_LIST
912 OvsCopySinglePacketNBL(PVOID ovsContext
,
913 PNET_BUFFER_LIST nbl
,
920 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
921 PNET_BUFFER_LIST newNbl
;
924 POVS_BUFFER_CONTEXT srcCtx
, dstCtx
;
926 size
= NET_BUFFER_DATA_LENGTH(nb
);
927 if ((size
+ headRoom
) <= OVS_FIX_NBL_DATA_SIZE
) {
928 newNbl
= OvsAllocateFixSizeNBL(context
, size
, headRoom
);
930 newNbl
= OvsAllocateVariableSizeNBL(context
, size
, headRoom
);
932 if (newNbl
== NULL
) {
935 newNb
= NET_BUFFER_LIST_FIRST_NB(newNbl
);
936 status
= NdisCopyFromNetBufferToNetBuffer(newNb
, 0, size
, nb
, 0,
939 srcCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
940 if (status
== NDIS_STATUS_SUCCESS
) {
941 status
= OvsCopyNBLInfo(nbl
, newNbl
, srcCtx
, copiedSize
, copyNblInfo
);
944 if (status
!= NDIS_STATUS_SUCCESS
|| copiedSize
!= size
) {
945 OvsCompleteNBL(context
, newNbl
, TRUE
);
949 dstCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl
);
950 ASSERT(dstCtx
&& srcCtx
);
951 ASSERT(srcCtx
->magic
== OVS_CTX_MAGIC
&& dstCtx
->magic
== OVS_CTX_MAGIC
);
953 dstCtx
->flags
|= srcCtx
->flags
& (OVS_BUFFER_RECV_BUFFER
|
954 OVS_BUFFER_SEND_BUFFER
);
956 OvsDumpNetBufferList(newNbl
);
957 OvsDumpForwardingDetails(newNbl
);
959 OVS_LOG_LOUD("Copy single nb to new NBL: %p", newNbl
);
964 * --------------------------------------------------------------------------
967 * Copy the NBL to a new NBL including data.
970 * The NBL can have multiple NBs, but the final result is one NBL.
971 * --------------------------------------------------------------------------
974 OvsFullCopyNBL(PVOID ovsContext
,
975 PNET_BUFFER_LIST nbl
,
979 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
980 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
981 PNET_BUFFER_LIST newNbl
;
982 PNET_BUFFER nb
, newNb
, firstNb
= NULL
, prevNb
= NULL
;
983 POVS_BUFFER_CONTEXT dstCtx
, srcCtx
;
986 UINT32 size
, totalSize
;
989 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo
;
991 srcCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
992 if (srcCtx
== NULL
|| srcCtx
->magic
!= OVS_CTX_MAGIC
) {
993 OVS_LOG_INFO("src nbl must have ctx initialized");
994 ASSERT(srcCtx
&& srcCtx
->magic
== OVS_CTX_MAGIC
);
998 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1003 if (NET_BUFFER_NEXT_NB(nb
) == NULL
) {
1004 return OvsCopySinglePacketNBL(context
, nbl
, nb
, headRoom
, copyNblInfo
);
1007 newNbl
= NdisAllocateNetBufferList(ovsPool
->nblOnlyPool
,
1008 (UINT16
)sizeof (OVS_BUFFER_CONTEXT
),
1009 (UINT16
)OVS_DEFAULT_NBL_CONTEXT_FILL
);
1010 if (newNbl
== NULL
) {
1015 size
= NET_BUFFER_DATA_LENGTH(nb
);
1016 totalSize
= MEM_ALIGN_SIZE(size
+ headRoom
);
1017 mdl
= OvsAllocateMDLAndData(ovsPool
->ndisHandle
, totalSize
);
1022 newNb
= NdisAllocateNetBuffer(ovsPool
->nbPool
, mdl
, totalSize
, 0);
1023 if (newNb
== NULL
) {
1024 OvsFreeMDLAndData(mdl
);
1027 if (firstNb
== NULL
) {
1030 NET_BUFFER_NEXT_NB(prevNb
) = newNb
;
1034 InterlockedIncrement((LONG
volatile *)&ovsPool
->nbCount
);
1036 status
= NdisRetreatNetBufferDataStart(newNb
, size
, 0, NULL
);
1037 ASSERT(status
== NDIS_STATUS_SUCCESS
);
1039 status
= NdisCopyFromNetBufferToNetBuffer(newNb
, 0, size
, nb
, 0,
1041 if (status
!= NDIS_STATUS_SUCCESS
|| size
!= copiedSize
) {
1045 nb
= NET_BUFFER_NEXT_NB(nb
);
1048 NET_BUFFER_LIST_FIRST_NB(newNbl
) = firstNb
;
1050 newNbl
->SourceHandle
= ovsPool
->ndisHandle
;
1051 status
= context
->NdisSwitchHandlers
.
1052 AllocateNetBufferListForwardingContext(ovsPool
->ndisContext
, newNbl
);
1054 if (status
!= NDIS_STATUS_SUCCESS
) {
1058 status
= OvsCopyNBLInfo(nbl
, newNbl
, srcCtx
, 0, copyNblInfo
);
1059 if (status
!= NDIS_STATUS_SUCCESS
) {
1063 dstInfo
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl
);
1064 dstInfo
->IsPacketDataSafe
= TRUE
;
1066 dstCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl
);
1068 flags
= srcCtx
->flags
& (OVS_BUFFER_RECV_BUFFER
| OVS_BUFFER_SEND_BUFFER
);
1070 flags
|= OVS_BUFFER_PRIVATE_MDL
| OVS_BUFFER_PRIVATE_DATA
|
1071 OVS_BUFFER_PRIVATE_NET_BUFFER
| OVS_BUFFER_FROM_NBL_ONLY_POOL
|
1072 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
;
1074 OvsInitNBLContext(dstCtx
, flags
, NET_BUFFER_DATA_LENGTH(firstNb
),
1075 OVS_DPPORT_NUMBER_INVALID
);
1078 OvsDumpNetBufferList(nbl
);
1079 OvsDumpForwardingDetails(nbl
);
1080 InterlockedIncrement((LONG
volatile *)&ovsPool
->nblOnlyCount
);
1082 OVS_LOG_LOUD("newNbl: %p", newNbl
);
1088 InterlockedDecrement((LONG
volatile *)&ovsPool
->nbCount
);
1091 firstNb
= NET_BUFFER_NEXT_NB(prevNb
);
1092 mdl
= NET_BUFFER_FIRST_MDL(prevNb
);
1093 NET_BUFFER_FIRST_MDL(prevNb
) = NULL
;
1094 NdisFreeNetBuffer(prevNb
);
1095 OvsFreeMDLAndData(mdl
);
1097 NdisFreeNetBufferList(newNbl
);
1098 OVS_LOG_ERROR("OvsFullCopyNBL failed");
1103 GetIpHeaderInfo(PNET_BUFFER_LIST curNbl
,
1106 CHAR
*ethBuf
[sizeof(EthHdr
)];
1111 curNb
= NET_BUFFER_LIST_FIRST_NB(curNbl
);
1112 ASSERT(NET_BUFFER_NEXT_NB(curNb
) == NULL
);
1114 eth
= (EthHdr
*)NdisGetDataBuffer(curNb
, ETH_HEADER_LENGTH
,
1115 (PVOID
)ðBuf
, 1, 0);
1117 return NDIS_STATUS_INVALID_PACKET
;
1119 ipHdr
= (IPHdr
*)((PCHAR
)eth
+ ETH_HEADER_LENGTH
);
1120 if (ipHdr
== NULL
) {
1121 return NDIS_STATUS_INVALID_PACKET
;
1123 *hdrSize
= (UINT32
)(ETH_HEADER_LENGTH
+ (ipHdr
->ihl
* 4));
1124 return NDIS_STATUS_SUCCESS
;
1128 * --------------------------------------------------------------------------
1129 * GetSegmentHeaderInfo
1131 * Extract header size and sequence number for the segment.
1132 * --------------------------------------------------------------------------
1135 GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl
,
1136 const POVS_PACKET_HDR_INFO hdrInfo
,
1137 UINT32
*hdrSize
, UINT32
*seqNumber
)
1142 /* Parse the orginal Eth/IP/TCP header */
1143 tcp
= OvsGetPacketBytes(nbl
, sizeof *tcp
, hdrInfo
->l4Offset
, &tcpStorage
);
1145 return NDIS_STATUS_FAILURE
;
1147 *seqNumber
= ntohl(tcp
->seq
);
1148 *hdrSize
= hdrInfo
->l4Offset
+ TCP_HDR_LEN(tcp
);
1150 return NDIS_STATUS_SUCCESS
;
1154 * --------------------------------------------------------------------------
1157 * Fix IP length, Offset, IP checksum.
1158 * XXX - Support IpV6 Fragments
1159 * --------------------------------------------------------------------------
1162 FixFragmentHeader(PNET_BUFFER nb
, UINT16 fragmentSize
,
1163 BOOLEAN lastPacket
, UINT16 offset
)
1165 EthHdr
*dstEth
= NULL
;
1167 PUINT8 bufferStart
= NULL
;
1169 mdl
= NET_BUFFER_FIRST_MDL(nb
);
1171 bufferStart
= (PUINT8
)OvsGetMdlWithLowPriority(mdl
);
1173 return NDIS_STATUS_RESOURCES
;
1175 dstEth
= (EthHdr
*)(bufferStart
+ NET_BUFFER_CURRENT_MDL_OFFSET(nb
));
1177 switch (dstEth
->Type
) {
1178 case ETH_TYPE_IPV4_NBO
:
1180 IPHdr
*dstIP
= NULL
;
1181 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1182 >= sizeof(EthHdr
) + sizeof(IPHdr
));
1184 dstIP
= (IPHdr
*)((PCHAR
)dstEth
+ sizeof(*dstEth
));
1185 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1186 >= sizeof(EthHdr
) + dstIP
->ihl
* 4);
1187 dstIP
->tot_len
= htons(fragmentSize
+ dstIP
->ihl
* 4);
1189 dstIP
->frag_off
= htons(offset
& IP_OFFSET
);
1191 dstIP
->frag_off
= htons((offset
& IP_OFFSET
) | IP_MF
);
1195 dstIP
->check
= IPChecksum((UINT8
*)dstIP
, dstIP
->ihl
* 4, 0);
1198 case ETH_TYPE_IPV6_NBO
:
1200 return NDIS_STATUS_NOT_SUPPORTED
;
1203 OVS_LOG_ERROR("Invalid eth type: %d\n", dstEth
->Type
);
1204 ASSERT(! "Invalid eth type");
1207 return STATUS_SUCCESS
;
1211 * --------------------------------------------------------------------------
1214 * Fix IP length, IP checksum, TCP sequence number and TCP checksum
1216 * --------------------------------------------------------------------------
1219 FixSegmentHeader(PNET_BUFFER nb
, UINT16 segmentSize
, UINT32 seqNumber
,
1220 BOOLEAN lastPacket
, UINT16 packetCounter
)
1222 EthHdr
*dstEth
= NULL
;
1223 TCPHdr
*dstTCP
= NULL
;
1225 PUINT8 bufferStart
= NULL
;
1227 mdl
= NET_BUFFER_FIRST_MDL(nb
);
1229 bufferStart
= (PUINT8
)OvsGetMdlWithLowPriority(mdl
);
1231 return NDIS_STATUS_RESOURCES
;
1233 dstEth
= (EthHdr
*)(bufferStart
+ NET_BUFFER_CURRENT_MDL_OFFSET(nb
));
1235 switch (dstEth
->Type
) {
1236 case ETH_TYPE_IPV4_NBO
:
1238 IPHdr
*dstIP
= NULL
;
1240 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1241 >= sizeof(EthHdr
) + sizeof(IPHdr
) + sizeof(TCPHdr
));
1242 dstIP
= (IPHdr
*)((PCHAR
)dstEth
+ sizeof(*dstEth
));
1243 dstTCP
= (TCPHdr
*)((PCHAR
)dstIP
+ dstIP
->ihl
* 4);
1244 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1245 >= sizeof(EthHdr
) + dstIP
->ihl
* 4 + TCP_HDR_LEN(dstTCP
));
1247 /* Fix IP length and checksum */
1248 ASSERT(dstIP
->protocol
== IPPROTO_TCP
);
1249 dstIP
->tot_len
= htons(segmentSize
+ dstIP
->ihl
* 4 + TCP_HDR_LEN(dstTCP
));
1250 dstIP
->id
+= packetCounter
;
1252 dstIP
->check
= IPChecksum((UINT8
*)dstIP
, dstIP
->ihl
* 4, 0);
1253 dstTCP
->seq
= htonl(seqNumber
);
1256 * Set the TCP FIN and PSH bit only for the last packet
1257 * More information can be found under:
1258 * https://msdn.microsoft.com/en-us/library/windows/hardware/ff568840%28v=vs.85%29.aspx
1261 dstTCP
->fin
= lastPacket
;
1264 dstTCP
->psh
= lastPacket
;
1266 UINT16 csumLength
= segmentSize
+ TCP_HDR_LEN(dstTCP
);
1267 dstTCP
->check
= IPPseudoChecksum(&dstIP
->saddr
,
1271 dstTCP
->check
= CalculateChecksumNB(nb
,
1273 sizeof(*dstEth
) + dstIP
->ihl
* 4);
1276 case ETH_TYPE_IPV6_NBO
:
1278 IPv6Hdr
*dstIP
= NULL
;
1280 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1281 >= sizeof(EthHdr
) + sizeof(IPv6Hdr
) + sizeof(TCPHdr
));
1282 dstIP
= (IPv6Hdr
*)((PCHAR
)dstEth
+ sizeof(*dstEth
));
1283 dstTCP
= (TCPHdr
*)((PCHAR
)dstIP
+ sizeof(IPv6Hdr
));
1284 ASSERT((INT
)MmGetMdlByteCount(mdl
) - NET_BUFFER_CURRENT_MDL_OFFSET(nb
)
1285 >= sizeof(EthHdr
) + sizeof(IPv6Hdr
) + TCP_HDR_LEN(dstTCP
));
1288 ASSERT(dstIP
->nexthdr
== IPPROTO_TCP
);
1289 dstIP
->payload_len
= htons(segmentSize
+ sizeof(IPv6Hdr
) + TCP_HDR_LEN(dstTCP
));
1291 dstTCP
->seq
= htonl(seqNumber
);
1293 dstTCP
->fin
= lastPacket
;
1296 dstTCP
->psh
= lastPacket
;
1299 UINT16 csumLength
= segmentSize
+ TCP_HDR_LEN(dstTCP
);
1300 dstTCP
->check
= IPv6PseudoChecksum((UINT32
*)&dstIP
->saddr
,
1301 (UINT32
*)&dstIP
->daddr
,
1304 dstTCP
->check
= CalculateChecksumNB(nb
,
1306 sizeof(*dstEth
) + sizeof(IPv6Hdr
));
1310 OVS_LOG_ERROR("Invalid eth type: %d\n", dstEth
->Type
);
1311 ASSERT(! "Invalid eth type");
1314 return STATUS_SUCCESS
;
1317 * --------------------------------------------------------------------------
1318 * OvsTcpSegmentNBL --
1319 * Wrapper function to Fragment a given NBL based on MSS
1320 * --------------------------------------------------------------------------
1323 OvsTcpSegmentNBL(PVOID ovsContext
,
1324 PNET_BUFFER_LIST nbl
,
1325 POVS_PACKET_HDR_INFO hdrInfo
,
1328 BOOLEAN isIpFragment
)
1330 return OvsFragmentNBL(ovsContext
, nbl
, hdrInfo
, mss
, headRoom
, isIpFragment
);
1335 * --------------------------------------------------------------------------
1338 * Fragment NBL payload, and prepend each segment with Ether/IP/TCP header.
1339 * Leave headRoom for additional encap.
1342 * NBL should have OVS_BUFFER_CONTEXT setup before calling
1344 * The NBL should already have ref to itself so that during copy
1345 * it will not be freed.
1346 * Currently this API assert there is only one NB in an NBL, it needs
1347 * to be fixed if we receive multiple NBs in an NBL.
1348 * --------------------------------------------------------------------------
1351 OvsFragmentNBL(PVOID ovsContext
,
1352 PNET_BUFFER_LIST nbl
,
1353 POVS_PACKET_HDR_INFO hdrInfo
,
1354 UINT32 fragmentSize
,
1356 BOOLEAN isIpFragment
)
1358 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
1360 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
1362 POVS_BUFFER_CONTEXT dstCtx
, srcCtx
;
1363 UINT32 size
, hdrSize
, nblSize
, seqNumber
= 0;
1364 PNET_BUFFER_LIST newNbl
;
1365 PNET_BUFFER nb
, newNb
;
1369 UINT16 offset
= 0, packetCounter
= 0;
1371 srcCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
1372 if (srcCtx
== NULL
|| srcCtx
->magic
!= OVS_CTX_MAGIC
) {
1373 OVS_LOG_INFO("src nbl must have ctx initialized");
1374 ASSERT(srcCtx
&& srcCtx
->magic
== OVS_CTX_MAGIC
);
1378 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1379 ASSERT(NET_BUFFER_NEXT_NB(nb
) == NULL
);
1381 /* Figure out the header size */
1383 status
= GetIpHeaderInfo(nbl
, &hdrSize
);
1385 status
= GetSegmentHeaderInfo(nbl
, hdrInfo
, &hdrSize
, &seqNumber
);
1387 if (status
!= NDIS_STATUS_SUCCESS
) {
1388 OVS_LOG_INFO("Cannot parse NBL header");
1391 /* Get the NBL size. */
1393 nblSize
= fragmentSize
- hdrSize
;
1395 nblSize
= fragmentSize
;
1397 size
= NET_BUFFER_DATA_LENGTH(nb
) - hdrSize
;
1399 /* XXX add to ovsPool counters? */
1400 newNbl
= NdisAllocateFragmentNetBufferList(nbl
, NULL
, NULL
, hdrSize
,
1401 nblSize
, hdrSize
+ headRoom
,
1403 if (newNbl
== NULL
) {
1407 /* Now deal with TCP payload */
1408 for (newNb
= NET_BUFFER_LIST_FIRST_NB(newNbl
); newNb
!= NULL
;
1409 newNb
= NET_BUFFER_NEXT_NB(newNb
)) {
1410 segmentSize
= (size
> nblSize
? nblSize
: size
) & 0xffff;
1412 NdisAdvanceNetBufferDataStart(newNb
, headRoom
, FALSE
, NULL
);
1415 /* Now copy the eth/IP/TCP header and fix up */
1416 status
= NdisCopyFromNetBufferToNetBuffer(newNb
, 0, hdrSize
, nb
, 0,
1418 if (status
!= NDIS_STATUS_SUCCESS
|| hdrSize
!= copiedSize
) {
1423 status
= FixFragmentHeader(newNb
, segmentSize
,
1424 NET_BUFFER_NEXT_NB(newNb
) == NULL
,
1427 status
= FixSegmentHeader(newNb
, segmentSize
, seqNumber
,
1428 NET_BUFFER_NEXT_NB(newNb
) == NULL
,
1432 if (status
!= NDIS_STATUS_SUCCESS
) {
1436 /* Move on to the next segment */
1438 offset
+= (segmentSize
) / 8;
1440 seqNumber
+= segmentSize
;
1442 size
-= segmentSize
;
1446 status
= OvsAllocateNBLContext(context
, newNbl
);
1447 if (status
!= NDIS_STATUS_SUCCESS
) {
1451 status
= OvsCopyNBLInfo(nbl
, newNbl
, srcCtx
, hdrSize
+ headRoom
, FALSE
);
1452 if (status
!= NDIS_STATUS_SUCCESS
) {
1453 goto nbl_context_error
;
1457 /*Copy with Flag - NDIS_SWITCH_COPY_NBL_INFO_FLAGS_PRESERVE_DESTINATIONS.*/
1458 status
= context
->NdisSwitchHandlers
.
1459 CopyNetBufferListInfo(context
->ovsPool
.ndisContext
, newNbl
, nbl
, 1);
1461 if (status
!= NDIS_STATUS_SUCCESS
) {
1462 goto nbl_context_error
;
1465 newNbl
->ParentNetBufferList
= nbl
;
1467 /* Remember it's a fragment NBL so we can free it properly */
1468 dstCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl
);
1469 ASSERT(dstCtx
!= NULL
);
1470 dstCtx
->flags
= OVS_BUFFER_FRAGMENT
| OVS_BUFFER_PRIVATE_CONTEXT
|
1471 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
| OVS_BUFFER_SEND_BUFFER
;
1472 dstCtx
->refCount
= 1;
1473 dstCtx
->magic
= OVS_CTX_MAGIC
;
1474 dstCtx
->dataOffsetDelta
= hdrSize
+ headRoom
;
1477 InterlockedIncrement((LONG
volatile *)&srcCtx
->refCount
);
1479 InterlockedIncrement((LONG
volatile *)&ovsPool
->fragNBLCount
);
1481 OvsDumpNetBufferList(nbl
);
1482 OvsDumpForwardingDetails(nbl
);
1484 OvsDumpNetBufferList(newNbl
);
1485 OvsDumpForwardingDetails(newNbl
);
1487 OVS_LOG_TRACE("Fragment nbl %p to newNbl: %p", nbl
, newNbl
);
1491 OvsFreeNBLContext(context
, newNbl
);
1494 InterlockedDecrement((LONG
volatile *)&ovsPool
->fragNBLCount
);
1496 NdisFreeFragmentNetBufferList(newNbl
, hdrSize
+ headRoom
, 0);
1501 * --------------------------------------------------------------------------
1502 * OvsAllocateNBLFromBuffer --
1504 * This function allocates all the stuff necessary for creating an NBL from the
1505 * input buffer of specified length, namely, a nonpaged data buffer of size
1506 * length, an MDL from it, and a NB and NBL from it. It does not allocate an NBL
1507 * context yet. It also copies data from the specified buffer to the NBL.
1508 * --------------------------------------------------------------------------
1511 OvsAllocateNBLFromBuffer(PVOID context
,
1515 POVS_SWITCH_CONTEXT switchContext
= (POVS_SWITCH_CONTEXT
)context
;
1517 PNET_BUFFER_LIST nbl
= NULL
;
1521 if (length
> OVS_DEFAULT_DATA_SIZE
) {
1522 nbl
= OvsAllocateVariableSizeNBL(switchContext
, length
,
1523 OVS_DEFAULT_HEADROOM_SIZE
);
1526 nbl
= OvsAllocateFixSizeNBL(switchContext
, length
,
1527 OVS_DEFAULT_HEADROOM_SIZE
);
1533 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1534 mdl
= NET_BUFFER_CURRENT_MDL(nb
);
1535 data
= (PUINT8
)OvsGetMdlWithLowPriority(mdl
)
1536 + NET_BUFFER_CURRENT_MDL_OFFSET(nb
);
1538 OvsCompleteNBL(switchContext
, nbl
, TRUE
);
1542 NdisMoveMemory(data
, buffer
, length
);
1548 * --------------------------------------------------------------------------
1549 * OvsFullCopyToMultipleNBLs --
1551 * Copy NBL to multiple NBLs, each NB will have its own NBL
1552 * --------------------------------------------------------------------------
1555 OvsFullCopyToMultipleNBLs(PVOID ovsContext
,
1556 PNET_BUFFER_LIST nbl
,
1558 BOOLEAN copyNblInfo
)
1561 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)ovsContext
;
1562 PNET_BUFFER_LIST firstNbl
, currNbl
, newNbl
;
1564 POVS_BUFFER_CONTEXT srcCtx
;
1566 srcCtx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
1567 if (srcCtx
== NULL
|| srcCtx
->magic
!= OVS_CTX_MAGIC
) {
1568 OVS_LOG_INFO("src nbl must have ctx initialized");
1569 ASSERT(srcCtx
&& srcCtx
->magic
== OVS_CTX_MAGIC
);
1573 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1574 newNbl
= OvsCopySinglePacketNBL(context
, nbl
, nb
, headRoom
, copyNblInfo
);
1576 if (newNbl
== NULL
|| NET_BUFFER_NEXT_NB(nb
) == NULL
) {
1584 newNbl
= OvsCopySinglePacketNBL(context
, nbl
, nb
, headRoom
,
1586 if (newNbl
== NULL
) {
1587 goto copymultiple_error
;
1589 NET_BUFFER_LIST_NEXT_NBL(currNbl
) = newNbl
;
1591 nb
= NET_BUFFER_NEXT_NB(nb
);
1598 firstNbl
= NET_BUFFER_LIST_NEXT_NBL(firstNbl
);
1599 NET_BUFFER_LIST_NEXT_NBL(currNbl
) = NULL
;
1600 OvsCompleteNBL(context
, currNbl
, TRUE
);
1608 * --------------------------------------------------------------------------
1611 * This function tries to free the NBL allocated by OVS buffer
1612 * management module. If it trigger the completion of the parent
1613 * NBL, it will recursively call itself. If it trigger the completion
1614 * of external NBL, it will be returned to the caller. The caller
1615 * is responsible to call API to return to upper layer.
1616 * --------------------------------------------------------------------------
1619 OvsCompleteNBL(PVOID switch_ctx
,
1620 PNET_BUFFER_LIST nbl
,
1623 POVS_BUFFER_CONTEXT ctx
;
1625 PNET_BUFFER_LIST parent
;
1627 NDIS_HANDLE poolHandle
;
1629 POVS_SWITCH_CONTEXT context
= (POVS_SWITCH_CONTEXT
)switch_ctx
;
1630 POVS_NBL_POOL ovsPool
= &context
->ovsPool
;
1634 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
1636 ASSERT(ctx
&& ctx
->magic
== OVS_CTX_MAGIC
);
1638 OVS_LOG_TRACE("Enter: nbl: %p, ctx: %p, refCount: %d, updateRef:%d",
1639 nbl
, ctx
, ctx
->refCount
, updateRef
);
1642 value
= InterlockedDecrement((LONG
volatile *)&ctx
->refCount
);
1648 * This is a special case, the refCount must be zero
1650 ASSERT(ctx
->refCount
== 0);
1653 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1656 if (!(flags
& OVS_BUFFER_FRAGMENT
) &&
1657 NET_BUFFER_DATA_LENGTH(nb
) != ctx
->origDataLength
) {
1659 if (NET_BUFFER_DATA_LENGTH(nb
) < ctx
->origDataLength
) {
1660 diff
= ctx
->origDataLength
-NET_BUFFER_DATA_LENGTH(nb
);
1661 status
= NdisRetreatNetBufferListDataStart(nbl
, diff
, 0,
1663 ASSERT(status
== NDIS_STATUS_SUCCESS
);
1665 diff
= NET_BUFFER_DATA_LENGTH(nb
) - ctx
->origDataLength
;
1666 NdisAdvanceNetBufferListDataStart(nbl
, diff
, TRUE
, NULL
);
1670 if (ctx
->flags
& OVS_BUFFER_PRIVATE_CONTEXT
) {
1671 NdisFreeNetBufferListContext(nbl
, sizeof (OVS_BUFFER_CONTEXT
));
1674 if (flags
& OVS_BUFFER_NEED_COMPLETE
) {
1676 * return to caller for completion
1679 InterlockedDecrement((LONG
volatile *)&ovsPool
->sysNBLCount
);
1684 if (flags
& OVS_BUFFER_PRIVATE_FORWARD_CONTEXT
) {
1685 context
->NdisSwitchHandlers
.
1686 FreeNetBufferListForwardingContext(ovsPool
->ndisContext
, nbl
);
1689 if (flags
& (OVS_BUFFER_PRIVATE_MDL
| OVS_BUFFER_PRIVATE_DATA
)) {
1690 PNET_BUFFER nbTemp
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1692 PMDL mdl
= NET_BUFFER_FIRST_MDL(nbTemp
);
1694 ASSERT(mdl
->Next
== NULL
);
1695 OvsFreeMDLAndData(mdl
);
1697 NET_BUFFER_FIRST_MDL(nbTemp
) = NULL
;
1698 nbTemp
= NET_BUFFER_NEXT_NB(nbTemp
);
1702 if (flags
& OVS_BUFFER_PRIVATE_NET_BUFFER
) {
1703 PNET_BUFFER nbTemp
, nextNb
;
1705 nbTemp
= NET_BUFFER_LIST_FIRST_NB(nbl
);
1707 nextNb
= NET_BUFFER_NEXT_NB(nbTemp
);
1708 NdisFreeNetBuffer(nbTemp
);
1710 InterlockedDecrement((LONG
volatile *)&ovsPool
->nbCount
);
1714 NET_BUFFER_LIST_FIRST_NB(nbl
) = NULL
;
1717 parent
= nbl
->ParentNetBufferList
;
1719 poolHandle
= NdisGetPoolFromNetBufferList(nbl
);
1720 if (flags
& OVS_BUFFER_FROM_FIX_SIZE_POOL
) {
1721 ASSERT(poolHandle
== ovsPool
->fixSizePool
);
1723 InterlockedDecrement((LONG
volatile *)&ovsPool
->fixNBLCount
);
1725 NdisFreeNetBufferList(nbl
);
1726 } else if (flags
& OVS_BUFFER_FROM_ZERO_SIZE_POOL
) {
1727 ASSERT(poolHandle
== ovsPool
->zeroSizePool
);
1729 InterlockedDecrement((LONG
volatile *)&ovsPool
->zeroNBLCount
);
1731 NdisFreeNetBufferList(nbl
);
1732 } else if (flags
& OVS_BUFFER_FROM_NBL_ONLY_POOL
) {
1733 ASSERT(poolHandle
== ovsPool
->nblOnlyPool
);
1735 InterlockedDecrement((LONG
volatile *)&ovsPool
->nblOnlyCount
);
1737 NdisFreeCloneNetBufferList(nbl
, 0);
1738 } else if (flags
& OVS_BUFFER_FRAGMENT
) {
1739 OVS_LOG_TRACE("Free fragment %p parent %p", nbl
, parent
);
1741 InterlockedDecrement((LONG
volatile *)&ovsPool
->fragNBLCount
);
1743 NdisFreeFragmentNetBufferList(nbl
, ctx
->dataOffsetDelta
, 0);
1746 if (parent
!= NULL
) {
1747 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(parent
);
1748 ASSERT(ctx
&& ctx
->magic
== OVS_CTX_MAGIC
);
1749 value
= InterlockedDecrement((LONG
volatile *)&ctx
->refCount
);
1751 return OvsCompleteNBL(context
, parent
, FALSE
);
1758 * --------------------------------------------------------------------------
1759 * OvsSetCtxSourcePortNo --
1760 * Setter function which stores the source port of an NBL in the NBL
1762 * --------------------------------------------------------------------------
1765 OvsSetCtxSourcePortNo(PNET_BUFFER_LIST nbl
,
1768 POVS_BUFFER_CONTEXT ctx
;
1769 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
1771 ASSERT(ctx
&& ctx
->magic
== OVS_CTX_MAGIC
);
1772 return STATUS_INVALID_PARAMETER
;
1775 ctx
->srcPortNo
= portNo
;
1776 return NDIS_STATUS_SUCCESS
;
1780 * --------------------------------------------------------------------------
1781 * OvsGetCtxSourcePortNo --
1782 * Get source port of an NBL from its Context Info.
1783 * --------------------------------------------------------------------------
1786 OvsGetCtxSourcePortNo(PNET_BUFFER_LIST nbl
,
1789 POVS_BUFFER_CONTEXT ctx
;
1790 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
1791 if (ctx
== NULL
|| portNo
== NULL
) {
1792 ASSERT(ctx
&& ctx
->magic
== OVS_CTX_MAGIC
);
1793 return STATUS_INVALID_PARAMETER
;
1795 *portNo
= ctx
->srcPortNo
;
1796 return NDIS_STATUS_SUCCESS
;
1800 * --------------------------------------------------------------------------
1801 * OvsCreateNewNBLsFromMultipleNBs --
1802 * Creates an NBL chain where each NBL has a single NB,
1803 * from an NBL which has multiple NBs.
1804 * Sets 'curNbl' and 'lastNbl' to the first and last NBL in the
1805 * newly created NBL chain respectively, and completes the original NBL.
1806 * --------------------------------------------------------------------------
1809 OvsCreateNewNBLsFromMultipleNBs(POVS_SWITCH_CONTEXT switchContext
,
1810 PNET_BUFFER_LIST
*curNbl
,
1811 PNET_BUFFER_LIST
*lastNbl
)
1813 NTSTATUS status
= STATUS_SUCCESS
;
1814 PNET_BUFFER_LIST newNbls
= NULL
;
1815 PNET_BUFFER_LIST nbl
= NULL
;
1816 BOOLEAN error
= TRUE
;
1819 /* Create new NBLs from curNbl with multiple net buffers. */
1820 newNbls
= OvsPartialCopyToMultipleNBLs(switchContext
,
1821 *curNbl
, 0, 0, TRUE
);
1822 if (NULL
== newNbls
) {
1823 OVS_LOG_ERROR("Failed to allocate NBLs with single NB.");
1824 status
= NDIS_STATUS_RESOURCES
;
1831 nbl
= NET_BUFFER_LIST_NEXT_NBL(nbl
);
1834 (*curNbl
)->Next
= NULL
;
1836 OvsCompleteNBL(switchContext
, *curNbl
, TRUE
);