iPXE
Functions
ib_packet.c File Reference

Infiniband Packet Formats. More...

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/iobuf.h>
#include <ipxe/infiniband.h>
#include <ipxe/ib_packet.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
int ib_push (struct ib_device *ibdev, struct io_buffer *iobuf, struct ib_queue_pair *qp, size_t payload_len, const struct ib_address_vector *dest)
 Add IB headers.
int ib_pull (struct ib_device *ibdev, struct io_buffer *iobuf, struct ib_queue_pair **qp, size_t *payload_len, struct ib_address_vector *dest, struct ib_address_vector *source)
 Remove IB headers.

Detailed Description

Infiniband Packet Formats.

Definition in file ib_packet.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
int ib_push ( struct ib_device ibdev,
struct io_buffer iobuf,
struct ib_queue_pair qp,
size_t  payload_len,
const struct ib_address_vector dest 
)

Add IB headers.

Parameters:
ibdevInfiniband device
iobufI/O buffer to contain headers
qpQueue pair
payload_lenPayload length
destDestination address vector
Return values:
rcReturn status code

Definition at line 52 of file ib_packet.c.

References ib_base_transport_header::ack__psn, bth, BTH_OPCODE_UD_SEND, io_buffer::data, DBGC2, DBGCP_HDA, ib_base_transport_header::dest_qp, deth, ib_global_route_header::dgid, ib_local_route_header::dlid, ib_queue_pair::ext_qpn, ib_address_vector::gid, ib_device::gid, ib_address_vector::gid_present, grh, ib_global_route_header::hoplmt, htonl, htons, IB_GRH_IPVER_IPv6, IB_GRH_NXTHDR_IBA, IB_LNH_BTH, IB_LNH_GRH, IB_QPN_SMI, IB_VL_DEFAULT, IB_VL_SMP, iob_len(), iob_push, ib_global_route_header::ipver__tclass__flowlabel, ib_local_route_header::length, ib_address_vector::lid, ib_device::lid, lrh, memcpy(), ib_device::name, NULL, ib_global_route_header::nxthdr, ib_base_transport_header::opcode, ib_global_route_header::paylen, ib_base_transport_header::pkey, ib_device::pkey, ib_work_queue::psn, ib_address_vector::qkey, ib_datagram_extended_transport_header::qkey, ib_address_vector::qpn, ib_base_transport_header::se__m__padcnt__tver, ib_queue_pair::send, ib_global_route_header::sgid, ib_address_vector::sl, ib_local_route_header::sl__lnh, ib_local_route_header::slid, ib_datagram_extended_transport_header::src_qp, and ib_local_route_header::vl__lver.

Referenced by arbel_fill_mlx_send_wqe(), hermon_fill_mlx_send_wqe(), linda_post_send(), and qib7322_post_send().

                                                     {
        struct ib_local_route_header *lrh;
        struct ib_global_route_header *grh;
        struct ib_base_transport_header *bth;
        struct ib_datagram_extended_transport_header *deth;
        size_t orig_iob_len = iob_len ( iobuf );
        size_t pad_len;
        size_t lrh_len;
        size_t grh_len;
        unsigned int vl;
        unsigned int lnh;

        DBGC2 ( ibdev, "IBDEV %s TX %04x:%08lx => %04x:%08lx (key %08lx)\n",
                ibdev->name, ibdev->lid, qp->ext_qpn, dest->lid, dest->qpn,
                dest->qkey );

        /* Calculate packet length */
        pad_len = ( (-payload_len) & 0x3 );
        payload_len += pad_len;
        payload_len += 4; /* ICRC */

        /* Reserve space for headers */
        orig_iob_len = iob_len ( iobuf );
        deth = iob_push ( iobuf, sizeof ( *deth ) );
        bth = iob_push ( iobuf, sizeof ( *bth ) );
        grh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
        grh = ( dest->gid_present ?
                iob_push ( iobuf, sizeof ( *grh ) ) : NULL );
        lrh = iob_push ( iobuf, sizeof ( *lrh ) );
        lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );

        /* Construct LRH */
        vl = ( ( qp->ext_qpn == IB_QPN_SMI ) ? IB_VL_SMP : IB_VL_DEFAULT );
        lrh->vl__lver = ( vl << 4 );
        lnh = ( grh ? IB_LNH_GRH : IB_LNH_BTH );
        lrh->sl__lnh = ( ( dest->sl << 4 ) | lnh );
        lrh->dlid = htons ( dest->lid );
        lrh->length = htons ( lrh_len >> 2 );
        lrh->slid = htons ( ibdev->lid );

        /* Construct GRH, if required */
        if ( grh ) {
                grh->ipver__tclass__flowlabel =
                        htonl ( IB_GRH_IPVER_IPv6 << 28 );
                grh->paylen = htons ( grh_len );
                grh->nxthdr = IB_GRH_NXTHDR_IBA;
                grh->hoplmt = 0;
                memcpy ( &grh->sgid, &ibdev->gid, sizeof ( grh->sgid ) );
                memcpy ( &grh->dgid, &dest->gid, sizeof ( grh->dgid ) );
        }

        /* Construct BTH */
        bth->opcode = BTH_OPCODE_UD_SEND;
        bth->se__m__padcnt__tver = ( pad_len << 4 );
        bth->pkey = htons ( ibdev->pkey );
        bth->dest_qp = htonl ( dest->qpn );
        bth->ack__psn = htonl ( ( qp->send.psn++ ) & 0xffffffUL );

        /* Construct DETH */
        deth->qkey = htonl ( dest->qkey );
        deth->src_qp = htonl ( qp->ext_qpn );

        DBGCP_HDA ( ibdev, 0, iobuf->data,
                    ( iob_len ( iobuf ) - orig_iob_len ) );

        return 0;
}
int ib_pull ( struct ib_device ibdev,
struct io_buffer iobuf,
struct ib_queue_pair **  qp,
size_t payload_len,
struct ib_address_vector dest,
struct ib_address_vector source 
)

Remove IB headers.

Parameters:
ibdevInfiniband device
iobufI/O buffer containing headers
qpQueue pair to fill in, or NULL
payload_lenPayload length to fill in, or NULL
destDestination address vector to fill in
sourceSource address vector to fill in
Return values:
rcReturn status code

Definition at line 133 of file ib_packet.c.

References assert, bth, BTH_OPCODE_UD_SEND, io_buffer::data, DBGC, DBGC2, DBGCP_HDA, ib_base_transport_header::dest_qp, deth, ib_global_route_header::dgid, ib_local_route_header::dlid, EINVAL, ENODEV, ENOTSUP, ib_queue_pair::ext_qpn, ib_address_vector::gid, ib_address_vector::gid_present, grh, ib_find_qp_mgid(), ib_find_qp_qpn(), IB_GID_ARGS, IB_GID_FMT, IB_LID_MULTICAST, IB_LNH_BTH, IB_LNH_GRH, iob_len(), iob_pull, ib_local_route_header::length, ib_address_vector::lid, lrh, memcpy(), memset(), ib_device::name, ntohl, ntohs, NULL, ib_base_transport_header::opcode, ib_address_vector::qkey, ib_datagram_extended_transport_header::qkey, ib_address_vector::qpn, ib_base_transport_header::se__m__padcnt__tver, ib_global_route_header::sgid, ib_address_vector::sl, ib_local_route_header::sl__lnh, ib_local_route_header::slid, and ib_datagram_extended_transport_header::src_qp.

Referenced by linda_complete_recv(), and qib7322_complete_recv().

                                                 {
        struct ib_local_route_header *lrh;
        struct ib_global_route_header *grh;
        struct ib_base_transport_header *bth;
        struct ib_datagram_extended_transport_header *deth;
        size_t orig_iob_len = iob_len ( iobuf );
        unsigned int lnh;
        size_t pad_len;

        /* Clear return values */
        if ( qp )
                *qp = NULL;
        if ( payload_len )
                *payload_len = 0;
        memset ( dest, 0, sizeof ( *dest ) );
        memset ( source, 0, sizeof ( *source ) );

        /* Extract LRH */
        if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) {
                DBGC ( ibdev, "IBDEV %s RX too short (%zd bytes) for LRH\n",
                       ibdev->name, iob_len ( iobuf ) );
                return -EINVAL;
        }
        lrh = iobuf->data;
        iob_pull ( iobuf, sizeof ( *lrh ) );
        dest->lid = ntohs ( lrh->dlid );
        dest->sl = ( lrh->sl__lnh >> 4 );
        source->lid = ntohs ( lrh->slid );
        source->sl = ( lrh->sl__lnh >> 4 );
        lnh = ( lrh->sl__lnh & 0x3 );

        /* Reject unsupported packets */
        if ( ! ( ( lnh == IB_LNH_BTH ) || ( lnh == IB_LNH_GRH ) ) ) {
                DBGC ( ibdev, "IBDEV %s RX unsupported LNH %x\n",
                       ibdev->name, lnh );
                return -ENOTSUP;
        }

        /* Extract GRH, if present */
        if ( lnh == IB_LNH_GRH ) {
                if ( iob_len ( iobuf ) < sizeof ( *grh ) ) {
                        DBGC ( ibdev, "IBDEV %s RX too short (%zd bytes) "
                               "for GRH\n", ibdev->name, iob_len ( iobuf ) );
                        return -EINVAL;
                }
                grh = iobuf->data;
                iob_pull ( iobuf, sizeof ( *grh ) );
                dest->gid_present = 1;
                memcpy ( &dest->gid, &grh->dgid, sizeof ( dest->gid ) );
                source->gid_present = 1;
                memcpy ( &source->gid, &grh->sgid, sizeof ( source->gid ) );
        } else {
                grh = NULL;
        }

        /* Extract BTH */
        if ( iob_len ( iobuf ) < sizeof ( *bth ) ) {
                DBGC ( ibdev, "IBDEV %s RX too short (%zd bytes) for BTH\n",
                       ibdev->name, iob_len ( iobuf ) );
                return -EINVAL;
        }
        bth = iobuf->data;
        iob_pull ( iobuf, sizeof ( *bth ) );
        if ( bth->opcode != BTH_OPCODE_UD_SEND ) {
                DBGC ( ibdev, "IBDEV %s unsupported BTH opcode %x\n",
                       ibdev->name, bth->opcode );
                return -ENOTSUP;
        }
        dest->qpn = ntohl ( bth->dest_qp );

        /* Extract DETH */
        if ( iob_len ( iobuf ) < sizeof ( *deth ) ) {
                DBGC ( ibdev, "IBDEV %s RX too short (%zd bytes) for DETH\n",
                       ibdev->name, iob_len ( iobuf ) );
                return -EINVAL;
        }
        deth = iobuf->data;
        iob_pull ( iobuf, sizeof ( *deth ) );
        source->qpn = ntohl ( deth->src_qp );
        source->qkey = ntohl ( deth->qkey );

        /* Calculate payload length, if applicable */
        if ( payload_len ) {
                pad_len = ( ( bth->se__m__padcnt__tver >> 4 ) & 0x3 );
                *payload_len = ( ( ntohs ( lrh->length ) << 2 )
                                 - ( orig_iob_len - iob_len ( iobuf ) )
                                 - pad_len - 4 /* ICRC */ );
        }

        /* Determine destination QP, if applicable */
        if ( qp ) {
                if ( IB_LID_MULTICAST ( dest->lid ) && grh ) {
                        if ( ! ( *qp = ib_find_qp_mgid ( ibdev, &grh->dgid ))){
                                DBGC ( ibdev, "IBDEV %s RX for unknown MGID "
                                       IB_GID_FMT "\n", ibdev->name,
                                       IB_GID_ARGS ( &grh->dgid ) );
                                return -ENODEV;
                        }
                } else {
                        if ( ! ( *qp = ib_find_qp_qpn ( ibdev, dest->qpn ) ) ) {
                                DBGC ( ibdev, "IBDEV %s RX for nonexistent "
                                       "QPN %#lx\n", ibdev->name, dest->qpn );
                                return -ENODEV;
                        }
                }
                assert ( *qp );
        }

        DBGC2 ( ibdev, "IBDEV %s RX %04x:%08lx <= %04x:%08lx (key %08x)\n",
                ibdev->name, dest->lid,
                ( IB_LID_MULTICAST ( dest->lid ) ?
                  ( qp ? (*qp)->ext_qpn : -1UL ) : dest->qpn ),
                source->lid, source->qpn, ntohl ( deth->qkey ) );
        DBGCP_HDA ( ibdev, 0,
                    ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ),
                    ( orig_iob_len - iob_len ( iobuf ) ) );

        return 0;
}