]> git.proxmox.com Git - mirror_ovs.git/blame - datapath-windows/ovsext/BufferMgmt.c
cirrus: Use FreeBSD 12.2.
[mirror_ovs.git] / datapath-windows / ovsext / BufferMgmt.c
CommitLineData
c803536e 1/*
7b383a56 2 * Copyright (c) 2014, 2016 VMware, Inc.
c803536e
SS
3 *
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:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17/*
18 * ****************************************************************************
19 *
20 * Simple Buffer Management framework for OVS
21 *
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.
25 *
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.
29 *
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.
33 *
34 * **Net buffer pool-- this is required when net buffer need to be
35 * allocated separately.
36 *
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
39 * code for details.
40 *
41 * Here is the usage of the management API
42 * All external NBL should be initialized its NBL context by calling
43 * OvsInitExternalNBLContext()
44 *
45 * After the external NBL context is initialized, it can call the following
46 * API to allocate, copy or partial copy NBL.
47 *
48 * OvsAllocateFixSizeNBL()
49 * OvsAllocateVariableSizeNBL()
50 *
51 * OvsPartialCopyNBL()
52 * OvsPartialCopyToMultipleNBLs()
53 *
54 * OvsFullCopyNBL()
55 * OvsFullCopyToMultipleNBLs()
56 *
57 * See code comments for detail description of the functions.
58 *
59 * All NBLs is completed through
60 * OvsCompleteNBL()
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.
66 *
67 * NOTE:
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.
75 *
76 * ****************************************************************************
77 */
78
79#include "precomp.h"
7b383a56
AS
80#include "Debug.h"
81#include "Flow.h"
82#include "Offload.h"
83#include "NetProto.h"
5406e557 84#include "PacketIO.h"
7b383a56 85#include "PacketParser.h"
fa1324c9 86#include "Switch.h"
7b383a56 87#include "Vport.h"
c803536e
SS
88
89#ifdef OVS_DBG_MOD
90#undef OVS_DBG_MOD
91#endif
92#define OVS_DBG_MOD OVS_DBG_BUFMGMT
7b383a56 93
c803536e
SS
94
95/*
96 * --------------------------------------------------------------------------
97 * OvsInitBufferPool --
98 *
99 * Allocate NBL and NB pool
100 *
101 * XXX: more optimization may be done for buffer management include local cache
102 * of NBL, NB, data, context, MDL.
103 * --------------------------------------------------------------------------
104 */
105NDIS_STATUS
106OvsInitBufferPool(PVOID ovsContext)
107{
108 POVS_NBL_POOL ovsPool;
109 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
110 NET_BUFFER_LIST_POOL_PARAMETERS nblParam;
111 NET_BUFFER_POOL_PARAMETERS nbParam;
112
113 C_ASSERT(MEMORY_ALLOCATION_ALIGNMENT >= 8);
114
115 OVS_LOG_TRACE("Enter: context: %p", context);
116
117 ovsPool = &context->ovsPool;
118 RtlZeroMemory(ovsPool, sizeof (OVS_NBL_POOL));
119 ovsPool->ndisHandle = context->NdisFilterHandle;
120 ovsPool->ndisContext = context->NdisSwitchContext;
121 /*
122 * fix size NBL pool includes
123 * NBL + NB + MDL + DATA + Context
124 * This is mainly used for Packet execute or slow path when copy is
125 * required and size is less than OVS_DEFAULT_DATA_SIZE. We expect
126 * Most of packet from user space will use this Pool. (This is
127 * true for all bfd and cfm packet.
128 */
129 RtlZeroMemory(&nblParam, sizeof (nblParam));
130 OVS_INIT_OBJECT_HEADER(&nblParam.Header,
131 NDIS_OBJECT_TYPE_DEFAULT,
132 NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1,
133 NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1);
134 nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE;
135 nblParam.PoolTag = OVS_FIX_SIZE_NBL_POOL_TAG;
136 nblParam.fAllocateNetBuffer = TRUE;
137 nblParam.DataSize = OVS_DEFAULT_DATA_SIZE + OVS_DEFAULT_HEADROOM_SIZE;
138
139 ovsPool->fixSizePool =
140 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
141 if (ovsPool->fixSizePool == NULL) {
142 goto pool_cleanup;
143 }
144
145 /*
146 * Zero Size NBL Pool includes
147 * NBL + NB + Context
148 * This is mainly for packet with large data Size, in this case MDL and
149 * Data will be allocate separately.
150 */
151 RtlZeroMemory(&nblParam, sizeof (nblParam));
152 OVS_INIT_OBJECT_HEADER(&nblParam.Header,
153 NDIS_OBJECT_TYPE_DEFAULT,
154 NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1,
155 NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1);
156
157 nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE;
158 nblParam.PoolTag = OVS_VARIABLE_SIZE_NBL_POOL_TAG;
159 nblParam.fAllocateNetBuffer = TRUE;
160 nblParam.DataSize = 0;
161
162 ovsPool->zeroSizePool =
163 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
164 if (ovsPool->zeroSizePool == NULL) {
165 goto pool_cleanup;
166 }
167
168 /*
169 * NBL only pool just includes
170 * NBL (+ context)
171 * This is mainly used for clone and partial copy
172 */
173 RtlZeroMemory(&nblParam, sizeof (nblParam));
174 OVS_INIT_OBJECT_HEADER(&nblParam.Header,
175 NDIS_OBJECT_TYPE_DEFAULT,
176 NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1,
177 NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1);
178
179 nblParam.ContextSize = OVS_DEFAULT_NBL_CONTEXT_SIZE;
180 nblParam.PoolTag = OVS_NBL_ONLY_POOL_TAG;
181 nblParam.fAllocateNetBuffer = FALSE;
182 nblParam.DataSize = 0;
183
184 ovsPool->nblOnlyPool =
185 NdisAllocateNetBufferListPool(context->NdisSwitchContext, &nblParam);
186 if (ovsPool->nblOnlyPool == NULL) {
187 goto pool_cleanup;
188 }
189
190 /* nb Pool
191 * NB only pool, used for copy
192 */
193
194 OVS_INIT_OBJECT_HEADER(&nbParam.Header,
195 NDIS_OBJECT_TYPE_DEFAULT,
196 NET_BUFFER_POOL_PARAMETERS_REVISION_1,
197 NDIS_SIZEOF_NET_BUFFER_POOL_PARAMETERS_REVISION_1);
198 nbParam.PoolTag = OVS_NET_BUFFER_POOL_TAG;
199 nbParam.DataSize = 0;
200 ovsPool->nbPool =
201 NdisAllocateNetBufferPool(context->NdisSwitchContext, &nbParam);
202 if (ovsPool->nbPool == NULL) {
203 goto pool_cleanup;
204 }
205 OVS_LOG_TRACE("Exit: fixSizePool: %p zeroSizePool: %p nblOnlyPool: %p"
206 "nbPool: %p", ovsPool->fixSizePool, ovsPool->zeroSizePool,
207 ovsPool->nblOnlyPool, ovsPool->nbPool);
208 return NDIS_STATUS_SUCCESS;
209
210pool_cleanup:
211 OvsCleanupBufferPool(context);
212 OVS_LOG_TRACE("Exit: Fail to initialize ovs buffer pool");
213 return NDIS_STATUS_RESOURCES;
214}
215
216
217/*
218 * --------------------------------------------------------------------------
219 * OvsCleanupBufferPool --
220 * Free Buffer pool for NBL and NB.
221 * --------------------------------------------------------------------------
222 */
223VOID
224OvsCleanupBufferPool(PVOID ovsContext)
225{
226 POVS_NBL_POOL ovsPool;
227 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
228 ovsPool = &context->ovsPool;
229 OVS_LOG_TRACE("Enter: context: %p", context);
230#ifdef DBG
231 ASSERT(ovsPool->fixNBLCount == 0);
232 ASSERT(ovsPool->zeroNBLCount == 0);
233 ASSERT(ovsPool->nblOnlyCount == 0);
234 ASSERT(ovsPool->nbCount == 0);
235 ASSERT(ovsPool->sysNBLCount == 0);
236 ASSERT(ovsPool->fragNBLCount == 0);
237#endif
238
239 if (ovsPool->fixSizePool) {
240 NdisFreeNetBufferListPool(ovsPool->fixSizePool);
241 ovsPool->fixSizePool = NULL;
242 }
243 if (ovsPool->zeroSizePool) {
244 NdisFreeNetBufferListPool(ovsPool->zeroSizePool);
245 ovsPool->zeroSizePool = NULL;
246 }
247 if (ovsPool->nblOnlyPool) {
248 NdisFreeNetBufferListPool(ovsPool->nblOnlyPool);
249 ovsPool->nblOnlyPool = NULL;
250 }
251 if (ovsPool->nbPool) {
252 NdisFreeNetBufferPool(ovsPool->nbPool);
253 ovsPool->nbPool = NULL;
254 }
255 OVS_LOG_TRACE("Exit: cleanup OVS Buffer pool");
256}
257
258
259static VOID
260OvsInitNBLContext(POVS_BUFFER_CONTEXT ctx,
261 UINT16 flags,
262 UINT32 origDataLength,
672c8c69
AK
263 UINT32 srcPortNo,
264 UINT16 mru)
c803536e
SS
265{
266 ctx->magic = OVS_CTX_MAGIC;
267 ctx->refCount = 1;
268 ctx->flags = flags;
269 ctx->srcPortNo = srcPortNo;
270 ctx->origDataLength = origDataLength;
672c8c69 271 ctx->mru = mru;
5406e557 272 ctx->pendingSend = 0;
c803536e
SS
273}
274
275
276static VOID
277OvsDumpForwardingDetails(PNET_BUFFER_LIST nbl)
278{
34825d5e 279#if OVS_DBG_DEFAULT >= OVS_DBG_LOUD
c803536e
SS
280 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
281 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
282 if (info == NULL) {
283 return;
284 }
285 OVS_LOG_INFO("nbl: %p, numAvailableDest: %d, srcId:%d, srcIndex: %d "
286 "isDataSafe: %s, safeDataSize: %d",
287 nbl, info->NumAvailableDestinations, info->SourcePortId,
288 info->SourceNicIndex,
289 info->IsPacketDataSafe ? "TRUE" : "FALSE",
290 info->IsPacketDataSafe ? 0 : info->SafePacketDataSize);
34825d5e
AK
291#else
292 UNREFERENCED_PARAMETER(nbl);
293#endif
c803536e
SS
294}
295
296static VOID
297OvsDumpNBLContext(PNET_BUFFER_LIST nbl)
298{
34825d5e 299#if OVS_DBG_DEFAULT >= OVS_DBG_LOUD
c803536e
SS
300 PNET_BUFFER_LIST_CONTEXT ctx = nbl->Context;
301 if (ctx == NULL) {
302 OVS_LOG_INFO("No Net Buffer List context");
303 return;
304 }
305 while (ctx) {
306 OVS_LOG_INFO("nbl: %p, ctx: %p, TotalSize: %d, Offset: %d",
307 nbl, ctx, ctx->Size, ctx->Offset);
308 ctx = ctx->Next;
309 }
34825d5e
AK
310#else
311 UNREFERENCED_PARAMETER(nbl);
312#endif
c803536e
SS
313}
314
315
316static VOID
317OvsDumpMDLChain(PMDL mdl)
318{
319 PMDL tmp;
320 tmp = mdl;
321 while (tmp) {
322 OVS_LOG_INFO("MDL: %p, Size: %d, MappedSystemVa: %p, StartVa: %p"
323 " ByteCount: %d, ByteOffset: %d",
324 tmp, tmp->Size, tmp->MappedSystemVa,
325 tmp->StartVa, tmp->ByteCount, tmp->ByteOffset);
326 tmp = tmp->Next;
327 }
328}
329
330
331static VOID
332OvsDumpNetBuffer(PNET_BUFFER nb)
333{
334 OVS_LOG_INFO("NET_BUFFER: %p, ChecksumBias: %d Handle: %p, MDLChain: %p "
335 "CurrMDL: %p, CurrOffset: %d, DataLen: %d, Offset: %d",
336 nb,
337 NET_BUFFER_CHECKSUM_BIAS(nb), nb->NdisPoolHandle,
338 NET_BUFFER_FIRST_MDL(nb),
339 NET_BUFFER_CURRENT_MDL(nb),
340 NET_BUFFER_CURRENT_MDL_OFFSET(nb),
341 NET_BUFFER_DATA_LENGTH(nb),
342 NET_BUFFER_DATA_OFFSET(nb));
343 OvsDumpMDLChain(NET_BUFFER_FIRST_MDL(nb));
344}
345
346
347static VOID
348OvsDumpNetBufferList(PNET_BUFFER_LIST nbl)
349{
34825d5e 350#if OVS_DBG_DEFAULT >= OVS_DBG_LOUD
c803536e
SS
351 PNET_BUFFER nb;
352 OVS_LOG_INFO("NBL: %p, parent: %p, SrcHandle: %p, ChildCount:%d "
353 "poolHandle: %p",
354 nbl, nbl->ParentNetBufferList,
355 nbl->SourceHandle, nbl->ChildRefCount,
356 nbl->NdisPoolHandle);
357 OvsDumpNBLContext(nbl);
358 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
359 while (nb) {
360 OvsDumpNetBuffer(nb);
361 nb = NET_BUFFER_NEXT_NB(nb);
362 }
34825d5e
AK
363#else
364 UNREFERENCED_PARAMETER(nbl);
365#endif
c803536e
SS
366}
367
368/*
369 * --------------------------------------------------------------------------
370 * OvsAllocateFixSizeNBL --
371 *
372 * Allocate fix size NBL which include
373 * NBL + NB + MBL + Data + Context
374 * Please note:
375 * * Forwarding Context is allocated, but forwarding detail information
376 * is not initailized.
377 * * The headroom can not be larger than OVS_DEFAULT_HEADROOM_SIZE(128
378 * byte).
379 * --------------------------------------------------------------------------
380 */
381PNET_BUFFER_LIST
382OvsAllocateFixSizeNBL(PVOID ovsContext,
383 UINT32 size,
384 UINT32 headRoom)
385{
386 PNET_BUFFER_LIST nbl = NULL;
387 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
388 POVS_BUFFER_CONTEXT ctx;
389 POVS_NBL_POOL ovsPool = &context->ovsPool;
390 NDIS_STATUS status;
391 UINT32 line;
392 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
393
394 if ((headRoom + size) > OVS_FIX_NBL_DATA_SIZE || size == 0) {
395 line = __LINE__;
396 goto allocate_done;
397 }
398
399 nbl = NdisAllocateNetBufferList(ovsPool->fixSizePool,
400 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
401 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
402
403 if (nbl == NULL) {
404 line = __LINE__;
405 goto allocate_done;
406 }
407
408 nbl->SourceHandle = ovsPool->ndisHandle;
409 status = context->NdisSwitchHandlers.
410 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
411
412 if (status != NDIS_STATUS_SUCCESS) {
413 NdisFreeNetBufferList(nbl);
414 nbl = NULL;
415 line = __LINE__;
416 goto allocate_done;
417 }
418 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
419 ASSERT(info);
420 info->IsPacketDataSafe = TRUE;
421 info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
422
423 status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
424 size, 0, NULL);
425 ASSERT(status == NDIS_STATUS_SUCCESS);
426
427#ifdef DBG
428 InterlockedIncrement((LONG volatile *)&ovsPool->fixNBLCount);
429 OvsDumpNetBufferList(nbl);
430 OvsDumpForwardingDetails(nbl);
431#endif
432
433 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
434 ASSERT(ctx);
435
436 OvsInitNBLContext(ctx, OVS_BUFFER_FROM_FIX_SIZE_POOL |
437 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT, size,
672c8c69 438 OVS_DPPORT_NUMBER_INVALID, 0);
c803536e
SS
439 line = __LINE__;
440allocate_done:
441 OVS_LOG_LOUD("Allocate Fix NBL: %p, line: %d", nbl, line);
442 return nbl;
443}
444
445
446static PMDL
447OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle,
448 UINT32 dataSize)
449{
450 PMDL mdl;
451 PVOID data;
452
48b3e646 453 data = OvsAllocateMemoryWithTag(dataSize, OVS_MDL_POOL_TAG);
c803536e
SS
454 if (data == NULL) {
455 return NULL;
456 }
457
458 mdl = NdisAllocateMdl(ndisHandle, data, dataSize);
459 if (mdl == NULL) {
48b3e646 460 OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
c803536e
SS
461 }
462
463 return mdl;
464}
465
466
467static VOID
468OvsFreeMDLAndData(PMDL mdl)
469{
470 PVOID data;
471
472 data = MmGetMdlVirtualAddress(mdl);
473 NdisFreeMdl(mdl);
48b3e646 474 OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
c803536e
SS
475}
476
477
478/*
479 * --------------------------------------------------------------------------
480 * OvsAllocateVariableSizeNBL --
481 *
482 * Allocate variable size NBL, the NBL looks like
483 * NBL + NB + Context
484 * MDL + Data
485 * --------------------------------------------------------------------------
486 */
487PNET_BUFFER_LIST
488OvsAllocateVariableSizeNBL(PVOID ovsContext,
489 UINT32 size,
490 UINT32 headRoom)
491{
492 PNET_BUFFER_LIST nbl = NULL;
493 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
494 POVS_NBL_POOL ovsPool = &context->ovsPool;
495 POVS_BUFFER_CONTEXT ctx;
496 UINT32 realSize;
497 PMDL mdl;
498 NDIS_STATUS status;
499 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
500 if (size == 0) {
501 return NULL;
502 }
503 realSize = MEM_ALIGN_SIZE(size + headRoom);
504
505 mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, realSize);
506 if (mdl == NULL) {
507 return NULL;
508 }
509
510 nbl = NdisAllocateNetBufferAndNetBufferList(ovsPool->zeroSizePool,
511 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
512 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL,
513 mdl, realSize, 0);
514 if (nbl == NULL) {
515 OvsFreeMDLAndData(mdl);
516 return NULL;
517 }
518
519 nbl->SourceHandle = ovsPool->ndisHandle;
520 status = context->NdisSwitchHandlers.
521 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
522
523 if (status != NDIS_STATUS_SUCCESS) {
524 /*
525 * do we need to remove mdl from nbl XXX
526 */
527 OvsFreeMDLAndData(mdl);
528 NdisFreeNetBufferList(nbl);
529 return NULL;
530 }
531
532 info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
533 ASSERT(info);
534 info->IsPacketDataSafe = TRUE;
535 info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
536 status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
537 size, 0, NULL);
538 ASSERT(status == NDIS_STATUS_SUCCESS);
539
540#ifdef DBG
541 InterlockedIncrement((LONG volatile *)&ovsPool->zeroNBLCount);
542 OvsDumpNetBufferList(nbl);
543 OvsDumpForwardingDetails(nbl);
544#endif
545
546 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
547
548 OvsInitNBLContext(ctx, OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
549 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT |
550 OVS_BUFFER_FROM_ZERO_SIZE_POOL,
672c8c69 551 size, OVS_DPPORT_NUMBER_INVALID, 0);
c803536e
SS
552
553 OVS_LOG_LOUD("Allocate variable size NBL: %p", nbl);
554 return nbl;
555}
556
557
558/*
559 * --------------------------------------------------------------------------
560 * OvsInitExternalNBLContext --
561 *
562 * For NBL not allocated by OVS, it will allocate and initialize
563 * the NBL context.
564 * --------------------------------------------------------------------------
565 */
566POVS_BUFFER_CONTEXT
567OvsInitExternalNBLContext(PVOID ovsContext,
568 PNET_BUFFER_LIST nbl,
569 BOOLEAN isRecv)
570{
571 NDIS_HANDLE poolHandle;
572 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
573 POVS_BUFFER_CONTEXT ctx;
574 PNET_BUFFER nb;
575 NDIS_STATUS status;
576 UINT16 flags;
577
578 poolHandle = NdisGetPoolFromNetBufferList(nbl);
579
7552cf4b
SV
580 if (poolHandle == context->ovsPool.ndisHandle ||
581 nbl->SourceHandle == context->ovsPool.ndisHandle) {
c803536e
SS
582 return (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
583 }
584 status = NdisAllocateNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT),
585 OVS_DEFAULT_NBL_CONTEXT_FILL,
586 OVS_OTHER_POOL_TAG);
587 if (status != NDIS_STATUS_SUCCESS) {
588 return NULL;
589 }
590#ifdef DBG
591 OvsDumpNBLContext(nbl);
592 InterlockedIncrement((LONG volatile *)&context->ovsPool.sysNBLCount);
593#endif
594 flags = isRecv ? OVS_BUFFER_RECV_BUFFER : OVS_BUFFER_SEND_BUFFER;
595 flags |= OVS_BUFFER_NEED_COMPLETE | OVS_BUFFER_PRIVATE_CONTEXT;
596 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
597
598 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
599 /*
600 * we use first nb to decide whether we need advance or retreat during
601 * complete.
602 */
12e888ba 603 OvsInitNBLContext(ctx, flags, NET_BUFFER_DATA_LENGTH(nb),
672c8c69 604 OVS_DPPORT_NUMBER_INVALID, 0);
c803536e
SS
605 return ctx;
606}
607
608/*
609 * --------------------------------------------------------------------------
610 * OvsAllocateNBLContext
611 *
612 * Create NBL buffer context and forwarding context.
613 * --------------------------------------------------------------------------
614 */
615NDIS_STATUS
616OvsAllocateNBLContext(POVS_SWITCH_CONTEXT context,
617 PNET_BUFFER_LIST nbl)
618{
619 POVS_NBL_POOL ovsPool = &context->ovsPool;
620 NDIS_STATUS status;
621
622 status = NdisAllocateNetBufferListContext(nbl,
623 sizeof (OVS_BUFFER_CONTEXT),
624 OVS_DEFAULT_NBL_CONTEXT_FILL,
625 OVS_OTHER_POOL_TAG);
626 if (status != NDIS_STATUS_SUCCESS) {
627 return NDIS_STATUS_FAILURE;
628 }
629
630 nbl->SourceHandle = ovsPool->ndisHandle;
631 status = context->NdisSwitchHandlers.
632 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
633
634 if (status != NDIS_STATUS_SUCCESS) {
635 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
636 return NDIS_STATUS_FAILURE;
637 }
638 return status;
639}
640
641/*
642 * --------------------------------------------------------------------------
643 * OvsFreeNBLContext
644 *
645 * Free the NBL buffer context and forwarding context.
646 * --------------------------------------------------------------------------
647 */
648NDIS_STATUS
649OvsFreeNBLContext(POVS_SWITCH_CONTEXT context,
650 PNET_BUFFER_LIST nbl)
651{
652 POVS_NBL_POOL ovsPool = &context->ovsPool;
653
654 context->NdisSwitchHandlers.
655 FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
656 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
657
658 return NDIS_STATUS_SUCCESS;
659}
660
661/*
662 * --------------------------------------------------------------------------
663 * OvsCopyNBLInfo
664 *
665 * Copy NBL info from src to dst
666 * --------------------------------------------------------------------------
667 */
668NDIS_STATUS
669OvsCopyNBLInfo(PNET_BUFFER_LIST srcNbl, PNET_BUFFER_LIST dstNbl,
670 POVS_BUFFER_CONTEXT srcCtx, UINT32 copySize,
671 BOOLEAN copyNblInfo)
672{
673 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO srcInfo, dstInfo;
674 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
675
676 srcInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(srcNbl);
677 dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(dstNbl);
678 if (srcInfo) {
679#ifdef OVS_USE_COPY_NET_BUFFER_LIST_INFO
680 status = context->NdisSwitchHandlers.
681 CopyNetBufferListInfo(ovsPool->ndisContext, dstNbl, srcNbl, 0);
682
683 if (status != NDIS_STATUS_SUCCESS) {
684 return status;
685 }
686#else
687 dstInfo->SourcePortId = srcInfo->SourcePortId;
688 dstInfo->SourceNicIndex = srcInfo->SourceNicIndex;
689 if (copyNblInfo) {
690 if (srcCtx->flags & OVS_BUFFER_RECV_BUFFER) {
691 NdisCopyReceiveNetBufferListInfo(dstNbl, srcNbl);
692 } else if (srcCtx->flags & OVS_BUFFER_SEND_BUFFER) {
693 NdisCopySendNetBufferListInfo(dstNbl, srcNbl);
694 }
695 }
696#endif
697 dstInfo->IsPacketDataSafe = srcInfo->IsPacketDataSafe;
698 if (!srcInfo->IsPacketDataSafe && copySize >
699 srcInfo->SafePacketDataSize) {
700 srcInfo->SafePacketDataSize = copySize;
701 }
702 } else {
703 /*
704 * Assume all data are safe
705 */
706 dstInfo->IsPacketDataSafe = TRUE;
707 dstInfo->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
708 }
709 return status;
710}
711
712/*
713 * --------------------------------------------------------------------------
714 * OvsPartialCopyNBL --
715 *
716 * Partial copy NBL, if there is multiple NB in NBL, each one will be
717 * copied. We also reserve headroom for the new NBL.
718 *
719 * Please note,
720 * NBL should have OVS_BUFFER_CONTEXT setup before calling
721 * this function.
722 * The NBL should already have ref to itself so that during copy
723 * it will not be freed.
724 * --------------------------------------------------------------------------
725 */
726PNET_BUFFER_LIST
727OvsPartialCopyNBL(PVOID ovsContext,
728 PNET_BUFFER_LIST nbl,
729 UINT32 copySize,
730 UINT32 headRoom,
731 BOOLEAN copyNblInfo)
732{
733 PNET_BUFFER_LIST newNbl;
734 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
735 NDIS_STATUS status;
736 PNET_BUFFER srcNb, dstNb;
737 ULONG byteCopied;
738 POVS_NBL_POOL ovsPool = &context->ovsPool;
739 POVS_BUFFER_CONTEXT srcCtx, dstCtx;
740 UINT16 flags;
741
742 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
743 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
744 OVS_LOG_INFO("src nbl must have ctx initialized");
745 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
746 return NULL;
747 }
748
749 if (copySize) {
750 NdisAdvanceNetBufferListDataStart(nbl, copySize, FALSE, NULL);
751 }
752 newNbl = NdisAllocateCloneNetBufferList(nbl, ovsPool->nblOnlyPool,
753 NULL, 0);
754 if (copySize) {
755 status = NdisRetreatNetBufferListDataStart(nbl, copySize, 0,
756 NULL, NULL);
757 ASSERT(status == NDIS_STATUS_SUCCESS);
758 }
759
760 if (newNbl == NULL) {
761 return NULL;
762 }
763
764 /*
765 * Allocate private memory for copy
766 */
767 if (copySize + headRoom) {
768 status = NdisRetreatNetBufferListDataStart(newNbl, copySize + headRoom,
769 0, NULL, NULL);
770 if (status != NDIS_STATUS_SUCCESS) {
771 goto retreat_error;
772 }
773
774 if (headRoom) {
775 NdisAdvanceNetBufferListDataStart(newNbl, headRoom, FALSE, NULL);
776 }
777 if (copySize) {
778 srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
779 dstNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
780
781 while (srcNb) {
782 status = NdisCopyFromNetBufferToNetBuffer(dstNb, 0, copySize,
783 srcNb, 0,
784 &byteCopied);
785 if (status != NDIS_STATUS_SUCCESS || copySize != byteCopied) {
786 goto nbl_context_error;
787 }
788 srcNb = NET_BUFFER_NEXT_NB(srcNb);
789 dstNb = NET_BUFFER_NEXT_NB(dstNb);
790 }
791 }
792 }
793
794 status = OvsAllocateNBLContext(context, newNbl);
795 if (status != NDIS_STATUS_SUCCESS) {
796 goto nbl_context_error;
797 }
798
799 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copySize, copyNblInfo);
800 if (status != NDIS_STATUS_SUCCESS) {
801 goto copy_list_info_error;
802 }
803
804#ifdef DBG
805 InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
806#endif
807
808 newNbl->ParentNetBufferList = nbl;
809
810 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
811 ASSERT(dstCtx != NULL);
812
813 flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
814
815 flags |= OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_CONTEXT |
816 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;
817
818 srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
0d4374aa 819 ASSERT(srcNb);
c803536e 820 OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(srcNb) - copySize,
672c8c69 821 OVS_DPPORT_NUMBER_INVALID, srcCtx->mru);
c803536e
SS
822
823 InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
7552cf4b 824
c803536e
SS
825#ifdef DBG
826 OvsDumpNetBufferList(nbl);
827 OvsDumpForwardingDetails(nbl);
828
829 OvsDumpNetBufferList(newNbl);
830 OvsDumpForwardingDetails(newNbl);
831#endif
7552cf4b 832
c803536e
SS
833 OVS_LOG_LOUD("Partial Copy new NBL: %p", newNbl);
834 return newNbl;
835
836copy_list_info_error:
837 OvsFreeNBLContext(context, newNbl);
838nbl_context_error:
839 if (copySize) {
840 NdisAdvanceNetBufferListDataStart(newNbl, copySize, TRUE, NULL);
841 }
842retreat_error:
843 NdisFreeCloneNetBufferList(newNbl, 0);
844 return NULL;
845}
846
847/*
848 * --------------------------------------------------------------------------
849 * OvsPartialCopyToMultipleNBLs --
850 *
851 * This is similar to OvsPartialCopyNBL() except that each NB will
852 * have its own NBL.
853 * --------------------------------------------------------------------------
854 */
855PNET_BUFFER_LIST
856OvsPartialCopyToMultipleNBLs(PVOID ovsContext,
857 PNET_BUFFER_LIST nbl,
858 UINT32 copySize,
859 UINT32 headRoom,
860 BOOLEAN copyNblInfo)
861{
862 PNET_BUFFER nb, nextNb = NULL, firstNb, prevNb;
863 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
864 PNET_BUFFER_LIST firstNbl = NULL, newNbl, prevNbl = NULL;
865
866 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
867 if (NET_BUFFER_NEXT_NB(nb) == NULL) {
868 return OvsPartialCopyNBL(context, nbl, copySize, headRoom, copyNblInfo);
869 }
870
871 firstNb = nb;
872 prevNb = nb;
873
874 while (nb) {
875 nextNb = NET_BUFFER_NEXT_NB(nb);
876 NET_BUFFER_NEXT_NB(nb) = NULL;
877
878 NET_BUFFER_LIST_FIRST_NB(nbl) = nb;
879
880 newNbl = OvsPartialCopyNBL(context, nbl, copySize, headRoom,
881 copyNblInfo);
882 if (newNbl == NULL) {
883 goto cleanup;
884 }
885 if (prevNbl == NULL) {
886 firstNbl = newNbl;
887 } else {
caa63627 888 NET_BUFFER_LIST_NEXT_NBL(prevNbl) = newNbl;
c803536e
SS
889 NET_BUFFER_NEXT_NB(prevNb) = nb;
890 }
891 prevNbl = newNbl;
892 prevNb = nb;
893 nb = nextNb;
894 }
895 NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;
896 return firstNbl;
897
898cleanup:
899 NET_BUFFER_NEXT_NB(prevNb) = nb;
900 NET_BUFFER_NEXT_NB(nb) = nextNb;
901 NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;
902
903 newNbl = firstNbl;
904 while (newNbl) {
905 firstNbl = NET_BUFFER_LIST_NEXT_NBL(newNbl);
885648d9 906 NET_BUFFER_LIST_NEXT_NBL(newNbl) = NULL;
c803536e
SS
907 OvsCompleteNBL(context, newNbl, TRUE);
908 newNbl = firstNbl;
909 }
910 return NULL;
911}
912
913
914static PNET_BUFFER_LIST
915OvsCopySinglePacketNBL(PVOID ovsContext,
916 PNET_BUFFER_LIST nbl,
917 PNET_BUFFER nb,
918 UINT32 headRoom,
919 BOOLEAN copyNblInfo)
920{
921 UINT32 size;
922 ULONG copiedSize;
923 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
924 PNET_BUFFER_LIST newNbl;
925 PNET_BUFFER newNb;
926 NDIS_STATUS status;
927 POVS_BUFFER_CONTEXT srcCtx, dstCtx;
928
929 size = NET_BUFFER_DATA_LENGTH(nb);
930 if ((size + headRoom) <= OVS_FIX_NBL_DATA_SIZE) {
931 newNbl = OvsAllocateFixSizeNBL(context, size, headRoom);
932 } else {
933 newNbl = OvsAllocateVariableSizeNBL(context, size, headRoom);
934 }
935 if (newNbl == NULL) {
936 return NULL;
937 }
938 newNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
939 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
940 &copiedSize);
941
942 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
943 if (status == NDIS_STATUS_SUCCESS) {
944 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copiedSize, copyNblInfo);
945 }
946
947 if (status != NDIS_STATUS_SUCCESS || copiedSize != size) {
948 OvsCompleteNBL(context, newNbl, TRUE);
949 return NULL;
950 }
951
952 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
953 ASSERT(dstCtx && srcCtx);
954 ASSERT(srcCtx->magic == OVS_CTX_MAGIC && dstCtx->magic == OVS_CTX_MAGIC);
955
956 dstCtx->flags |= srcCtx->flags & (OVS_BUFFER_RECV_BUFFER |
957 OVS_BUFFER_SEND_BUFFER);
958#ifdef DBG
959 OvsDumpNetBufferList(newNbl);
960 OvsDumpForwardingDetails(newNbl);
961#endif
962 OVS_LOG_LOUD("Copy single nb to new NBL: %p", newNbl);
963 return newNbl;
964}
965
966/*
967 * --------------------------------------------------------------------------
968 * OvsFullCopyNBL --
969 *
970 * Copy the NBL to a new NBL including data.
971 *
972 * Notes:
973 * The NBL can have multiple NBs, but the final result is one NBL.
974 * --------------------------------------------------------------------------
975 */
976PNET_BUFFER_LIST
977OvsFullCopyNBL(PVOID ovsContext,
978 PNET_BUFFER_LIST nbl,
979 UINT32 headRoom,
980 BOOLEAN copyNblInfo)
981{
982 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
983 POVS_NBL_POOL ovsPool = &context->ovsPool;
984 PNET_BUFFER_LIST newNbl;
985 PNET_BUFFER nb, newNb, firstNb = NULL, prevNb = NULL;
986 POVS_BUFFER_CONTEXT dstCtx, srcCtx;
987 PMDL mdl;
988 NDIS_STATUS status;
989 UINT32 size, totalSize;
990 ULONG copiedSize;
991 UINT16 flags;
992 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo;
993
994 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
995 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
996 OVS_LOG_INFO("src nbl must have ctx initialized");
997 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
998 return NULL;
999 }
1000
1001 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
445995a8
AS
1002 if (nb == NULL) {
1003 return NULL;
1004 }
c803536e
SS
1005
1006 if (NET_BUFFER_NEXT_NB(nb) == NULL) {
1007 return OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
1008 }
1009
1010 newNbl = NdisAllocateNetBufferList(ovsPool->nblOnlyPool,
1011 (UINT16)sizeof (OVS_BUFFER_CONTEXT),
1012 (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
1013 if (newNbl == NULL) {
1014 return NULL;
1015 }
1016
1017 while (nb) {
1018 size = NET_BUFFER_DATA_LENGTH(nb);
1019 totalSize = MEM_ALIGN_SIZE(size + headRoom);
1020 mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, totalSize);
1021
1022 if (mdl == NULL) {
1023 goto nblcopy_error;
1024 }
1025 newNb = NdisAllocateNetBuffer(ovsPool->nbPool, mdl, totalSize, 0);
1026 if (newNb == NULL) {
1027 OvsFreeMDLAndData(mdl);
1028 goto nblcopy_error;
1029 }
1030 if (firstNb == NULL) {
1031 firstNb = newNb;
1032 } else {
1033 NET_BUFFER_NEXT_NB(prevNb) = newNb;
1034 }
1035 prevNb = newNb;
1036#ifdef DBG
1037 InterlockedIncrement((LONG volatile *)&ovsPool->nbCount);
1038#endif
1039 status = NdisRetreatNetBufferDataStart(newNb, size, 0, NULL);
1040 ASSERT(status == NDIS_STATUS_SUCCESS);
1041
1042 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
1043 &copiedSize);
1044 if (status != NDIS_STATUS_SUCCESS || size != copiedSize) {
1045 goto nblcopy_error;
1046 }
1047
1048 nb = NET_BUFFER_NEXT_NB(nb);
1049 }
1050
1051 NET_BUFFER_LIST_FIRST_NB(newNbl) = firstNb;
1052
1053 newNbl->SourceHandle = ovsPool->ndisHandle;
1054 status = context->NdisSwitchHandlers.
1055 AllocateNetBufferListForwardingContext(ovsPool->ndisContext, newNbl);
1056
1057 if (status != NDIS_STATUS_SUCCESS) {
1058 goto nblcopy_error;
1059 }
1060
1061 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, 0, copyNblInfo);
1062 if (status != NDIS_STATUS_SUCCESS) {
1063 goto nblcopy_error;
1064 }
1065
1066 dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl);
1067 dstInfo->IsPacketDataSafe = TRUE;
1068
1069 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
1070
1071 flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
1072
1073 flags |= OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
1074 OVS_BUFFER_PRIVATE_NET_BUFFER | OVS_BUFFER_FROM_NBL_ONLY_POOL |
1075 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;
1076
1077 OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(firstNb),
672c8c69 1078 OVS_DPPORT_NUMBER_INVALID, srcCtx->mru);
c803536e
SS
1079
1080#ifdef DBG
1081 OvsDumpNetBufferList(nbl);
1082 OvsDumpForwardingDetails(nbl);
1083 InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
1084#endif
1085 OVS_LOG_LOUD("newNbl: %p", newNbl);
1086 return newNbl;
1087
1088nblcopy_error:
1089 while (firstNb) {
1090#ifdef DBG
1091 InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
1092#endif
1093 prevNb = firstNb;
1094 firstNb = NET_BUFFER_NEXT_NB(prevNb);
1095 mdl = NET_BUFFER_FIRST_MDL(prevNb);
1096 NET_BUFFER_FIRST_MDL(prevNb) = NULL;
1097 NdisFreeNetBuffer(prevNb);
1098 OvsFreeMDLAndData(mdl);
1099 }
1100 NdisFreeNetBufferList(newNbl);
1101 OVS_LOG_ERROR("OvsFullCopyNBL failed");
1102 return NULL;
1103}
1104
ac8df9f6
AK
1105NDIS_STATUS
1106GetIpHeaderInfo(PNET_BUFFER_LIST curNbl,
202b8137 1107 const POVS_PACKET_HDR_INFO hdrInfo,
ac8df9f6
AK
1108 UINT32 *hdrSize)
1109{
ac8df9f6
AK
1110 EthHdr *eth;
1111 IPHdr *ipHdr;
1112 PNET_BUFFER curNb;
1113
1114 curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
1115 ASSERT(NET_BUFFER_NEXT_NB(curNb) == NULL);
1116
202b8137
AK
1117 eth = (EthHdr *)NdisGetDataBuffer(curNb,
1118 hdrInfo->l4Offset,
1119 NULL, 1, 0);
ac8df9f6
AK
1120 if (eth == NULL) {
1121 return NDIS_STATUS_INVALID_PACKET;
1122 }
202b8137
AK
1123 ipHdr = (IPHdr *)((PCHAR)eth + hdrInfo->l3Offset);
1124 *hdrSize = (UINT32)(hdrInfo->l3Offset + (ipHdr->ihl * 4));
ac8df9f6
AK
1125 return NDIS_STATUS_SUCCESS;
1126}
1127
c803536e
SS
1128/*
1129 * --------------------------------------------------------------------------
1130 * GetSegmentHeaderInfo
1131 *
1132 * Extract header size and sequence number for the segment.
1133 * --------------------------------------------------------------------------
1134 */
1135static NDIS_STATUS
1136GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl,
1137 const POVS_PACKET_HDR_INFO hdrInfo,
1138 UINT32 *hdrSize, UINT32 *seqNumber)
1139{
1140 TCPHdr tcpStorage;
1141 const TCPHdr *tcp;
1142
1143 /* Parse the orginal Eth/IP/TCP header */
1144 tcp = OvsGetPacketBytes(nbl, sizeof *tcp, hdrInfo->l4Offset, &tcpStorage);
1145 if (tcp == NULL) {
1146 return NDIS_STATUS_FAILURE;
1147 }
1148 *seqNumber = ntohl(tcp->seq);
1149 *hdrSize = hdrInfo->l4Offset + TCP_HDR_LEN(tcp);
1150
1151 return NDIS_STATUS_SUCCESS;
1152}
1153
ac8df9f6
AK
1154/*
1155 * --------------------------------------------------------------------------
1156 * FixFragmentHeader
1157 *
1158 * Fix IP length, Offset, IP checksum.
1159 * XXX - Support IpV6 Fragments
1160 * --------------------------------------------------------------------------
1161 */
1162static NDIS_STATUS
1163FixFragmentHeader(PNET_BUFFER nb, UINT16 fragmentSize,
1164 BOOLEAN lastPacket, UINT16 offset)
1165{
1166 EthHdr *dstEth = NULL;
1167 PMDL mdl = NULL;
1168 PUINT8 bufferStart = NULL;
1169
1170 mdl = NET_BUFFER_FIRST_MDL(nb);
1171
cba5d148 1172 bufferStart = (PUINT8)OvsGetMdlWithLowPriority(mdl);
ac8df9f6
AK
1173 if (!bufferStart) {
1174 return NDIS_STATUS_RESOURCES;
1175 }
1176 dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb));
1177
1178 switch (dstEth->Type) {
1179 case ETH_TYPE_IPV4_NBO:
1180 {
1181 IPHdr *dstIP = NULL;
1182 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1183 >= sizeof(EthHdr) + sizeof(IPHdr));
1184
1185 dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth));
1186 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1187 >= sizeof(EthHdr) + dstIP->ihl * 4);
1188 dstIP->tot_len = htons(fragmentSize + dstIP->ihl * 4);
1189 if (lastPacket) {
1190 dstIP->frag_off = htons(offset & IP_OFFSET);
1191 } else {
1192 dstIP->frag_off = htons((offset & IP_OFFSET) | IP_MF);
1193 }
1194
1195 dstIP->check = 0;
1196 dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);
1197 break;
1198 }
1199 case ETH_TYPE_IPV6_NBO:
1200 {
1201 return NDIS_STATUS_NOT_SUPPORTED;
1202 }
1203 default:
1204 OVS_LOG_ERROR("Invalid eth type: %d\n", dstEth->Type);
1205 ASSERT(! "Invalid eth type");
1206 }
1207
1208 return STATUS_SUCCESS;
1209}
c803536e
SS
1210
1211/*
1212 * --------------------------------------------------------------------------
1213 * FixSegmentHeader
1214 *
1215 * Fix IP length, IP checksum, TCP sequence number and TCP checksum
1216 * in the segment.
1217 * --------------------------------------------------------------------------
1218 */
1219static NDIS_STATUS
89d762f3
AS
1220FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
1221 BOOLEAN lastPacket, UINT16 packetCounter)
c803536e 1222{
884d541f
SV
1223 EthHdr *dstEth = NULL;
1224 TCPHdr *dstTCP = NULL;
1225 PMDL mdl = NULL;
1226 PUINT8 bufferStart = NULL;
c803536e
SS
1227
1228 mdl = NET_BUFFER_FIRST_MDL(nb);
1229
cba5d148 1230 bufferStart = (PUINT8)OvsGetMdlWithLowPriority(mdl);
c803536e
SS
1231 if (!bufferStart) {
1232 return NDIS_STATUS_RESOURCES;
1233 }
1234 dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb));
89d762f3 1235
884d541f
SV
1236 switch (dstEth->Type) {
1237 case ETH_TYPE_IPV4_NBO:
1238 {
1239 IPHdr *dstIP = NULL;
1240
1241 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1242 >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr));
1243 dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth));
1244 dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4);
1245 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1246 >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
1247
1248 /* Fix IP length and checksum */
1249 ASSERT(dstIP->protocol == IPPROTO_TCP);
1250 dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
1251 dstIP->id += packetCounter;
1252 dstIP->check = 0;
1253 dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);
1254 dstTCP->seq = htonl(seqNumber);
1255
1256 /*
1257 * Set the TCP FIN and PSH bit only for the last packet
1258 * More information can be found under:
1259 * https://msdn.microsoft.com/en-us/library/windows/hardware/ff568840%28v=vs.85%29.aspx
1260 */
1261 if (dstTCP->fin) {
1262 dstTCP->fin = lastPacket;
1263 }
1264 if (dstTCP->psh) {
1265 dstTCP->psh = lastPacket;
1266 }
1267 UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP);
1268 dstTCP->check = IPPseudoChecksum(&dstIP->saddr,
1269 &dstIP->daddr,
1270 IPPROTO_TCP,
1271 csumLength);
1272 dstTCP->check = CalculateChecksumNB(nb,
1273 csumLength,
1274 sizeof(*dstEth) + dstIP->ihl * 4);
1275 break;
89d762f3 1276 }
884d541f
SV
1277 case ETH_TYPE_IPV6_NBO:
1278 {
1279 IPv6Hdr *dstIP = NULL;
1280
1281 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1282 >= sizeof(EthHdr) + sizeof(IPv6Hdr) + sizeof(TCPHdr));
1283 dstIP = (IPv6Hdr *)((PCHAR)dstEth + sizeof(*dstEth));
1284 dstTCP = (TCPHdr *)((PCHAR)dstIP + sizeof(IPv6Hdr));
1285 ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
1286 >= sizeof(EthHdr) + sizeof(IPv6Hdr) + TCP_HDR_LEN(dstTCP));
1287
1288 /* Fix IP length */
1289 ASSERT(dstIP->nexthdr == IPPROTO_TCP);
1290 dstIP->payload_len = htons(segmentSize + sizeof(IPv6Hdr) + TCP_HDR_LEN(dstTCP));
1291
1292 dstTCP->seq = htonl(seqNumber);
1293 if (dstTCP->fin) {
1294 dstTCP->fin = lastPacket;
1295 }
1296 if (dstTCP->psh) {
1297 dstTCP->psh = lastPacket;
1298 }
89d762f3 1299
884d541f
SV
1300 UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP);
1301 dstTCP->check = IPv6PseudoChecksum((UINT32*)&dstIP->saddr,
1302 (UINT32*)&dstIP->daddr,
1303 IPPROTO_TCP,
1304 csumLength);
1305 dstTCP->check = CalculateChecksumNB(nb,
1306 csumLength,
1307 sizeof(*dstEth) + sizeof(IPv6Hdr));
1308 break;
1309 }
1310 default:
1311 OVS_LOG_ERROR("Invalid eth type: %d\n", dstEth->Type);
1312 ASSERT(! "Invalid eth type");
1313 }
89d762f3 1314
c803536e
SS
1315 return STATUS_SUCCESS;
1316}
ac8df9f6
AK
1317 /*
1318 * --------------------------------------------------------------------------
1319 * OvsTcpSegmentNBL --
1320 * Wrapper function to Fragment a given NBL based on MSS
1321 * --------------------------------------------------------------------------
1322 */
1323PNET_BUFFER_LIST
1324OvsTcpSegmentNBL(PVOID ovsContext,
1325 PNET_BUFFER_LIST nbl,
1326 POVS_PACKET_HDR_INFO hdrInfo,
1327 UINT32 mss,
1328 UINT32 headRoom,
1329 BOOLEAN isIpFragment)
1330{
1331 return OvsFragmentNBL(ovsContext, nbl, hdrInfo, mss, headRoom, isIpFragment);
1332}
1333
c803536e
SS
1334
1335/*
1336 * --------------------------------------------------------------------------
ac8df9f6 1337 * OvsFragmentNBL --
c803536e 1338 *
ac8df9f6 1339 * Fragment NBL payload, and prepend each segment with Ether/IP/TCP header.
c803536e
SS
1340 * Leave headRoom for additional encap.
1341 *
1342 * Please note,
1343 * NBL should have OVS_BUFFER_CONTEXT setup before calling
1344 * this function.
1345 * The NBL should already have ref to itself so that during copy
1346 * it will not be freed.
1347 * Currently this API assert there is only one NB in an NBL, it needs
1348 * to be fixed if we receive multiple NBs in an NBL.
1349 * --------------------------------------------------------------------------
1350 */
1351PNET_BUFFER_LIST
ac8df9f6
AK
1352OvsFragmentNBL(PVOID ovsContext,
1353 PNET_BUFFER_LIST nbl,
1354 POVS_PACKET_HDR_INFO hdrInfo,
1355 UINT32 fragmentSize,
1356 UINT32 headRoom,
1357 BOOLEAN isIpFragment)
c803536e
SS
1358{
1359 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
1360#ifdef DBG
1361 POVS_NBL_POOL ovsPool = &context->ovsPool;
1362#endif
1363 POVS_BUFFER_CONTEXT dstCtx, srcCtx;
ac8df9f6 1364 UINT32 size, hdrSize, nblSize, seqNumber = 0;
c803536e
SS
1365 PNET_BUFFER_LIST newNbl;
1366 PNET_BUFFER nb, newNb;
1367 NDIS_STATUS status;
1368 UINT16 segmentSize;
1369 ULONG copiedSize;
ac8df9f6 1370 UINT16 offset = 0, packetCounter = 0;
c803536e
SS
1371
1372 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1373 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
1374 OVS_LOG_INFO("src nbl must have ctx initialized");
1375 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
1376 return NULL;
1377 }
1378
1379 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1380 ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL);
1381
ac8df9f6
AK
1382 /* Figure out the header size */
1383 if (isIpFragment) {
202b8137 1384 status = GetIpHeaderInfo(nbl, hdrInfo, &hdrSize);
ac8df9f6
AK
1385 } else {
1386 status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber);
1387 }
c803536e
SS
1388 if (status != NDIS_STATUS_SUCCESS) {
1389 OVS_LOG_INFO("Cannot parse NBL header");
1390 return NULL;
1391 }
ac8df9f6
AK
1392 /* Get the NBL size. */
1393 if (isIpFragment) {
1394 nblSize = fragmentSize - hdrSize;
1395 } else {
1396 nblSize = fragmentSize;
1397 }
c803536e
SS
1398 size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize;
1399
1400 /* XXX add to ovsPool counters? */
ac8df9f6
AK
1401 newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL, NULL, hdrSize,
1402 nblSize, hdrSize + headRoom ,
1403 0, 0);
c803536e
SS
1404 if (newNbl == NULL) {
1405 return NULL;
1406 }
1407
1408 /* Now deal with TCP payload */
1409 for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL;
1410 newNb = NET_BUFFER_NEXT_NB(newNb)) {
ac8df9f6 1411 segmentSize = (size > nblSize ? nblSize : size) & 0xffff;
c803536e
SS
1412 if (headRoom) {
1413 NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL);
1414 }
1415
1416 /* Now copy the eth/IP/TCP header and fix up */
1417 status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize, nb, 0,
1418 &copiedSize);
1419 if (status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize) {
1420 goto nblcopy_error;
1421 }
1422
ac8df9f6
AK
1423 if (isIpFragment) {
1424 status = FixFragmentHeader(newNb, segmentSize,
1425 NET_BUFFER_NEXT_NB(newNb) == NULL,
1426 offset);
1427 } else {
1428 status = FixSegmentHeader(newNb, segmentSize, seqNumber,
1429 NET_BUFFER_NEXT_NB(newNb) == NULL,
1430 packetCounter);
1431 }
1432
c803536e
SS
1433 if (status != NDIS_STATUS_SUCCESS) {
1434 goto nblcopy_error;
1435 }
1436
c803536e 1437 /* Move on to the next segment */
ac8df9f6
AK
1438 if (isIpFragment) {
1439 offset += (segmentSize) / 8;
1440 } else {
1441 seqNumber += segmentSize;
1442 }
c803536e 1443 size -= segmentSize;
89d762f3 1444 packetCounter++;
c803536e
SS
1445 }
1446
1447 status = OvsAllocateNBLContext(context, newNbl);
1448 if (status != NDIS_STATUS_SUCCESS) {
1449 goto nblcopy_error;
1450 }
1451
1452 status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, hdrSize + headRoom, FALSE);
1453 if (status != NDIS_STATUS_SUCCESS) {
1454 goto nbl_context_error;
1455 }
1456
ac8df9f6
AK
1457 if (isIpFragment) {
1458 /*Copy with Flag - NDIS_SWITCH_COPY_NBL_INFO_FLAGS_PRESERVE_DESTINATIONS.*/
1459 status = context->NdisSwitchHandlers.
1460 CopyNetBufferListInfo(context->ovsPool.ndisContext, newNbl, nbl, 1);
1461
1462 if (status != NDIS_STATUS_SUCCESS) {
1463 goto nbl_context_error;
1464 }
1465 }
c803536e
SS
1466 newNbl->ParentNetBufferList = nbl;
1467
1468 /* Remember it's a fragment NBL so we can free it properly */
1469 dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
1470 ASSERT(dstCtx != NULL);
1471 dstCtx->flags = OVS_BUFFER_FRAGMENT | OVS_BUFFER_PRIVATE_CONTEXT |
1472 OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | OVS_BUFFER_SEND_BUFFER;
1473 dstCtx->refCount = 1;
1474 dstCtx->magic = OVS_CTX_MAGIC;
1475 dstCtx->dataOffsetDelta = hdrSize + headRoom;
ac8df9f6 1476 dstCtx->mru = 0;
c803536e
SS
1477
1478 InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
1479#ifdef DBG
1480 InterlockedIncrement((LONG volatile *)&ovsPool->fragNBLCount);
1481
1482 OvsDumpNetBufferList(nbl);
1483 OvsDumpForwardingDetails(nbl);
1484
1485 OvsDumpNetBufferList(newNbl);
1486 OvsDumpForwardingDetails(newNbl);
1487#endif
ac8df9f6 1488 OVS_LOG_TRACE("Fragment nbl %p to newNbl: %p", nbl, newNbl);
c803536e
SS
1489 return newNbl;
1490
1491nbl_context_error:
1492 OvsFreeNBLContext(context, newNbl);
1493nblcopy_error:
1494#ifdef DBG
1495 InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
1496#endif
1497 NdisFreeFragmentNetBufferList(newNbl, hdrSize + headRoom, 0);
1498 return NULL;
1499}
1500
9a80ee14
SV
1501/*
1502 * --------------------------------------------------------------------------
1503 * OvsAllocateNBLFromBuffer --
1504 *
1505 * This function allocates all the stuff necessary for creating an NBL from the
1506 * input buffer of specified length, namely, a nonpaged data buffer of size
1507 * length, an MDL from it, and a NB and NBL from it. It does not allocate an NBL
1508 * context yet. It also copies data from the specified buffer to the NBL.
1509 * --------------------------------------------------------------------------
1510 */
1511PNET_BUFFER_LIST
1512OvsAllocateNBLFromBuffer(PVOID context,
1513 PVOID buffer,
1514 ULONG length)
1515{
1516 POVS_SWITCH_CONTEXT switchContext = (POVS_SWITCH_CONTEXT)context;
1517 UINT8 *data = NULL;
1518 PNET_BUFFER_LIST nbl = NULL;
1519 PNET_BUFFER nb;
1520 PMDL mdl;
1521
1522 if (length > OVS_DEFAULT_DATA_SIZE) {
1523 nbl = OvsAllocateVariableSizeNBL(switchContext, length,
1524 OVS_DEFAULT_HEADROOM_SIZE);
1525
1526 } else {
1527 nbl = OvsAllocateFixSizeNBL(switchContext, length,
1528 OVS_DEFAULT_HEADROOM_SIZE);
1529 }
1530 if (nbl == NULL) {
1531 return NULL;
1532 }
1533
1534 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1535 mdl = NET_BUFFER_CURRENT_MDL(nb);
cba5d148
AS
1536 data = (PUINT8)OvsGetMdlWithLowPriority(mdl)
1537 + NET_BUFFER_CURRENT_MDL_OFFSET(nb);
9a80ee14
SV
1538 if (!data) {
1539 OvsCompleteNBL(switchContext, nbl, TRUE);
1540 return NULL;
1541 }
1542
1543 NdisMoveMemory(data, buffer, length);
1544
1545 return nbl;
1546}
c803536e
SS
1547
1548/*
1549 * --------------------------------------------------------------------------
1550 * OvsFullCopyToMultipleNBLs --
1551 *
1552 * Copy NBL to multiple NBLs, each NB will have its own NBL
1553 * --------------------------------------------------------------------------
1554 */
1555PNET_BUFFER_LIST
1556OvsFullCopyToMultipleNBLs(PVOID ovsContext,
1557 PNET_BUFFER_LIST nbl,
1558 UINT32 headRoom,
1559 BOOLEAN copyNblInfo)
1560{
1561
1562 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
1563 PNET_BUFFER_LIST firstNbl, currNbl, newNbl;
1564 PNET_BUFFER nb;
1565 POVS_BUFFER_CONTEXT srcCtx;
1566
1567 srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1568 if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
1569 OVS_LOG_INFO("src nbl must have ctx initialized");
1570 ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
1571 return NULL;
1572 }
1573
1574 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1575 newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
1576
1577 if (newNbl == NULL || NET_BUFFER_NEXT_NB(nb) == NULL) {
1578 return newNbl;
1579 } else {
1580 firstNbl = newNbl;
1581 currNbl = newNbl;
1582 }
1583
1584 while (nb) {
1585 newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom,
1586 copyNblInfo);
1587 if (newNbl == NULL) {
1588 goto copymultiple_error;
1589 }
1590 NET_BUFFER_LIST_NEXT_NBL(currNbl) = newNbl;
1591 currNbl = newNbl;
1592 nb = NET_BUFFER_NEXT_NB(nb);
1593 }
1594 return firstNbl;
1595
1596copymultiple_error:
1597 while (firstNbl) {
1598 currNbl = firstNbl;
1599 firstNbl = NET_BUFFER_LIST_NEXT_NBL(firstNbl);
1600 NET_BUFFER_LIST_NEXT_NBL(currNbl) = NULL;
1601 OvsCompleteNBL(context, currNbl, TRUE);
1602 }
1603 return NULL;
1604
1605}
1606
1607
1608/*
1609 * --------------------------------------------------------------------------
1610 * OvsCompleteNBL --
1611 *
1612 * This function tries to free the NBL allocated by OVS buffer
1613 * management module. If it trigger the completion of the parent
1614 * NBL, it will recursively call itself. If it trigger the completion
1615 * of external NBL, it will be returned to the caller. The caller
1616 * is responsible to call API to return to upper layer.
1617 * --------------------------------------------------------------------------
1618 */
1619PNET_BUFFER_LIST
8ce087fd 1620OvsCompleteNBL(PVOID switch_ctx,
c803536e
SS
1621 PNET_BUFFER_LIST nbl,
1622 BOOLEAN updateRef)
1623{
1624 POVS_BUFFER_CONTEXT ctx;
1625 UINT16 flags;
308a079e 1626 UINT32 dataOffsetDelta;
c803536e
SS
1627 PNET_BUFFER_LIST parent;
1628 NDIS_STATUS status;
1629 NDIS_HANDLE poolHandle;
1630 LONG value;
8ce087fd 1631 POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)switch_ctx;
c803536e
SS
1632 POVS_NBL_POOL ovsPool = &context->ovsPool;
1633 PNET_BUFFER nb;
1634
1635
1636 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1637
1638 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1639
1640 OVS_LOG_TRACE("Enter: nbl: %p, ctx: %p, refCount: %d, updateRef:%d",
1641 nbl, ctx, ctx->refCount, updateRef);
1642
1643 if (updateRef) {
1644 value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
1645 if (value != 0) {
1646 return NULL;
1647 }
1648 } else {
1649 /*
1650 * This is a special case, the refCount must be zero
1651 */
1652 ASSERT(ctx->refCount == 0);
1653 }
1654
1655 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
1656
1657 flags = ctx->flags;
308a079e 1658 dataOffsetDelta = ctx->dataOffsetDelta;
c803536e
SS
1659 if (!(flags & OVS_BUFFER_FRAGMENT) &&
1660 NET_BUFFER_DATA_LENGTH(nb) != ctx->origDataLength) {
1661 UINT32 diff;
1662 if (NET_BUFFER_DATA_LENGTH(nb) < ctx->origDataLength) {
1663 diff = ctx->origDataLength -NET_BUFFER_DATA_LENGTH(nb);
1664 status = NdisRetreatNetBufferListDataStart(nbl, diff, 0,
1665 NULL, NULL);
1666 ASSERT(status == NDIS_STATUS_SUCCESS);
1667 } else {
1668 diff = NET_BUFFER_DATA_LENGTH(nb) - ctx->origDataLength;
1669 NdisAdvanceNetBufferListDataStart(nbl, diff, TRUE, NULL);
1670 }
1671 }
1672
308a079e 1673 if (flags & OVS_BUFFER_PRIVATE_CONTEXT) {
c803536e
SS
1674 NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
1675 }
1676
1677 if (flags & OVS_BUFFER_NEED_COMPLETE) {
1678 /*
1679 * return to caller for completion
1680 */
1681#ifdef DBG
1682 InterlockedDecrement((LONG volatile *)&ovsPool->sysNBLCount);
1683#endif
1684 return nbl;
1685 }
1686
1687 if (flags & OVS_BUFFER_PRIVATE_FORWARD_CONTEXT) {
1688 context->NdisSwitchHandlers.
1689 FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
1690 }
1691
1692 if (flags & (OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA)) {
bf71b09b
SV
1693 PNET_BUFFER nbTemp = NET_BUFFER_LIST_FIRST_NB(nbl);
1694 while (nbTemp) {
1695 PMDL mdl = NET_BUFFER_FIRST_MDL(nbTemp);
5a3cb514
AS
1696 if (mdl) {
1697 ASSERT(mdl->Next == NULL);
1698 OvsFreeMDLAndData(mdl);
1699 }
bf71b09b 1700 NET_BUFFER_FIRST_MDL(nbTemp) = NULL;
bf71b09b 1701 nbTemp = NET_BUFFER_NEXT_NB(nbTemp);
c803536e
SS
1702 }
1703 }
1704
1705 if (flags & OVS_BUFFER_PRIVATE_NET_BUFFER) {
bf71b09b 1706 PNET_BUFFER nbTemp, nextNb;
c803536e 1707
bf71b09b
SV
1708 nbTemp = NET_BUFFER_LIST_FIRST_NB(nbl);
1709 while (nbTemp) {
1710 nextNb = NET_BUFFER_NEXT_NB(nbTemp);
1711 NdisFreeNetBuffer(nbTemp);
c803536e
SS
1712#ifdef DBG
1713 InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
1714#endif
bf71b09b 1715 nbTemp = nextNb;
c803536e
SS
1716 }
1717 NET_BUFFER_LIST_FIRST_NB(nbl) = NULL;
1718 }
1719
1720 parent = nbl->ParentNetBufferList;
1721
1722 poolHandle = NdisGetPoolFromNetBufferList(nbl);
1723 if (flags & OVS_BUFFER_FROM_FIX_SIZE_POOL) {
1724 ASSERT(poolHandle == ovsPool->fixSizePool);
1725#ifdef DBG
1726 InterlockedDecrement((LONG volatile *)&ovsPool->fixNBLCount);
1727#endif
1728 NdisFreeNetBufferList(nbl);
1729 } else if (flags & OVS_BUFFER_FROM_ZERO_SIZE_POOL) {
1730 ASSERT(poolHandle == ovsPool->zeroSizePool);
1731#ifdef DBG
1732 InterlockedDecrement((LONG volatile *)&ovsPool->zeroNBLCount);
1733#endif
1734 NdisFreeNetBufferList(nbl);
1735 } else if (flags & OVS_BUFFER_FROM_NBL_ONLY_POOL) {
1736 ASSERT(poolHandle == ovsPool->nblOnlyPool);
1737#ifdef DBG
1738 InterlockedDecrement((LONG volatile *)&ovsPool->nblOnlyCount);
1739#endif
1740 NdisFreeCloneNetBufferList(nbl, 0);
1741 } else if (flags & OVS_BUFFER_FRAGMENT) {
1742 OVS_LOG_TRACE("Free fragment %p parent %p", nbl, parent);
1743#ifdef DBG
1744 InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
1745#endif
308a079e 1746 NdisFreeFragmentNetBufferList(nbl, dataOffsetDelta, 0);
c803536e
SS
1747 }
1748
1749 if (parent != NULL) {
1750 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(parent);
1751 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
5406e557 1752 UINT16 pendingSend = 1, exchange = 0;
c803536e 1753 value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
5406e557
AK
1754 InterlockedCompareExchange16((SHORT volatile *)&pendingSend, exchange, (SHORT)ctx->pendingSend);
1755 if (value == 1 && pendingSend == exchange) {
1756 InterlockedExchange16((SHORT volatile *)&ctx->pendingSend, 0);
1757 OvsSendNBLIngress(context, parent, ctx->sendFlags);
1758 } else if (value == 0){
c803536e
SS
1759 return OvsCompleteNBL(context, parent, FALSE);
1760 }
1761 }
1762 return NULL;
1763}
1764
1765/*
1766 * --------------------------------------------------------------------------
1767 * OvsSetCtxSourcePortNo --
1768 * Setter function which stores the source port of an NBL in the NBL
1769 * Context Info.
1770 * --------------------------------------------------------------------------
1771 */
1772NDIS_STATUS
1773OvsSetCtxSourcePortNo(PNET_BUFFER_LIST nbl,
1774 UINT32 portNo)
1775{
1776 POVS_BUFFER_CONTEXT ctx;
1777 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1778 if (ctx == NULL) {
1779 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1780 return STATUS_INVALID_PARAMETER;
1781 }
1782
1783 ctx->srcPortNo = portNo;
1784 return NDIS_STATUS_SUCCESS;
1785}
1786
1787/*
1788 * --------------------------------------------------------------------------
1789 * OvsGetCtxSourcePortNo --
1790 * Get source port of an NBL from its Context Info.
1791 * --------------------------------------------------------------------------
1792 */
1793NDIS_STATUS
1794OvsGetCtxSourcePortNo(PNET_BUFFER_LIST nbl,
1795 UINT32 *portNo)
1796{
1797 POVS_BUFFER_CONTEXT ctx;
1798 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1799 if (ctx == NULL || portNo == NULL) {
1800 ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
1801 return STATUS_INVALID_PARAMETER;
1802 }
1803 *portNo = ctx->srcPortNo;
1804 return NDIS_STATUS_SUCCESS;
1805}
bf4077e2
SR
1806
1807/*
1808 * --------------------------------------------------------------------------
1809 * OvsCreateNewNBLsFromMultipleNBs --
1810 * Creates an NBL chain where each NBL has a single NB,
1811 * from an NBL which has multiple NBs.
1812 * Sets 'curNbl' and 'lastNbl' to the first and last NBL in the
1813 * newly created NBL chain respectively, and completes the original NBL.
1814 * --------------------------------------------------------------------------
1815 */
1816NTSTATUS
1817OvsCreateNewNBLsFromMultipleNBs(POVS_SWITCH_CONTEXT switchContext,
1818 PNET_BUFFER_LIST *curNbl,
1819 PNET_BUFFER_LIST *lastNbl)
1820{
1821 NTSTATUS status = STATUS_SUCCESS;
1822 PNET_BUFFER_LIST newNbls = NULL;
1823 PNET_BUFFER_LIST nbl = NULL;
1824 BOOLEAN error = TRUE;
1825
1826 do {
1827 /* Create new NBLs from curNbl with multiple net buffers. */
1828 newNbls = OvsPartialCopyToMultipleNBLs(switchContext,
1829 *curNbl, 0, 0, TRUE);
1830 if (NULL == newNbls) {
1831 OVS_LOG_ERROR("Failed to allocate NBLs with single NB.");
1832 status = NDIS_STATUS_RESOURCES;
1833 break;
1834 }
1835
1836 nbl = newNbls;
1837 while (nbl) {
1838 *lastNbl = nbl;
1839 nbl = NET_BUFFER_LIST_NEXT_NBL(nbl);
1840 }
1841
1842 (*curNbl)->Next = NULL;
1843
1844 OvsCompleteNBL(switchContext, *curNbl, TRUE);
1845
1846 *curNbl = newNbls;
1847
1848 error = FALSE;
1849 } while (error);
1850
1851 return status;
1852}