You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ib_packet.c 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. FILE_LICENCE ( GPL2_OR_LATER );
  19. #include <stdint.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <errno.h>
  23. #include <byteswap.h>
  24. #include <gpxe/iobuf.h>
  25. #include <gpxe/infiniband.h>
  26. #include <gpxe/ib_packet.h>
  27. /**
  28. * @file
  29. *
  30. * Infiniband Packet Formats
  31. *
  32. */
  33. /**
  34. * Add IB headers
  35. *
  36. * @v ibdev Infiniband device
  37. * @v iobuf I/O buffer to contain headers
  38. * @v qp Queue pair
  39. * @v payload_len Payload length
  40. * @v av Address vector
  41. */
  42. int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
  43. struct ib_queue_pair *qp, size_t payload_len,
  44. const struct ib_address_vector *av ) {
  45. struct ib_local_route_header *lrh;
  46. struct ib_global_route_header *grh;
  47. struct ib_base_transport_header *bth;
  48. struct ib_datagram_extended_transport_header *deth;
  49. size_t orig_iob_len = iob_len ( iobuf );
  50. size_t pad_len;
  51. size_t lrh_len;
  52. size_t grh_len;
  53. unsigned int vl;
  54. unsigned int lnh;
  55. DBGC2 ( ibdev, "IBDEV %p TX %04x:%08lx => %04x:%08lx (key %08lx)\n",
  56. ibdev, ibdev->lid, qp->qpn, av->lid, av->qpn, av->qkey );
  57. /* Calculate packet length */
  58. pad_len = ( (-payload_len) & 0x3 );
  59. payload_len += pad_len;
  60. payload_len += 4; /* ICRC */
  61. /* Reserve space for headers */
  62. orig_iob_len = iob_len ( iobuf );
  63. deth = iob_push ( iobuf, sizeof ( *deth ) );
  64. bth = iob_push ( iobuf, sizeof ( *bth ) );
  65. grh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
  66. grh = ( av->gid_present ?
  67. iob_push ( iobuf, sizeof ( *grh ) ) : NULL );
  68. lrh = iob_push ( iobuf, sizeof ( *lrh ) );
  69. lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
  70. /* Construct LRH */
  71. vl = ( ( av->qpn == IB_QPN_SMA ) ? IB_VL_SMP : IB_VL_DEFAULT );
  72. lrh->vl__lver = ( vl << 4 );
  73. lnh = ( grh ? IB_LNH_GRH : IB_LNH_BTH );
  74. lrh->sl__lnh = ( ( av->sl << 4 ) | lnh );
  75. lrh->dlid = htons ( av->lid );
  76. lrh->length = htons ( lrh_len >> 2 );
  77. lrh->slid = htons ( ibdev->lid );
  78. /* Construct GRH, if required */
  79. if ( grh ) {
  80. grh->ipver__tclass__flowlabel =
  81. htonl ( IB_GRH_IPVER_IPv6 << 28 );
  82. grh->paylen = htons ( grh_len );
  83. grh->nxthdr = IB_GRH_NXTHDR_IBA;
  84. grh->hoplmt = 0;
  85. memcpy ( &grh->sgid, &ibdev->gid, sizeof ( grh->sgid ) );
  86. memcpy ( &grh->dgid, &av->gid, sizeof ( grh->dgid ) );
  87. }
  88. /* Construct BTH */
  89. bth->opcode = BTH_OPCODE_UD_SEND;
  90. bth->se__m__padcnt__tver = ( pad_len << 4 );
  91. bth->pkey = htons ( ibdev->pkey );
  92. bth->dest_qp = htonl ( av->qpn );
  93. bth->ack__psn = htonl ( ( ibdev->psn++ ) & 0xffffffUL );
  94. /* Construct DETH */
  95. deth->qkey = htonl ( av->qkey );
  96. deth->src_qp = htonl ( qp->qpn );
  97. DBGCP_HDA ( ibdev, 0, iobuf->data,
  98. ( iob_len ( iobuf ) - orig_iob_len ) );
  99. return 0;
  100. }
  101. /**
  102. * Remove IB headers
  103. *
  104. * @v ibdev Infiniband device
  105. * @v iobuf I/O buffer containing headers
  106. * @v qp Queue pair to fill in, or NULL
  107. * @v payload_len Payload length to fill in, or NULL
  108. * @v av Address vector to fill in
  109. */
  110. int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
  111. struct ib_queue_pair **qp, size_t *payload_len,
  112. struct ib_address_vector *av ) {
  113. struct ib_local_route_header *lrh;
  114. struct ib_global_route_header *grh;
  115. struct ib_base_transport_header *bth;
  116. struct ib_datagram_extended_transport_header *deth;
  117. size_t orig_iob_len = iob_len ( iobuf );
  118. unsigned int lnh;
  119. size_t pad_len;
  120. unsigned long qpn;
  121. unsigned int lid;
  122. /* Clear return values */
  123. if ( qp )
  124. *qp = NULL;
  125. if ( payload_len )
  126. *payload_len = 0;
  127. memset ( av, 0, sizeof ( *av ) );
  128. /* Extract LRH */
  129. if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) {
  130. DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for LRH\n",
  131. ibdev, iob_len ( iobuf ) );
  132. return -EINVAL;
  133. }
  134. lrh = iobuf->data;
  135. iob_pull ( iobuf, sizeof ( *lrh ) );
  136. av->lid = ntohs ( lrh->slid );
  137. av->sl = ( lrh->sl__lnh >> 4 );
  138. lnh = ( lrh->sl__lnh & 0x3 );
  139. lid = ntohs ( lrh->dlid );
  140. /* Reject unsupported packets */
  141. if ( ! ( ( lnh == IB_LNH_BTH ) || ( lnh == IB_LNH_GRH ) ) ) {
  142. DBGC ( ibdev, "IBDEV %p RX unsupported LNH %x\n",
  143. ibdev, lnh );
  144. return -ENOTSUP;
  145. }
  146. /* Extract GRH, if present */
  147. if ( lnh == IB_LNH_GRH ) {
  148. if ( iob_len ( iobuf ) < sizeof ( *grh ) ) {
  149. DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) "
  150. "for GRH\n", ibdev, iob_len ( iobuf ) );
  151. return -EINVAL;
  152. }
  153. grh = iobuf->data;
  154. iob_pull ( iobuf, sizeof ( *grh ) );
  155. av->gid_present = 1;
  156. memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) );
  157. } else {
  158. grh = NULL;
  159. }
  160. /* Extract BTH */
  161. if ( iob_len ( iobuf ) < sizeof ( *bth ) ) {
  162. DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for BTH\n",
  163. ibdev, iob_len ( iobuf ) );
  164. return -EINVAL;
  165. }
  166. bth = iobuf->data;
  167. iob_pull ( iobuf, sizeof ( *bth ) );
  168. if ( bth->opcode != BTH_OPCODE_UD_SEND ) {
  169. DBGC ( ibdev, "IBDEV %p unsupported BTH opcode %x\n",
  170. ibdev, bth->opcode );
  171. return -ENOTSUP;
  172. }
  173. qpn = ntohl ( bth->dest_qp );
  174. /* Extract DETH */
  175. if ( iob_len ( iobuf ) < sizeof ( *deth ) ) {
  176. DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for DETH\n",
  177. ibdev, iob_len ( iobuf ) );
  178. return -EINVAL;
  179. }
  180. deth = iobuf->data;
  181. iob_pull ( iobuf, sizeof ( *deth ) );
  182. av->qpn = ntohl ( deth->src_qp );
  183. av->qkey = ntohl ( deth->qkey );
  184. /* Calculate payload length, if applicable */
  185. if ( payload_len ) {
  186. pad_len = ( ( bth->se__m__padcnt__tver >> 4 ) & 0x3 );
  187. *payload_len = ( ( ntohs ( lrh->length ) << 2 )
  188. - ( orig_iob_len - iob_len ( iobuf ) )
  189. - pad_len - 4 /* ICRC */ );
  190. }
  191. /* Determine destination QP, if applicable */
  192. if ( qp ) {
  193. if ( IB_LID_MULTICAST ( lid ) && grh ) {
  194. *qp = ib_find_qp_mgid ( ibdev, &grh->dgid );
  195. } else {
  196. *qp = ib_find_qp_qpn ( ibdev, qpn );
  197. }
  198. if ( ! *qp ) {
  199. DBGC ( ibdev, "IBDEV %p RX for nonexistent QP\n",
  200. ibdev );
  201. return -ENODEV;
  202. }
  203. }
  204. DBGC2 ( ibdev, "IBDEV %p RX %04x:%08lx <= %04x:%08lx (key %08x)\n",
  205. ibdev, lid,
  206. ( IB_LID_MULTICAST( lid ) ? ( qp ? (*qp)->qpn : -1UL ) : qpn ),
  207. av->lid, av->qpn, ntohl ( deth->qkey ) );
  208. DBGCP_HDA ( ibdev, 0,
  209. ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ),
  210. ( orig_iob_len - iob_len ( iobuf ) ) );
  211. return 0;
  212. }