datapath-windows/ovsext/User.c
/*
 *----------------------------------------------------------------------------
 * OvsCreateQueueNlPacket --
 *
 *  Create a packet which will be forwarded to user space.
 *
 * InputParameter:
 *   userData: when cmd is user action, this field contain
 *      user action data.
 *   userDataLen: as name indicated
 *   cmd: either miss or user action
 *   inPort: datapath port id from which the packet is received.
 *   key: flow Key with a tunnel key if available
 *   nbl:  the NET_BUFFER_LIST which contain the packet
 *   nb: the packet
 *   isRecv: This is used to decide how to interprete the csum info
 *   hdrInfo: include hdr info initialized during flow extraction.
 *
 * Results:
 *    NULL if fail to create the packet
 *    The packet element otherwise
 *----------------------------------------------------------------------------
 */
OvsCreateQueueNlPacket
Create a packet which will be forwarded to user space.

when cmd is user action, this field contain
user action data.
userDataLen: as name indicated
cmd: either miss or user action
inPort: datapath port id from which the packet is received.

NULL if fail to create the packet
The packet element otherwise
OvsCreateQueueNlPacket Create a packet which will be forwarded to user space . when cmd is user action this field contain user action data . userDataLen : as name indicated cmd : either miss or user action inPort : datapath port id from which the packet is received . NULL if fail to create the packet The packet element otherwise
POVS_PACKET_QUEUE_ELEM
OvsCreateQueueNlPacket(PVOID userData,
                       UINT32 userDataLen,
                       UINT32 cmd,
                       POVS_VPORT_ENTRY vport,
                       OvsFlowKey *key,
                       OvsIPv4TunnelKey *tunnelKey,
                       PNET_BUFFER_LIST nbl,
                       PNET_BUFFER nb,
                       BOOLEAN isRecv,
                       POVS_PACKET_HDR_INFO hdrInfo)
{
#define VLAN_TAG_SIZE 4
    UINT32 allocLen, dataLen, extraLen = 0;
    POVS_PACKET_QUEUE_ELEM elem;
    UINT8 *src, *dst;
    NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
    PNDIS_NET_BUFFER_LIST_8021Q_INFO vlanInfo = NULL;
    PVOID vlanTag;
    UINT32 pid;
    UINT32 nlMsgSize;
    NL_BUFFER nlBuf;
    PNL_MSG_HDR nlMsg;
    POVS_BUFFER_CONTEXT ctx;
    if (vport == NULL){
        return NULL;
    }
    OvsGetPid(vport, nb, &pid);
    if (!pid) {
        return NULL;
    }
    csumInfo.Value = NET_BUFFER_LIST_INFO(nbl, TcpIpChecksumNetBufferListInfo);
    if (isRecv && (csumInfo.Receive.TcpChecksumFailed ||
            (csumInfo.Receive.UdpChecksumFailed && !hdrInfo->udpCsumZero) ||
            csumInfo.Receive.IpChecksumFailed)) {
        OVS_LOG_INFO("Packet dropped due to checksum failure.");
        ovsUserStats.dropDuetoChecksum++;
        return NULL;
    }
    vlanTag = NET_BUFFER_LIST_INFO(nbl, Ieee8021QNetBufferListInfo);
    if (vlanTag) {
        vlanInfo = (PNDIS_NET_BUFFER_LIST_8021Q_INFO)(PVOID *)&vlanTag;
        if (vlanInfo->Value) {
            extraLen = VLAN_TAG_SIZE;
        }
    }
    dataLen = NET_BUFFER_DATA_LENGTH(nb);
    if (NlAttrSize(dataLen) > MAXUINT16) {
        return NULL;
    }
    nlMsgSize = OvsGetUpcallMsgSize(userData, userDataLen, tunnelKey,
                                    dataLen + extraLen);
    allocLen = sizeof (OVS_PACKET_QUEUE_ELEM) + nlMsgSize;
    elem = (POVS_PACKET_QUEUE_ELEM)OvsAllocateMemoryWithTag(allocLen,
                                                            OVS_USER_POOL_TAG);
    if (elem == NULL) {
        ovsUserStats.dropDuetoResource++;
        return NULL;
    }
    elem->hdrInfo.value = hdrInfo->value;
    elem->upcallPid = pid;
    elem->packet.totalLen = nlMsgSize;
    elem->packet.queue = 0;
    elem->packet.userDataLen = userDataLen;
    elem->packet.inPort = vport->portNo;
    elem->packet.cmd = cmd;
    if (cmd == (UINT32)OVS_PACKET_CMD_MISS) {
        ovsUserStats.miss++;
    } else if (cmd == (UINT32)OVS_PACKET_CMD_ACTION) {
        ovsUserStats.action++;
    } else {
        ASSERT(FALSE);
        goto fail;
    }
    elem->packet.packetLen = dataLen + extraLen;
    NlBufInit(&nlBuf, (PCHAR)elem->packet.data, nlMsgSize);
    if (!NlFillOvsMsg(&nlBuf, OVS_WIN_NL_PACKET_FAMILY_ID, 0,
                      0, pid, (UINT8)cmd, OVS_PACKET_VERSION,
                      gOvsSwitchContext->dpNo)) {
        goto fail;
    }
    if (MapFlowKeyToNlKey(&nlBuf, key, OVS_PACKET_ATTR_KEY,
                          OVS_KEY_ATTR_TUNNEL) != STATUS_SUCCESS) {
        goto fail;
    }
    ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
    if (ctx->mru != 0) {
        if (!NlMsgPutTailU16(&nlBuf, OVS_PACKET_ATTR_MRU, (UINT16)ctx->mru)) {
            goto fail;
        }
    }
    if (tunnelKey) {
        if (MapFlowTunKeyToNlKey(&nlBuf, tunnelKey,
                                 OVS_PACKET_ATTR_EGRESS_TUN_KEY) != STATUS_SUCCESS) {
            goto fail;
        }
    }
    if (userData){
        if (!NlMsgPutTailUnspec(&nlBuf, OVS_PACKET_ATTR_USERDATA,
                                userData, (UINT16)userDataLen)) {
            goto fail;
        }
    }
    dst = (UINT8 *)NlMsgPutTailUnspecUninit(&nlBuf, OVS_PACKET_ATTR_PACKET,
                                            (UINT16)(dataLen + extraLen));
    if (!dst) {
        goto fail;
    }
    elem->packet.payload = dst;
    dst += extraLen;
    src = NdisGetDataBuffer(nb, dataLen, dst, 1, 0);
    if (src == NULL) {
        ovsUserStats.dropDuetoResource++;
        goto fail;
    }    else if (src != dst) {
        RtlCopyMemory(dst, src, dataLen);
    }
    OvsCompletePacketHeader(dst, isRecv, csumInfo, hdrInfo, &elem->hdrInfo);
    if (extraLen) {
        dst = elem->packet.payload;
        src = dst + extraLen;
        ((UINT32 *)dst)[0] = ((UINT32 *)src)[0];
        ((UINT32 *)dst)[1] = ((UINT32 *)src)[1];
        ((UINT32 *)dst)[2] = ((UINT32 *)src)[2];
        dst += 12;
        ((UINT16 *)dst)[0] = htons(0x8100);
        ((UINT16 *)dst)[1] = htons(vlanInfo->TagHeader.VlanId |
            (vlanInfo->TagHeader.CanonicalFormatId << 12) |
            (vlanInfo->TagHeader.UserPriority << 13));
        elem->hdrInfo.l3Offset += VLAN_TAG_SIZE;
        elem->hdrInfo.l4Offset += VLAN_TAG_SIZE;
        ovsUserStats.vlanInsert++;
    }
    nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuf, 0, 0);
    nlMsg->nlmsgLen = NlBufSize(&nlBuf);
    elem->packet.totalLen = nlMsg->nlmsgLen;
    return elem;
fail:
    OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
    return NULL;
}
POVS_PACKET_QUEUE_ELEM OvsCreateQueueNlPacket ( PVOID userData , UINT32 userDataLen , UINT32 cmd , POVS_VPORT_ENTRY vport , OvsFlowKey * key , OvsIPv4TunnelKey * tunnelKey , PNET_BUFFER_LIST nbl , PNET_BUFFER nb , BOOLEAN isRecv , POVS_PACKET_HDR_INFO hdrInfo ) { #define VLAN_TAG_SIZE  4 UINT32 allocLen , dataLen , extraLen = 0 ; POVS_PACKET_QUEUE_ELEM elem ; UINT8 * src , * dst ; NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo ; PNDIS_NET_BUFFER_LIST_8021Q_INFO vlanInfo = NULL ; PVOID vlanTag ; UINT32 pid ; UINT32 nlMsgSize ; NL_BUFFER nlBuf ; PNL_MSG_HDR nlMsg ; POVS_BUFFER_CONTEXT ctx ; if ( vport == NULL ) { return NULL ; } OvsGetPid ( vport , nb , & pid ) ; if ( ! pid ) { return NULL ; } csumInfo . Value = NET_BUFFER_LIST_INFO ( nbl , TcpIpChecksumNetBufferListInfo ) ; if ( isRecv && ( csumInfo . Receive . TcpChecksumFailed || ( csumInfo . Receive . UdpChecksumFailed && ! hdrInfo -> udpCsumZero ) || csumInfo . Receive . IpChecksumFailed ) ) { OVS_LOG_INFO ( " " ) ; ovsUserStats . dropDuetoChecksum ++ ; return NULL ; } vlanTag = NET_BUFFER_LIST_INFO ( nbl , Ieee8021QNetBufferListInfo ) ; if ( vlanTag ) { vlanInfo = ( PNDIS_NET_BUFFER_LIST_8021Q_INFO ) ( PVOID * ) & vlanTag ; if ( vlanInfo -> Value ) { extraLen = VLAN_TAG_SIZE ; } } dataLen = NET_BUFFER_DATA_LENGTH ( nb ) ; if ( NlAttrSize ( dataLen ) > MAXUINT16 ) { return NULL ; } nlMsgSize = OvsGetUpcallMsgSize ( userData , userDataLen , tunnelKey , dataLen + extraLen ) ; allocLen = sizeof ( OVS_PACKET_QUEUE_ELEM ) + nlMsgSize ; elem = ( POVS_PACKET_QUEUE_ELEM ) OvsAllocateMemoryWithTag ( allocLen , OVS_USER_POOL_TAG ) ; if ( elem == NULL ) { ovsUserStats . dropDuetoResource ++ ; return NULL ; } elem -> hdrInfo . value = hdrInfo -> value ; elem -> upcallPid = pid ; elem -> packet . totalLen = nlMsgSize ; elem -> packet . queue = 0 ; elem -> packet . userDataLen = userDataLen ; elem -> packet . inPort = vport -> portNo ; elem -> packet . cmd = cmd ; if ( cmd == ( UINT32 ) OVS_PACKET_CMD_MISS ) { ovsUserStats . miss ++ ; } else if ( cmd == ( UINT32 ) OVS_PACKET_CMD_ACTION ) { ovsUserStats . action ++ ; } else { ASSERT ( FALSE ) ; goto fail ; } elem -> packet . packetLen = dataLen + extraLen ; NlBufInit ( & nlBuf , ( PCHAR ) elem -> packet . data , nlMsgSize ) ; if ( ! NlFillOvsMsg ( & nlBuf , OVS_WIN_NL_PACKET_FAMILY_ID , 0 , 0 , pid , ( UINT8 ) cmd , OVS_PACKET_VERSION , gOvsSwitchContext -> dpNo ) ) { goto fail ; } if ( MapFlowKeyToNlKey ( & nlBuf , key , OVS_PACKET_ATTR_KEY , OVS_KEY_ATTR_TUNNEL ) != STATUS_SUCCESS ) { goto fail ; } ctx = ( POVS_BUFFER_CONTEXT ) NET_BUFFER_LIST_CONTEXT_DATA_START ( nbl ) ; if ( ctx -> mru != 0 ) { if ( ! NlMsgPutTailU16 ( & nlBuf , OVS_PACKET_ATTR_MRU , ( UINT16 ) ctx -> mru ) ) { goto fail ; } } if ( tunnelKey ) { if ( MapFlowTunKeyToNlKey ( & nlBuf , tunnelKey , OVS_PACKET_ATTR_EGRESS_TUN_KEY ) != STATUS_SUCCESS ) { goto fail ; } } if ( userData ) { if ( ! NlMsgPutTailUnspec ( & nlBuf , OVS_PACKET_ATTR_USERDATA , userData , ( UINT16 ) userDataLen ) ) { goto fail ; } } dst = ( UINT8 * ) NlMsgPutTailUnspecUninit ( & nlBuf , OVS_PACKET_ATTR_PACKET , ( UINT16 ) ( dataLen + extraLen ) ) ; if ( ! dst ) { goto fail ; } elem -> packet . payload = dst ; dst += extraLen ; src = NdisGetDataBuffer ( nb , dataLen , dst , 1 , 0 ) ; if ( src == NULL ) { ovsUserStats . dropDuetoResource ++ ; goto fail ; } else if ( src != dst ) { RtlCopyMemory ( dst , src , dataLen ) ; } OvsCompletePacketHeader ( dst , isRecv , csumInfo , hdrInfo , & elem -> hdrInfo ) ; if ( extraLen ) { dst = elem -> packet . payload ; src = dst + extraLen ; ( ( UINT32 * ) dst ) [ 0 ] = ( ( UINT32 * ) src ) [ 0 ] ; ( ( UINT32 * ) dst ) [ 1 ] = ( ( UINT32 * ) src ) [ 1 ] ; ( ( UINT32 * ) dst ) [ 2 ] = ( ( UINT32 * ) src ) [ 2 ] ; dst += 12 ; ( ( UINT16 * ) dst ) [ 0 ] = htons ( 0x8100 ) ; ( ( UINT16 * ) dst ) [ 1 ] = htons ( vlanInfo -> TagHeader . VlanId | ( vlanInfo -> TagHeader . CanonicalFormatId << 12 ) | ( vlanInfo -> TagHeader . UserPriority << 13 ) ) ; elem -> hdrInfo . l3Offset += VLAN_TAG_SIZE ; elem -> hdrInfo . l4Offset += VLAN_TAG_SIZE ; ovsUserStats . vlanInsert ++ ; } nlMsg = ( PNL_MSG_HDR ) NlBufAt ( & nlBuf , 0 , 0 ) ; nlMsg -> nlmsgLen = NlBufSize ( & nlBuf ) ; elem -> packet . totalLen = nlMsg -> nlmsgLen ; return elem ; fail : OvsFreeMemoryWithTag ( elem , OVS_USER_POOL_TAG ) ; return NULL ; }
OvsCreateQueueNlPacket
  Create a packet which will be forwarded to user space.
OvsCreateQueueNlPacket Create a packet which will be forwarded to user space .
/* No vport is not fatal. */ /*
         * There is no userspace queue created yet, so there is no point for
         * creating a new packet to be queued.
         */ /* XXX remove queueid */ /* XXX  no need as the length is already in the NL attrib */ /* XXX Should we have both packetLen and TotalLen*/ /*
     * Initialize the OVS header
     * Since we are pre allocating memory for the NL buffer
     * the attribute settings should not fail
     */ /* Set MRU attribute */ /* Set OVS_PACKET_ATTR_EGRESS_TUN_KEY attribute */ /*
     * Make space for the payload to be copied and set the attribute
     * XXX Uninit set initilizes the buffer with xero, we don't actually need
     * that the payload to be initailized
     */ /* Store the payload for csum calculation when packet is read */ /* Copy the data from the NDIS buffer to dst. */ /* Set csum if was offloaded */ /*
     * Finally insert VLAN tag
     */ /* 'totalLen' should be size of valid data. */