iPXE
lotest.c
Go to the documentation of this file.
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
24FILE_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 */
48
49/** Loopback testing received packets */
50static 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 */
62static 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 */
83static 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 */
101static 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 */
112static 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 */
124static 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 */
138static 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 * @v broadcast Use broadcast link-layer address
192 * @ret rc Return status code
193 */
194int loopback_test ( struct net_device *sender, struct net_device *receiver,
195 size_t mtu, int broadcast ) {
196 uint8_t *buf;
197 uint32_t *seq;
198 struct io_buffer *iobuf;
199 const void *ll_dest;
200 unsigned int i;
201 unsigned int successes;
202 int rc;
203
204 /* Open network devices */
205 if ( ( rc = ifopen ( sender ) ) != 0 )
206 return rc;
207 if ( ( rc = ifopen ( receiver ) ) != 0 )
208 return rc;
209
210 /* Wait for link-up */
211 if ( ( rc = iflinkwait ( sender, 0, 0 ) ) != 0 )
212 return rc;
213 if ( ( rc = iflinkwait ( receiver, 0, 0 ) ) != 0 )
214 return rc;
215
216 /* Allocate data buffer */
217 if ( mtu < sizeof ( *seq ) )
218 mtu = sizeof ( *seq );
219 buf = malloc ( mtu );
220 if ( ! buf )
221 return -ENOMEM;
222 seq = ( ( void * ) buf );
223
224 /* Determine destination address */
225 ll_dest = ( broadcast ? sender->ll_broadcast : receiver->ll_addr );
226
227 /* Print initial statistics */
228 printf ( "Performing %sloopback test from %s to %s with %zd byte MTU\n",
229 ( broadcast ? "broadcast " : "" ), sender->name,
230 receiver->name, mtu );
231 ifstat ( sender );
232 ifstat ( receiver );
233
234 /* Start loopback test */
235 lotest_flush();
236 lotest_receiver = receiver;
237
238 /* Perform loopback test */
239 for ( successes = 0 ; ; successes++ ) {
240
241 /* Print running total */
242 printf ( "\r%d", successes );
243
244 /* Generate random packet */
245 *seq = htonl ( successes );
246 for ( i = sizeof ( *seq ) ; i < mtu ; i++ )
247 buf[i] = random();
248 iobuf = alloc_iob ( MAX_LL_HEADER_LEN + mtu );
249 if ( ! iobuf ) {
250 printf ( "\nFailed to allocate I/O buffer" );
251 rc = -ENOMEM;
252 break;
253 }
255 memcpy ( iob_put ( iobuf, mtu ), buf, mtu );
256
257 /* Transmit packet */
258 if ( ( rc = net_tx ( iob_disown ( iobuf ), sender,
259 &lotest_protocol, ll_dest,
260 sender->ll_addr ) ) != 0 ) {
261 printf ( "\nFailed to transmit packet: %s",
262 strerror ( rc ) );
263 break;
264 }
265
266 /* Wait for received packet */
267 if ( ( rc = loopback_wait ( buf, mtu ) ) != 0 )
268 break;
269 }
270
271 printf ( "\n");
272
273 /* Stop loopback testing */
275 lotest_flush();
276
277 /* Dump final statistics */
278 ifstat ( sender );
279 ifstat ( receiver );
280
281 /* Free buffer */
282 free ( buf );
283
284 return 0;
285}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned int uint32_t
Definition stdint.h:12
unsigned char uint8_t
Definition stdint.h:10
int getchar(void)
Read a single character from any console.
Definition console.c:86
int iskey(void)
Check for available input on any console.
Definition console.c:131
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint32_t mtu
Maximum MTU.
Definition ena.h:17
uint8_t flags
Flags.
Definition ena.h:7
Error codes.
static struct net_device * netdev
Definition gdbudp.c:53
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBG_HDA(...)
Definition compiler.h:499
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ECANCELED
Operation canceled.
Definition errno.h:344
u16 seq
802.11 Sequence Control field
Definition ieee80211.h:5
int ifopen(struct net_device *netdev)
Open network device.
Definition ifmgmt.c:66
int iflinkwait(struct net_device *netdev, unsigned long timeout, int verbose)
Wait for link-up, with status indication.
Definition ifmgmt.c:220
void ifstat(struct net_device *netdev)
Print status of network device.
Definition ifmgmt.c:111
Network interface management.
#define htonl(value)
Definition byteswap.h:134
#define htons(value)
Definition byteswap.h:136
User interaction.
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
I/O buffers.
#define iob_put(iobuf, len)
Definition iobuf.h:125
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition iobuf.h:217
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
#define iob_reserve(iobuf, len)
Definition iobuf.h:72
Key definitions.
#define CTRL_C
Definition keys.h:21
#define list_first_entry(list, type, member)
Get the container of the first entry in a list.
Definition list.h:334
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition list.h:94
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
#define LIST_HEAD(list)
Declare a static list head.
Definition list.h:38
static int loopback_wait(void *data, size_t len)
Wait for packet to be received.
Definition lotest.c:138
static void lotest_flush(void)
Discard all received loopback test packets.
Definition lotest.c:124
static struct io_buffer * lotest_dequeue(void)
Dequeue received packet.
Definition lotest.c:83
static const char * lotest_ntoa(const void *net_addr __unused)
Transcribe network-layer address.
Definition lotest.c:101
int loopback_test(struct net_device *sender, struct net_device *receiver, size_t mtu, int broadcast)
Perform loopback test between two network devices.
Definition lotest.c:194
static int lotest_rx(struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest __unused, const void *ll_source __unused, unsigned int flags __unused)
Process received packet.
Definition lotest.c:62
static struct net_device * lotest_receiver
Current loopback test receiver.
Definition lotest.c:47
Loopback testing.
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:621
int net_tx(struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest, const void *ll_source)
Transmit network-layer packet.
Definition netdevice.c:1074
void net_poll(void)
Poll the network stack.
Definition netdevice.c:1127
Network device management.
#define MAX_LL_HEADER_LEN
Maximum length of a link-layer header.
Definition netdevice.h:46
#define __net_protocol
Declare a network-layer protocol.
Definition netdevice.h:474
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition random.c:32
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
struct stp_switch sender
Sender switch.
Definition stp.h:19
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
struct list_head list
List of which this buffer is a member.
Definition iobuf.h:45
A network device.
Definition netdevice.h:353
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition netdevice.h:363
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
Definition netdevice.h:388
A network-layer protocol.
Definition netdevice.h:65
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition vsprintf.c:465