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