datapath-windows/ovsext/BufferMgmt.c
/*
 * --------------------------------------------------------------------------
 * OvsFullCopyNBL --
 *
 *    Copy the NBL to a new NBL including data.
 *
 * Notes:
 *     The NBL can have multiple NBs, but the final result is one NBL.
 * --------------------------------------------------------------------------
 */


Copy the NBL to a new NBL including data.

The NBL can have multiple NBs, but the final result is one NBL.
Copy the NBL to a new NBL including data . The NBL can have multiple NBs but the final result is one NBL .
PNET_BUFFER_LIST
OvsFullCopyNBL(PVOID ovsContext,
               PNET_BUFFER_LIST nbl,
               UINT32 headRoom,
               BOOLEAN copyNblInfo)
{
    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
    POVS_NBL_POOL ovsPool = &context->ovsPool;
    PNET_BUFFER_LIST newNbl;
    PNET_BUFFER nb, newNb, firstNb = NULL, prevNb = NULL;
    POVS_BUFFER_CONTEXT dstCtx, srcCtx;
    PMDL mdl;
    NDIS_STATUS status;
    UINT32 size, totalSize;
    ULONG copiedSize;
    UINT16 flags;
    PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo;
    srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
    if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
        OVS_LOG_INFO("src nbl must have ctx initialized");
        ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
        return NULL;
    }
    nb = NET_BUFFER_LIST_FIRST_NB(nbl);
    if (nb == NULL) {
        return NULL;
    }
    if (NET_BUFFER_NEXT_NB(nb) == NULL) {
        return OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
    }
    newNbl = NdisAllocateNetBufferList(ovsPool->nblOnlyPool,
                                       (UINT16)sizeof (OVS_BUFFER_CONTEXT),
                                       (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
    if (newNbl == NULL) {
        return NULL;
    }
    while (nb) {
        size = NET_BUFFER_DATA_LENGTH(nb);
        totalSize = MEM_ALIGN_SIZE(size + headRoom);
        mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, totalSize);
        if (mdl == NULL) {
            goto nblcopy_error;
        }
        newNb = NdisAllocateNetBuffer(ovsPool->nbPool, mdl, totalSize, 0);
        if (newNb == NULL) {
            OvsFreeMDLAndData(mdl);
            goto nblcopy_error;
        }
        if (firstNb == NULL) {
            firstNb = newNb;
        } else {
            NET_BUFFER_NEXT_NB(prevNb) = newNb;
        }
        prevNb = newNb;
#ifdef DBG
        InterlockedIncrement((LONG volatile *)&ovsPool->nbCount);
#endif
        status = NdisRetreatNetBufferDataStart(newNb, size, 0, NULL);
        ASSERT(status == NDIS_STATUS_SUCCESS);
        status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
                                                  &copiedSize);
        if (status != NDIS_STATUS_SUCCESS || size != copiedSize) {
            goto nblcopy_error;
        }
        nb = NET_BUFFER_NEXT_NB(nb);
    }
    NET_BUFFER_LIST_FIRST_NB(newNbl) = firstNb;
    newNbl->SourceHandle = ovsPool->ndisHandle;
    status = context->NdisSwitchHandlers.
         AllocateNetBufferListForwardingContext(ovsPool->ndisContext, newNbl);
    if (status != NDIS_STATUS_SUCCESS) {
        goto nblcopy_error;
    }
    status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, 0, copyNblInfo);
    if (status != NDIS_STATUS_SUCCESS) {
        goto nblcopy_error;
    }
    dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl);
    dstInfo->IsPacketDataSafe = TRUE;
    dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
    flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
    flags |= OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
             OVS_BUFFER_PRIVATE_NET_BUFFER | OVS_BUFFER_FROM_NBL_ONLY_POOL |
             OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;
    OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(firstNb),
                      OVS_DPPORT_NUMBER_INVALID, srcCtx->mru);
#ifdef DBG
    OvsDumpNetBufferList(nbl);
    OvsDumpForwardingDetails(nbl);
    InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
#endif
    OVS_LOG_LOUD("newNbl: %p", newNbl);
    return newNbl;
nblcopy_error:
    while (firstNb) {
#ifdef DBG
        InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
#endif
        prevNb = firstNb;
        firstNb = NET_BUFFER_NEXT_NB(prevNb);
        mdl = NET_BUFFER_FIRST_MDL(prevNb);
        NET_BUFFER_FIRST_MDL(prevNb) = NULL;
        NdisFreeNetBuffer(prevNb);
        OvsFreeMDLAndData(mdl);
    }
    NdisFreeNetBufferList(newNbl);
    OVS_LOG_ERROR("OvsFullCopyNBL failed");
    return NULL;
}
PNET_BUFFER_LIST OvsFullCopyNBL ( PVOID ovsContext , PNET_BUFFER_LIST nbl , UINT32 headRoom , BOOLEAN copyNblInfo ) { POVS_SWITCH_CONTEXT context = ( POVS_SWITCH_CONTEXT ) ovsContext ; POVS_NBL_POOL ovsPool = & context -> ovsPool ; PNET_BUFFER_LIST newNbl ; PNET_BUFFER nb , newNb , firstNb = NULL , prevNb = NULL ; POVS_BUFFER_CONTEXT dstCtx , srcCtx ; PMDL mdl ; NDIS_STATUS status ; UINT32 size , totalSize ; ULONG copiedSize ; UINT16 flags ; PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo ; srcCtx = ( POVS_BUFFER_CONTEXT ) NET_BUFFER_LIST_CONTEXT_DATA_START ( nbl ) ; if ( srcCtx == NULL || srcCtx -> magic != OVS_CTX_MAGIC ) { OVS_LOG_INFO ( " " ) ; ASSERT ( srcCtx && srcCtx -> magic == OVS_CTX_MAGIC ) ; return NULL ; } nb = NET_BUFFER_LIST_FIRST_NB ( nbl ) ; if ( nb == NULL ) { return NULL ; } if ( NET_BUFFER_NEXT_NB ( nb ) == NULL ) { return OvsCopySinglePacketNBL ( context , nbl , nb , headRoom , copyNblInfo ) ; } newNbl = NdisAllocateNetBufferList ( ovsPool -> nblOnlyPool , ( UINT16 ) sizeof ( OVS_BUFFER_CONTEXT ) , ( UINT16 ) OVS_DEFAULT_NBL_CONTEXT_FILL ) ; if ( newNbl == NULL ) { return NULL ; } while ( nb ) { size = NET_BUFFER_DATA_LENGTH ( nb ) ; totalSize = MEM_ALIGN_SIZE ( size + headRoom ) ; mdl = OvsAllocateMDLAndData ( ovsPool -> ndisHandle , totalSize ) ; if ( mdl == NULL ) { goto nblcopy_error ; } newNb = NdisAllocateNetBuffer ( ovsPool -> nbPool , mdl , totalSize , 0 ) ; if ( newNb == NULL ) { OvsFreeMDLAndData ( mdl ) ; goto nblcopy_error ; } if ( firstNb == NULL ) { firstNb = newNb ; } else { NET_BUFFER_NEXT_NB ( prevNb ) = newNb ; } prevNb = newNb ; #ifdef DBG InterlockedIncrement ( ( LONG volatile * ) & ovsPool -> nbCount ) ; #endif status = NdisRetreatNetBufferDataStart ( newNb , size , 0 , NULL ) ; ASSERT ( status == NDIS_STATUS_SUCCESS ) ; status = NdisCopyFromNetBufferToNetBuffer ( newNb , 0 , size , nb , 0 , & copiedSize ) ; if ( status != NDIS_STATUS_SUCCESS || size != copiedSize ) { goto nblcopy_error ; } nb = NET_BUFFER_NEXT_NB ( nb ) ; } NET_BUFFER_LIST_FIRST_NB ( newNbl ) = firstNb ; newNbl -> SourceHandle = ovsPool -> ndisHandle ; status = context -> NdisSwitchHandlers . AllocateNetBufferListForwardingContext ( ovsPool -> ndisContext , newNbl ) ; if ( status != NDIS_STATUS_SUCCESS ) { goto nblcopy_error ; } status = OvsCopyNBLInfo ( nbl , newNbl , srcCtx , 0 , copyNblInfo ) ; if ( status != NDIS_STATUS_SUCCESS ) { goto nblcopy_error ; } dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL ( newNbl ) ; dstInfo -> IsPacketDataSafe = TRUE ; dstCtx = ( POVS_BUFFER_CONTEXT ) NET_BUFFER_LIST_CONTEXT_DATA_START ( newNbl ) ; flags = srcCtx -> flags & ( OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER ) ; flags |= OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA | OVS_BUFFER_PRIVATE_NET_BUFFER | OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT ; OvsInitNBLContext ( dstCtx , flags , NET_BUFFER_DATA_LENGTH ( firstNb ) , OVS_DPPORT_NUMBER_INVALID , srcCtx -> mru ) ; #ifdef DBG OvsDumpNetBufferList ( nbl ) ; OvsDumpForwardingDetails ( nbl ) ; InterlockedIncrement ( ( LONG volatile * ) & ovsPool -> nblOnlyCount ) ; #endif OVS_LOG_LOUD ( " " , newNbl ) ; return newNbl ; nblcopy_error : while ( firstNb ) { #ifdef DBG InterlockedDecrement ( ( LONG volatile * ) & ovsPool -> nbCount ) ; #endif prevNb = firstNb ; firstNb = NET_BUFFER_NEXT_NB ( prevNb ) ; mdl = NET_BUFFER_FIRST_MDL ( prevNb ) ; NET_BUFFER_FIRST_MDL ( prevNb ) = NULL ; NdisFreeNetBuffer ( prevNb ) ; OvsFreeMDLAndData ( mdl ) ; } NdisFreeNetBufferList ( newNbl ) ; OVS_LOG_ERROR ( " " ) ; return NULL ; }
OvsFullCopyNBL
OvsFullCopyNBL