datapath-windows/ovsext/BufferMgmt.c
/*
 * --------------------------------------------------------------------------
 * OvsFragmentNBL --
 *
 *    Fragment NBL payload, and prepend each segment with Ether/IP/TCP header.
 *    Leave headRoom for additional encap.
 *
 *    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.
 *       Currently this API assert there is only one NB in an NBL, it needs
 *       to be fixed if we receive multiple NBs in an NBL.
 * --------------------------------------------------------------------------
 */


Fragment NBL payload, and prepend each segment with Ether/IP/TCP header.
Leave headRoom for additional encap.

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.
Currently this API assert there is only one NB in an NBL, it needs
to be fixed if we receive multiple NBs in an NBL.
Fragment NBL payload and prepend each segment with Ether / IP / TCP header . Leave headRoom for additional encap . 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 . Currently this API assert there is only one NB in an NBL it needs to be fixed if we receive multiple NBs in an NBL .
PNET_BUFFER_LIST
OvsFragmentNBL(PVOID ovsContext,
               PNET_BUFFER_LIST nbl,
               POVS_PACKET_HDR_INFO hdrInfo,
               UINT32 fragmentSize,
               UINT32 headRoom,
               BOOLEAN isIpFragment)
{
    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
#ifdef DBG
    POVS_NBL_POOL ovsPool = &context->ovsPool;
#endif
    POVS_BUFFER_CONTEXT dstCtx, srcCtx;
    UINT32 size, hdrSize, nblSize, seqNumber = 0;
    PNET_BUFFER_LIST newNbl;
    PNET_BUFFER nb, newNb;
    NDIS_STATUS status;
    UINT16 segmentSize;
    ULONG copiedSize;
    UINT16 offset = 0, packetCounter = 0;
    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);
    ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL);
    if (isIpFragment) {
        status = GetIpHeaderInfo(nbl, hdrInfo, &hdrSize);
    } else {
        status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber);
    }
    if (status != NDIS_STATUS_SUCCESS) {
        OVS_LOG_INFO("Cannot parse NBL header");
        return NULL;
    }
    if (isIpFragment) {
        nblSize = fragmentSize - hdrSize;
    } else {
        nblSize = fragmentSize;
    }
    size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize;
    newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL, NULL, hdrSize,
                                               nblSize, hdrSize + headRoom ,
                                               0, 0);
    if (newNbl == NULL) {
        return NULL;
    }
    for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL;
            newNb = NET_BUFFER_NEXT_NB(newNb)) {
        segmentSize = (size > nblSize ? nblSize : size) & 0xffff;
        if (headRoom) {
            NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL);
        }
        status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize, nb, 0,
                                                  &copiedSize);
        if (status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize) {
            goto nblcopy_error;
        }
        if (isIpFragment) {
            status = FixFragmentHeader(newNb, segmentSize,
                                       NET_BUFFER_NEXT_NB(newNb) == NULL,
                                       offset);
        } else {
            status = FixSegmentHeader(newNb, segmentSize, seqNumber,
                                      NET_BUFFER_NEXT_NB(newNb) == NULL,
                                      packetCounter);
        }
        if (status != NDIS_STATUS_SUCCESS) {
            goto nblcopy_error;
        }
        if (isIpFragment) {
            offset += (segmentSize) / 8;
        } else {
            seqNumber += segmentSize;
        }
        size -= segmentSize;
        packetCounter++;
    }
    status = OvsAllocateNBLContext(context, newNbl);
    if (status != NDIS_STATUS_SUCCESS) {
        goto nblcopy_error;
    }
    status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, hdrSize + headRoom, FALSE);
    if (status != NDIS_STATUS_SUCCESS) {
        goto nbl_context_error;
    }
    if (isIpFragment) {
        status = context->NdisSwitchHandlers.
            CopyNetBufferListInfo(context->ovsPool.ndisContext, newNbl, nbl, 1);
        if (status != NDIS_STATUS_SUCCESS) {
            goto nbl_context_error;
        }
    }
    newNbl->ParentNetBufferList = nbl;
    dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
    ASSERT(dstCtx != NULL);
    dstCtx->flags = OVS_BUFFER_FRAGMENT | OVS_BUFFER_PRIVATE_CONTEXT |
        OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | OVS_BUFFER_SEND_BUFFER;
    dstCtx->refCount = 1;
    dstCtx->magic = OVS_CTX_MAGIC;
    dstCtx->dataOffsetDelta = hdrSize + headRoom;
    dstCtx->mru = 0;
    InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
#ifdef DBG
    InterlockedIncrement((LONG volatile *)&ovsPool->fragNBLCount);
    OvsDumpNetBufferList(nbl);
    OvsDumpForwardingDetails(nbl);
    OvsDumpNetBufferList(newNbl);
    OvsDumpForwardingDetails(newNbl);
#endif
    OVS_LOG_TRACE("Fragment nbl %p to newNbl: %p", nbl, newNbl);
    return newNbl;
nbl_context_error:
    OvsFreeNBLContext(context, newNbl);
nblcopy_error:
#ifdef DBG
    InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
#endif
    NdisFreeFragmentNetBufferList(newNbl, hdrSize + headRoom, 0);
    return NULL;
}
PNET_BUFFER_LIST OvsFragmentNBL ( PVOID ovsContext , PNET_BUFFER_LIST nbl , POVS_PACKET_HDR_INFO hdrInfo , UINT32 fragmentSize , UINT32 headRoom , BOOLEAN isIpFragment ) { POVS_SWITCH_CONTEXT context = ( POVS_SWITCH_CONTEXT ) ovsContext ; #ifdef DBG POVS_NBL_POOL ovsPool = & context -> ovsPool ; #endif POVS_BUFFER_CONTEXT dstCtx , srcCtx ; UINT32 size , hdrSize , nblSize , seqNumber = 0 ; PNET_BUFFER_LIST newNbl ; PNET_BUFFER nb , newNb ; NDIS_STATUS status ; UINT16 segmentSize ; ULONG copiedSize ; UINT16 offset = 0 , packetCounter = 0 ; 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 ) ; ASSERT ( NET_BUFFER_NEXT_NB ( nb ) == NULL ) ; if ( isIpFragment ) { status = GetIpHeaderInfo ( nbl , hdrInfo , & hdrSize ) ; } else { status = GetSegmentHeaderInfo ( nbl , hdrInfo , & hdrSize , & seqNumber ) ; } if ( status != NDIS_STATUS_SUCCESS ) { OVS_LOG_INFO ( " " ) ; return NULL ; } if ( isIpFragment ) { nblSize = fragmentSize - hdrSize ; } else { nblSize = fragmentSize ; } size = NET_BUFFER_DATA_LENGTH ( nb ) - hdrSize ; newNbl = NdisAllocateFragmentNetBufferList ( nbl , NULL , NULL , hdrSize , nblSize , hdrSize + headRoom , 0 , 0 ) ; if ( newNbl == NULL ) { return NULL ; } for ( newNb = NET_BUFFER_LIST_FIRST_NB ( newNbl ) ; newNb != NULL ; newNb = NET_BUFFER_NEXT_NB ( newNb ) ) { segmentSize = ( size > nblSize ? nblSize : size ) & 0xffff ; if ( headRoom ) { NdisAdvanceNetBufferDataStart ( newNb , headRoom , FALSE , NULL ) ; } status = NdisCopyFromNetBufferToNetBuffer ( newNb , 0 , hdrSize , nb , 0 , & copiedSize ) ; if ( status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize ) { goto nblcopy_error ; } if ( isIpFragment ) { status = FixFragmentHeader ( newNb , segmentSize , NET_BUFFER_NEXT_NB ( newNb ) == NULL , offset ) ; } else { status = FixSegmentHeader ( newNb , segmentSize , seqNumber , NET_BUFFER_NEXT_NB ( newNb ) == NULL , packetCounter ) ; } if ( status != NDIS_STATUS_SUCCESS ) { goto nblcopy_error ; } if ( isIpFragment ) { offset += ( segmentSize ) / 8 ; } else { seqNumber += segmentSize ; } size -= segmentSize ; packetCounter ++ ; } status = OvsAllocateNBLContext ( context , newNbl ) ; if ( status != NDIS_STATUS_SUCCESS ) { goto nblcopy_error ; } status = OvsCopyNBLInfo ( nbl , newNbl , srcCtx , hdrSize + headRoom , FALSE ) ; if ( status != NDIS_STATUS_SUCCESS ) { goto nbl_context_error ; } if ( isIpFragment ) { status = context -> NdisSwitchHandlers . CopyNetBufferListInfo ( context -> ovsPool . ndisContext , newNbl , nbl , 1 ) ; if ( status != NDIS_STATUS_SUCCESS ) { goto nbl_context_error ; } } newNbl -> ParentNetBufferList = nbl ; dstCtx = ( POVS_BUFFER_CONTEXT ) NET_BUFFER_LIST_CONTEXT_DATA_START ( newNbl ) ; ASSERT ( dstCtx != NULL ) ; dstCtx -> flags = OVS_BUFFER_FRAGMENT | OVS_BUFFER_PRIVATE_CONTEXT | OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | OVS_BUFFER_SEND_BUFFER ; dstCtx -> refCount = 1 ; dstCtx -> magic = OVS_CTX_MAGIC ; dstCtx -> dataOffsetDelta = hdrSize + headRoom ; dstCtx -> mru = 0 ; InterlockedIncrement ( ( LONG volatile * ) & srcCtx -> refCount ) ; #ifdef DBG InterlockedIncrement ( ( LONG volatile * ) & ovsPool -> fragNBLCount ) ; OvsDumpNetBufferList ( nbl ) ; OvsDumpForwardingDetails ( nbl ) ; OvsDumpNetBufferList ( newNbl ) ; OvsDumpForwardingDetails ( newNbl ) ; #endif OVS_LOG_TRACE ( " " , nbl , newNbl ) ; return newNbl ; nbl_context_error : OvsFreeNBLContext ( context , newNbl ) ; nblcopy_error : #ifdef DBG InterlockedDecrement ( ( LONG volatile * ) & ovsPool -> fragNBLCount ) ; #endif NdisFreeFragmentNetBufferList ( newNbl , hdrSize + headRoom , 0 ) ; return NULL ; }
OvsFragmentNBL
OvsFragmentNBL
/* Figure out the header size */ /* Get the NBL size. */ /* XXX add to ovsPool counters? */ /* Now deal with TCP payload */ /* Now copy the eth/IP/TCP header and fix up */ /* Move on to the next segment */ /*Copy with Flag - NDIS_SWITCH_COPY_NBL_INFO_FLAGS_PRESERVE_DESTINATIONS.*/ /* Remember it's a fragment NBL so we can free it properly */