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.

lotest.c 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * Copyright (C) 2010 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., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. #include <stdint.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <stdio.h>
  24. #include <errno.h>
  25. #include <byteswap.h>
  26. #include <ipxe/iobuf.h>
  27. #include <ipxe/netdevice.h>
  28. #include <ipxe/if_ether.h>
  29. #include <ipxe/keys.h>
  30. #include <ipxe/console.h>
  31. #include <usr/ifmgmt.h>
  32. #include <usr/lotest.h>
  33. /** @file
  34. *
  35. * Loopback testing
  36. *
  37. */
  38. /** Current loopback test receiver */
  39. static struct net_device *lotest_receiver;
  40. /** Loopback testing received packets */
  41. static LIST_HEAD ( lotest_queue );
  42. /**
  43. * Process received packet
  44. *
  45. * @v iobuf I/O buffer
  46. * @v netdev Network device
  47. * @v ll_dest Link-layer destination address
  48. * @v ll_source Link-layer source address
  49. * @v flags Packet flags
  50. * @ret rc Return status code
  51. */
  52. static int lotest_rx ( struct io_buffer *iobuf,
  53. struct net_device *netdev,
  54. const void *ll_dest __unused,
  55. const void *ll_source __unused,
  56. unsigned int flags __unused ) {
  57. /* Add to received packet queue if currently performing a test */
  58. if ( netdev == lotest_receiver ) {
  59. list_add_tail ( &iobuf->list, &lotest_queue );
  60. } else {
  61. free_iob ( iobuf );
  62. }
  63. return 0;
  64. }
  65. /**
  66. * Dequeue received packet
  67. *
  68. * @ret iobuf I/O buffer, or NULL
  69. */
  70. static struct io_buffer * lotest_dequeue ( void ) {
  71. struct io_buffer *iobuf;
  72. /* Remove first packet (if any) from received packet queue */
  73. iobuf = list_first_entry ( &lotest_queue, struct io_buffer, list );
  74. if ( ! iobuf )
  75. return NULL;
  76. list_del ( &iobuf->list );
  77. return iobuf;
  78. }
  79. /**
  80. * Transcribe network-layer address
  81. *
  82. * @v net_addr Network-layer address
  83. * @ret string Human-readable transcription of address
  84. */
  85. static const char * lotest_ntoa ( const void *net_addr __unused ) {
  86. return "<INVALID>";
  87. }
  88. /**
  89. * Loopback test network-layer protocol
  90. *
  91. * Using a dedicated network-layer protocol avoids problems caused by
  92. * cards supporting features such as IPv4 checksum offload trying to
  93. * interpret the (randomly generated) network-layer content.
  94. */
  95. static struct net_protocol lotest_protocol __net_protocol = {
  96. .name = "LOTEST",
  97. .rx = lotest_rx,
  98. .ntoa = lotest_ntoa,
  99. .net_proto = htons ( 0x6950 ), /* Not a genuine protocol number */
  100. .net_addr_len = 0,
  101. };
  102. /**
  103. * Discard all received loopback test packets
  104. *
  105. */
  106. static void lotest_flush ( void ) {
  107. struct io_buffer *iobuf;
  108. while ( ( iobuf = lotest_dequeue() ) != NULL )
  109. free_iob ( iobuf );
  110. }
  111. /**
  112. * Wait for packet to be received
  113. *
  114. * @v data Expected data
  115. * @v len Expected data length
  116. * @ret rc Return status code
  117. */
  118. static int loopback_wait ( void *data, size_t len ) {
  119. struct io_buffer *iobuf;
  120. /* Poll until packet arrives */
  121. while ( 1 ) {
  122. /* Check for cancellation */
  123. if ( iskey() && ( getchar() == CTRL_C ) )
  124. return -ECANCELED;
  125. /* Poll network devices */
  126. net_poll();
  127. /* Dequeue packet, if available */
  128. iobuf = lotest_dequeue();
  129. if ( ! iobuf )
  130. continue;
  131. /* Check packet length */
  132. if ( iob_len ( iobuf ) != len ) {
  133. printf ( "\nLength mismatch: sent %zd, received %zd",
  134. len, iob_len ( iobuf ) );
  135. DBG ( "\nSent:\n" );
  136. DBG_HDA ( 0, data, len );
  137. DBG ( "Received:\n" );
  138. DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
  139. free_iob ( iob_disown ( iobuf ) );
  140. return -EINVAL;
  141. }
  142. /* Check packet content */
  143. if ( memcmp ( iobuf->data, data, len ) != 0 ) {
  144. printf ( "\nContent mismatch" );
  145. DBG ( "\nSent:\n" );
  146. DBG_HDA ( 0, data, len );
  147. DBG ( "Received:\n" );
  148. DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
  149. free_iob ( iob_disown ( iobuf ) );
  150. return -EINVAL;
  151. }
  152. /* Discard packet and return */
  153. free_iob ( iob_disown ( iobuf ) );
  154. return 0;
  155. }
  156. }
  157. /**
  158. * Perform loopback test between two network devices
  159. *
  160. * @v sender Sending network device
  161. * @v receiver Received network device
  162. * @v mtu Packet size (excluding link-layer headers)
  163. * @ret rc Return status code
  164. */
  165. int loopback_test ( struct net_device *sender, struct net_device *receiver,
  166. size_t mtu ) {
  167. uint8_t *buf;
  168. uint32_t *seq;
  169. struct io_buffer *iobuf;
  170. unsigned int i;
  171. unsigned int successes;
  172. int rc;
  173. /* Open network devices */
  174. if ( ( rc = ifopen ( sender ) ) != 0 )
  175. return rc;
  176. if ( ( rc = ifopen ( receiver ) ) != 0 )
  177. return rc;
  178. /* Wait for link-up */
  179. if ( ( rc = iflinkwait ( sender, 0 ) ) != 0 )
  180. return rc;
  181. if ( ( rc = iflinkwait ( receiver, 0 ) ) != 0 )
  182. return rc;
  183. /* Allocate data buffer */
  184. if ( mtu < sizeof ( *seq ) )
  185. mtu = sizeof ( *seq );
  186. buf = malloc ( mtu );
  187. if ( ! buf )
  188. return -ENOMEM;
  189. seq = ( ( void * ) buf );
  190. /* Print initial statistics */
  191. printf ( "Performing loopback test from %s to %s with %zd byte MTU\n",
  192. sender->name, receiver->name, mtu );
  193. ifstat ( sender );
  194. ifstat ( receiver );
  195. /* Start loopback test */
  196. lotest_flush();
  197. lotest_receiver = receiver;
  198. /* Perform loopback test */
  199. for ( successes = 0 ; ; successes++ ) {
  200. /* Print running total */
  201. printf ( "\r%d", successes );
  202. /* Generate random packet */
  203. *seq = htonl ( successes );
  204. for ( i = sizeof ( *seq ) ; i < mtu ; i++ )
  205. buf[i] = random();
  206. iobuf = alloc_iob ( MAX_LL_HEADER_LEN + mtu );
  207. if ( ! iobuf ) {
  208. printf ( "\nFailed to allocate I/O buffer" );
  209. rc = -ENOMEM;
  210. break;
  211. }
  212. iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
  213. memcpy ( iob_put ( iobuf, mtu ), buf, mtu );
  214. /* Transmit packet */
  215. if ( ( rc = net_tx ( iob_disown ( iobuf ), sender,
  216. &lotest_protocol, receiver->ll_addr,
  217. sender->ll_addr ) ) != 0 ) {
  218. printf ( "\nFailed to transmit packet: %s",
  219. strerror ( rc ) );
  220. break;
  221. }
  222. /* Wait for received packet */
  223. if ( ( rc = loopback_wait ( buf, mtu ) ) != 0 )
  224. break;
  225. }
  226. printf ( "\n");
  227. /* Stop loopback testing */
  228. lotest_receiver = NULL;
  229. lotest_flush();
  230. /* Dump final statistics */
  231. ifstat ( sender );
  232. ifstat ( receiver );
  233. /* Free buffer */
  234. free ( buf );
  235. return 0;
  236. }