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