datapath-windows/ovsext/BufferMgmt.c
/*
 * --------------------------------------------------------------------------
 * OvsPartialCopyNBL --
 *
 *    Partial copy NBL, if there is multiple NB in NBL, each one will be
 *    copied. We also reserve headroom for the new NBL.
 *
 *    Please note,
 *       NBL should have OVS_BUFFER_CONTEXT setup before calling
 *       this function.
 *       The NBL should already have ref to itself so that during copy
 *       it will not be freed.
 * --------------------------------------------------------------------------
 */


Partial copy NBL, if there is multiple NB in NBL, each one will be
copied. We also reserve headroom for the new NBL.

Please note,
NBL should have OVS_BUFFER_CONTEXT setup before calling
this function.
The NBL should already have ref to itself so that during copy
it will not be freed.
Partial copy NBL if there is multiple NB in NBL each one will be copied . We also reserve headroom for the new NBL . Please note NBL should have OVS_BUFFER_CONTEXT setup before calling this function . The NBL should already have ref to itself so that during copy it will not be freed .
PNET_BUFFER_LIST
OvsPartialCopyNBL(PVOID ovsContext,
                  PNET_BUFFER_LIST nbl,
                  UINT32 copySize,
                  UINT32 headRoom,
                  BOOLEAN copyNblInfo)
{
    PNET_BUFFER_LIST newNbl;
    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
    NDIS_STATUS status;
    PNET_BUFFER srcNb, dstNb;
    ULONG byteCopied;
    POVS_NBL_POOL ovsPool = &context->ovsPool;
    POVS_BUFFER_CONTEXT srcCtx, dstCtx;
    UINT16 flags;
    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;
    }
    if (copySize) {
        NdisAdvanceNetBufferListDataStart(nbl, copySize, FALSE, NULL);
    }
    newNbl = NdisAllocateCloneNetBufferList(nbl, ovsPool->nblOnlyPool,
                                            NULL, 0);
    if (copySize) {
        status = NdisRetreatNetBufferListDataStart(nbl, copySize, 0,
                                                   NULL, NULL);
        ASSERT(status == NDIS_STATUS_SUCCESS);
    }
    if (newNbl == NULL) {
        return NULL;
    }
    if (copySize + headRoom) {
        status = NdisRetreatNetBufferListDataStart(newNbl, copySize + headRoom,
                                                   0, NULL, NULL);
        if (status != NDIS_STATUS_SUCCESS) {
            goto retreat_error;
        }
        if (headRoom) {
            NdisAdvanceNetBufferListDataStart(newNbl, headRoom, FALSE, NULL);
        }
        if (copySize) {
            srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
            dstNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
            while (srcNb) {
                status = NdisCopyFromNetBufferToNetBuffer(dstNb, 0, copySize,
                                                          srcNb, 0,
                                                          &byteCopied);
                if (status != NDIS_STATUS_SUCCESS || copySize != byteCopied) {
                    goto nbl_context_error;
                }
                srcNb = NET_BUFFER_NEXT_NB(srcNb);
                dstNb = NET_BUFFER_NEXT_NB(dstNb);
            }
        }
    }
    status = OvsAllocateNBLContext(context, newNbl);
    if (status != NDIS_STATUS_SUCCESS) {
        goto nbl_context_error;
    }
    status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copySize, copyNblInfo);
    if (status != NDIS_STATUS_SUCCESS) {
        goto copy_list_info_error;
    }
#ifdef DBG
    InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
#endif
    newNbl->ParentNetBufferList = nbl;
    dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
    ASSERT(dstCtx != NULL);
    flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);
    flags |= OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_CONTEXT |
             OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;
    srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
    ASSERT(srcNb);
    OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(srcNb) - copySize,
                      OVS_DPPORT_NUMBER_INVALID, srcCtx->mru);
    InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
#ifdef DBG
    OvsDumpNetBufferList(nbl);
    OvsDumpForwardingDetails(nbl);
    OvsDumpNetBufferList(newNbl);
    OvsDumpForwardingDetails(newNbl);
#endif
    OVS_LOG_LOUD("Partial Copy new NBL: %p", newNbl);
    return newNbl;
copy_list_info_error:
    OvsFreeNBLContext(context, newNbl);
nbl_context_error:
    if (copySize) {
        NdisAdvanceNetBufferListDataStart(newNbl, copySize, TRUE, NULL);
    }
retreat_error:
    NdisFreeCloneNetBufferList(newNbl, 0);
    return NULL;
}
PNET_BUFFER_LIST OvsPartialCopyNBL ( PVOID ovsContext , PNET_BUFFER_LIST nbl , UINT32 copySize , UINT32 headRoom , BOOLEAN copyNblInfo ) { PNET_BUFFER_LIST newNbl ; POVS_SWITCH_CONTEXT context = ( POVS_SWITCH_CONTEXT ) ovsContext ; NDIS_STATUS status ; PNET_BUFFER srcNb , dstNb ; ULONG byteCopied ; POVS_NBL_POOL ovsPool = & context -> ovsPool ; POVS_BUFFER_CONTEXT srcCtx , dstCtx ; UINT16 flags ; 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 ; } if ( copySize ) { NdisAdvanceNetBufferListDataStart ( nbl , copySize , FALSE , NULL ) ; } newNbl = NdisAllocateCloneNetBufferList ( nbl , ovsPool -> nblOnlyPool , NULL , 0 ) ; if ( copySize ) { status = NdisRetreatNetBufferListDataStart ( nbl , copySize , 0 , NULL , NULL ) ; ASSERT ( status == NDIS_STATUS_SUCCESS ) ; } if ( newNbl == NULL ) { return NULL ; } if ( copySize + headRoom ) { status = NdisRetreatNetBufferListDataStart ( newNbl , copySize + headRoom , 0 , NULL , NULL ) ; if ( status != NDIS_STATUS_SUCCESS ) { goto retreat_error ; } if ( headRoom ) { NdisAdvanceNetBufferListDataStart ( newNbl , headRoom , FALSE , NULL ) ; } if ( copySize ) { srcNb = NET_BUFFER_LIST_FIRST_NB ( nbl ) ; dstNb = NET_BUFFER_LIST_FIRST_NB ( newNbl ) ; while ( srcNb ) { status = NdisCopyFromNetBufferToNetBuffer ( dstNb , 0 , copySize , srcNb , 0 , & byteCopied ) ; if ( status != NDIS_STATUS_SUCCESS || copySize != byteCopied ) { goto nbl_context_error ; } srcNb = NET_BUFFER_NEXT_NB ( srcNb ) ; dstNb = NET_BUFFER_NEXT_NB ( dstNb ) ; } } } status = OvsAllocateNBLContext ( context , newNbl ) ; if ( status != NDIS_STATUS_SUCCESS ) { goto nbl_context_error ; } status = OvsCopyNBLInfo ( nbl , newNbl , srcCtx , copySize , copyNblInfo ) ; if ( status != NDIS_STATUS_SUCCESS ) { goto copy_list_info_error ; } #ifdef DBG InterlockedIncrement ( ( LONG volatile * ) & ovsPool -> nblOnlyCount ) ; #endif newNbl -> ParentNetBufferList = nbl ; dstCtx = ( POVS_BUFFER_CONTEXT ) NET_BUFFER_LIST_CONTEXT_DATA_START ( newNbl ) ; ASSERT ( dstCtx != NULL ) ; flags = srcCtx -> flags & ( OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER ) ; flags |= OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_CONTEXT | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT ; srcNb = NET_BUFFER_LIST_FIRST_NB ( nbl ) ; ASSERT ( srcNb ) ; OvsInitNBLContext ( dstCtx , flags , NET_BUFFER_DATA_LENGTH ( srcNb ) - copySize , OVS_DPPORT_NUMBER_INVALID , srcCtx -> mru ) ; InterlockedIncrement ( ( LONG volatile * ) & srcCtx -> refCount ) ; #ifdef DBG OvsDumpNetBufferList ( nbl ) ; OvsDumpForwardingDetails ( nbl ) ; OvsDumpNetBufferList ( newNbl ) ; OvsDumpForwardingDetails ( newNbl ) ; #endif OVS_LOG_LOUD ( " " , newNbl ) ; return newNbl ; copy_list_info_error : OvsFreeNBLContext ( context , newNbl ) ; nbl_context_error : if ( copySize ) { NdisAdvanceNetBufferListDataStart ( newNbl , copySize , TRUE , NULL ) ; } retreat_error : NdisFreeCloneNetBufferList ( newNbl , 0 ) ; return NULL ; }
OvsPartialCopyNBL
OvsPartialCopyNBL
/*
     * Allocate private memory for copy
     */