ib_packet.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020 
00021 #include <stdint.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <errno.h>
00025 #include <byteswap.h>
00026 #include <gpxe/iobuf.h>
00027 #include <gpxe/infiniband.h>
00028 #include <gpxe/ib_packet.h>
00029 
00030 /**
00031  * @file
00032  *
00033  * Infiniband Packet Formats
00034  *
00035  */
00036 
00037 /**
00038  * Add IB headers
00039  *
00040  * @v ibdev             Infiniband device
00041  * @v iobuf             I/O buffer to contain headers
00042  * @v qp                Queue pair
00043  * @v payload_len       Payload length
00044  * @v av                Address vector
00045  */
00046 int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
00047               struct ib_queue_pair *qp, size_t payload_len,
00048               const struct ib_address_vector *av ) {
00049         struct ib_local_route_header *lrh;
00050         struct ib_global_route_header *grh;
00051         struct ib_base_transport_header *bth;
00052         struct ib_datagram_extended_transport_header *deth;
00053         size_t orig_iob_len = iob_len ( iobuf );
00054         size_t pad_len;
00055         size_t lrh_len;
00056         size_t grh_len;
00057         unsigned int vl;
00058         unsigned int lnh;
00059 
00060         DBGC2 ( ibdev, "IBDEV %p TX %04x:%08lx => %04x:%08lx (key %08lx)\n",
00061                 ibdev, ibdev->lid, qp->ext_qpn, av->lid, av->qpn, av->qkey );
00062 
00063         /* Calculate packet length */
00064         pad_len = ( (-payload_len) & 0x3 );
00065         payload_len += pad_len;
00066         payload_len += 4; /* ICRC */
00067 
00068         /* Reserve space for headers */
00069         orig_iob_len = iob_len ( iobuf );
00070         deth = iob_push ( iobuf, sizeof ( *deth ) );
00071         bth = iob_push ( iobuf, sizeof ( *bth ) );
00072         grh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
00073         grh = ( av->gid_present ?
00074                 iob_push ( iobuf, sizeof ( *grh ) ) : NULL );
00075         lrh = iob_push ( iobuf, sizeof ( *lrh ) );
00076         lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
00077 
00078         /* Construct LRH */
00079         vl = ( ( qp->ext_qpn == IB_QPN_SMI ) ? IB_VL_SMP : IB_VL_DEFAULT );
00080         lrh->vl__lver = ( vl << 4 );
00081         lnh = ( grh ? IB_LNH_GRH : IB_LNH_BTH );
00082         lrh->sl__lnh = ( ( av->sl << 4 ) | lnh );
00083         lrh->dlid = htons ( av->lid );
00084         lrh->length = htons ( lrh_len >> 2 );
00085         lrh->slid = htons ( ibdev->lid );
00086 
00087         /* Construct GRH, if required */
00088         if ( grh ) {
00089                 grh->ipver__tclass__flowlabel =
00090                         htonl ( IB_GRH_IPVER_IPv6 << 28 );
00091                 grh->paylen = htons ( grh_len );
00092                 grh->nxthdr = IB_GRH_NXTHDR_IBA;
00093                 grh->hoplmt = 0;
00094                 memcpy ( &grh->sgid, &ibdev->gid, sizeof ( grh->sgid ) );
00095                 memcpy ( &grh->dgid, &av->gid, sizeof ( grh->dgid ) );
00096         }
00097 
00098         /* Construct BTH */
00099         bth->opcode = BTH_OPCODE_UD_SEND;
00100         bth->se__m__padcnt__tver = ( pad_len << 4 );
00101         bth->pkey = htons ( ibdev->pkey );
00102         bth->dest_qp = htonl ( av->qpn );
00103         bth->ack__psn = htonl ( ( qp->send.psn++ ) & 0xffffffUL );
00104 
00105         /* Construct DETH */
00106         deth->qkey = htonl ( av->qkey );
00107         deth->src_qp = htonl ( qp->ext_qpn );
00108 
00109         DBGCP_HDA ( ibdev, 0, iobuf->data,
00110                     ( iob_len ( iobuf ) - orig_iob_len ) );
00111 
00112         return 0;
00113 }
00114 
00115 /**
00116  * Remove IB headers
00117  *
00118  * @v ibdev             Infiniband device
00119  * @v iobuf             I/O buffer containing headers
00120  * @v qp                Queue pair to fill in, or NULL
00121  * @v payload_len       Payload length to fill in, or NULL
00122  * @v av                Address vector to fill in
00123  */
00124 int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
00125               struct ib_queue_pair **qp, size_t *payload_len,
00126               struct ib_address_vector *av ) {
00127         struct ib_local_route_header *lrh;
00128         struct ib_global_route_header *grh;
00129         struct ib_base_transport_header *bth;
00130         struct ib_datagram_extended_transport_header *deth;
00131         size_t orig_iob_len = iob_len ( iobuf );
00132         unsigned int lnh;
00133         size_t pad_len;
00134         unsigned long qpn;
00135         unsigned int lid;
00136 
00137         /* Clear return values */
00138         if ( qp )
00139                 *qp = NULL;
00140         if ( payload_len )
00141                 *payload_len = 0;
00142         memset ( av, 0, sizeof ( *av ) );
00143 
00144         /* Extract LRH */
00145         if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) {
00146                 DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for LRH\n",
00147                        ibdev, iob_len ( iobuf ) );
00148                 return -EINVAL;
00149         }
00150         lrh = iobuf->data;
00151         iob_pull ( iobuf, sizeof ( *lrh ) );
00152         av->lid = ntohs ( lrh->slid );
00153         av->sl = ( lrh->sl__lnh >> 4 );
00154         lnh = ( lrh->sl__lnh & 0x3 );
00155         lid = ntohs ( lrh->dlid );
00156 
00157         /* Reject unsupported packets */
00158         if ( ! ( ( lnh == IB_LNH_BTH ) || ( lnh == IB_LNH_GRH ) ) ) {
00159                 DBGC ( ibdev, "IBDEV %p RX unsupported LNH %x\n",
00160                        ibdev, lnh );
00161                 return -ENOTSUP;
00162         }
00163 
00164         /* Extract GRH, if present */
00165         if ( lnh == IB_LNH_GRH ) {
00166                 if ( iob_len ( iobuf ) < sizeof ( *grh ) ) {
00167                         DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) "
00168                                "for GRH\n", ibdev, iob_len ( iobuf ) );
00169                         return -EINVAL;
00170                 }
00171                 grh = iobuf->data;
00172                 iob_pull ( iobuf, sizeof ( *grh ) );
00173                 av->gid_present = 1;
00174                 memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) );
00175         } else {
00176                 grh = NULL;
00177         }
00178 
00179         /* Extract BTH */
00180         if ( iob_len ( iobuf ) < sizeof ( *bth ) ) {
00181                 DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for BTH\n",
00182                        ibdev, iob_len ( iobuf ) );
00183                 return -EINVAL;
00184         }
00185         bth = iobuf->data;
00186         iob_pull ( iobuf, sizeof ( *bth ) );
00187         if ( bth->opcode != BTH_OPCODE_UD_SEND ) {
00188                 DBGC ( ibdev, "IBDEV %p unsupported BTH opcode %x\n",
00189                        ibdev, bth->opcode );
00190                 return -ENOTSUP;
00191         }
00192         qpn = ntohl ( bth->dest_qp );
00193 
00194         /* Extract DETH */
00195         if ( iob_len ( iobuf ) < sizeof ( *deth ) ) {
00196                 DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for DETH\n",
00197                        ibdev, iob_len ( iobuf ) );
00198                 return -EINVAL;
00199         }
00200         deth = iobuf->data;
00201         iob_pull ( iobuf, sizeof ( *deth ) );
00202         av->qpn = ntohl ( deth->src_qp );
00203         av->qkey = ntohl ( deth->qkey );
00204 
00205         /* Calculate payload length, if applicable */
00206         if ( payload_len ) {
00207                 pad_len = ( ( bth->se__m__padcnt__tver >> 4 ) & 0x3 );
00208                 *payload_len = ( ( ntohs ( lrh->length ) << 2 )
00209                                  - ( orig_iob_len - iob_len ( iobuf ) )
00210                                  - pad_len - 4 /* ICRC */ );
00211         }
00212 
00213         /* Determine destination QP, if applicable */
00214         if ( qp ) {
00215                 if ( IB_LID_MULTICAST ( lid ) && grh ) {
00216                         if ( ! ( *qp = ib_find_qp_mgid ( ibdev, &grh->dgid ))){
00217                                 DBGC ( ibdev, "IBDEV %p RX for unknown MGID "
00218                                        "%08x:%08x:%08x:%08x\n", ibdev,
00219                                        ntohl ( grh->dgid.u.dwords[0] ),
00220                                        ntohl ( grh->dgid.u.dwords[1] ),
00221                                        ntohl ( grh->dgid.u.dwords[2] ),
00222                                        ntohl ( grh->dgid.u.dwords[3] ) );
00223                                 return -ENODEV;
00224                         }
00225                 } else {
00226                         if ( ! ( *qp = ib_find_qp_qpn ( ibdev, qpn ) ) ) {
00227                                 DBGC ( ibdev, "IBDEV %p RX for nonexistent "
00228                                        "QPN %lx\n", ibdev, qpn );
00229                                 return -ENODEV;
00230                         }
00231                 }
00232                 assert ( *qp );
00233         }
00234 
00235         DBGC2 ( ibdev, "IBDEV %p RX %04x:%08lx <= %04x:%08lx (key %08x)\n",
00236                 ibdev, lid, ( IB_LID_MULTICAST( lid ) ?
00237                               ( qp ? (*qp)->ext_qpn : -1UL ) : qpn ),
00238                 av->lid, av->qpn, ntohl ( deth->qkey ) );
00239         DBGCP_HDA ( ibdev, 0,
00240                     ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ),
00241                     ( orig_iob_len - iob_len ( iobuf ) ) );
00242 
00243         return 0;
00244 }

Generated on Tue Apr 6 20:01:10 2010 for gPXE by  doxygen 1.5.7.1