Browse Source

[lotest] Add loopback testing commands

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
1c7f47895c
6 changed files with 344 additions and 0 deletions
  1. 3
    0
      src/config/config.c
  2. 1
    0
      src/config/general.h
  3. 114
    0
      src/hci/commands/lotest_cmd.c
  4. 1
    0
      src/include/ipxe/errfile.h
  5. 210
    0
      src/usr/lotest.c
  6. 15
    0
      src/usr/lotest.h

+ 3
- 0
src/config/config.c View File

@@ -231,6 +231,9 @@ REQUIRE_OBJECT ( digest_cmd );
231 231
 #ifdef PXE_CMD
232 232
 REQUIRE_OBJECT ( pxe_cmd );
233 233
 #endif
234
+#ifdef LOTEST_CMD
235
+REQUIRE_OBJECT ( lotest_cmd );
236
+#endif
234 237
 
235 238
 /*
236 239
  * Drag in miscellaneous objects

+ 1
- 0
src/config/general.h View File

@@ -122,6 +122,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
122 122
 #define LOGIN_CMD		/* Login command */
123 123
 #undef	TIME_CMD		/* Time commands */
124 124
 #undef	DIGEST_CMD		/* Image crypto digest commands */
125
+#undef	LOTEST_CMD		/* Loopback testing commands */
125 126
 //#undef	PXE_CMD			/* PXE commands */
126 127
 
127 128
 /*

+ 114
- 0
src/hci/commands/lotest_cmd.c View File

@@ -0,0 +1,114 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <stdio.h>
22
+#include <stdlib.h>
23
+#include <string.h>
24
+#include <getopt.h>
25
+#include <ipxe/netdevice.h>
26
+#include <ipxe/command.h>
27
+#include <ipxe/if_ether.h>
28
+#include <usr/lotest.h>
29
+
30
+/** @file
31
+ *
32
+ * Loopback testing commands
33
+ *
34
+ */
35
+
36
+static void lotest_syntax ( char **argv ) {
37
+	printf ( "Usage:\n  %s <sending interface> <receiving interface>\n",
38
+		 argv[0] );
39
+}
40
+
41
+static int lotest_exec ( int argc, char **argv ) {
42
+	static struct option lotest_opts[] = {
43
+		{ "help", 0, NULL, 'h' },
44
+		{ "mtu", required_argument, NULL, 'm' },
45
+		{ NULL, 0, NULL, 0 },
46
+	};
47
+	const char *sender_name;
48
+	const char *receiver_name;
49
+	const char *mtu_text = NULL;
50
+	struct net_device *sender;
51
+	struct net_device *receiver;
52
+	char *endp;
53
+	size_t mtu;
54
+	int c;
55
+	int rc;
56
+
57
+	/* Parse command line */
58
+	while ( ( c = getopt_long ( argc, argv, "hm:", lotest_opts,
59
+				    NULL ) ) >= 0 ) {
60
+		switch ( c ) {
61
+		case 'm':
62
+			mtu_text = optarg;
63
+			break;
64
+		case 'h':
65
+			/* Display help text */
66
+		default:
67
+			/* Unrecognised/invalid option */
68
+			lotest_syntax ( argv );
69
+			return 1;
70
+		}
71
+	}
72
+	if ( optind != ( argc - 2 ) ) {
73
+		lotest_syntax ( argv );
74
+		return 1;
75
+	}
76
+	sender_name = argv[optind];
77
+	receiver_name = argv[optind + 1];
78
+
79
+	/* Identify network devices */
80
+	sender = find_netdev ( sender_name );
81
+	if ( ! sender ) {
82
+		printf ( "%s: no such interface\n", sender_name );
83
+		return 1;
84
+	}
85
+	receiver = find_netdev ( receiver_name );
86
+	if ( ! receiver ) {
87
+		printf ( "%s: no such interface\n", receiver_name );
88
+		return 1;
89
+	}
90
+
91
+	/* Identify MTU */
92
+	if ( mtu_text ) {
93
+		mtu = strtoul ( mtu_text, &endp, 10 );
94
+		if ( *endp ) {
95
+			printf ( "%s: invalid MTU\n", mtu_text );
96
+			return 1;
97
+		}
98
+	} else {
99
+		mtu = ETH_MAX_MTU;
100
+	}
101
+
102
+	/* Perform loopback test */
103
+	if ( ( rc = loopback_test ( sender, receiver, mtu ) ) != 0 ) {
104
+		printf ( "Test failed: %s\n", strerror ( rc ) );
105
+		return 1;
106
+	}
107
+
108
+	return 0;
109
+}
110
+
111
+struct command lotest_command __command = {
112
+	.name = "lotest",
113
+	.exec = lotest_exec,
114
+};

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -223,6 +223,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
223 223
 #define ERRFILE_ib_srpboot	      ( ERRFILE_OTHER | 0x00180000 )
224 224
 #define ERRFILE_iwmgmt		      ( ERRFILE_OTHER | 0x00190000 )
225 225
 #define ERRFILE_linux_smbios	      ( ERRFILE_OTHER | 0x001a0000 )
226
+#define ERRFILE_lotest		      ( ERRFILE_OTHER | 0x001b0000 )
226 227
 
227 228
 /** @} */
228 229
 

+ 210
- 0
src/usr/lotest.c View File

@@ -0,0 +1,210 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <stdint.h>
22
+#include <stdlib.h>
23
+#include <string.h>
24
+#include <stdio.h>
25
+#include <errno.h>
26
+#include <byteswap.h>
27
+#include <ipxe/iobuf.h>
28
+#include <ipxe/netdevice.h>
29
+#include <ipxe/if_ether.h>
30
+#include <ipxe/keys.h>
31
+#include <console.h>
32
+#include <usr/ifmgmt.h>
33
+#include <usr/lotest.h>
34
+
35
+/** @file
36
+ *
37
+ * Loopback testing
38
+ *
39
+ */
40
+
41
+#define LINK_WAIT_MS 15000
42
+
43
+/**
44
+ * Process received packet
45
+ *
46
+ * @v iobuf		I/O buffer
47
+ * @v netdev		Network device
48
+ * @v ll_source		Link-layer source address
49
+ * @ret rc		Return status code
50
+ */
51
+static int lotest_rx ( struct io_buffer *iobuf,
52
+		       struct net_device *netdev __unused,
53
+		       const void *ll_source __unused ) {
54
+	free_iob ( iobuf );
55
+	return -ENOTSUP;
56
+}
57
+
58
+/**
59
+ * Transcribe network-layer address
60
+ *
61
+ * @v net_addr		Network-layer address
62
+ * @ret string		Human-readable transcription of address
63
+ */
64
+static const char * lotest_ntoa ( const void *net_addr __unused ) {
65
+	return "<INVALID>";
66
+}
67
+
68
+/**
69
+ * Loopback test network-layer protocol
70
+ *
71
+ * Using a dedicated network-layer protocol avoids problems caused by
72
+ * cards supporting features such as IPv4 checksum offload trying to
73
+ * interpret the (randomly generated) network-layer content.
74
+ */
75
+static struct net_protocol lotest_protocol __net_protocol = {
76
+	.name = "LOTEST",
77
+	.rx = lotest_rx,
78
+	.ntoa = lotest_ntoa,
79
+	.net_proto = htons ( 0x6950 ), /* Not a genuine protocol number */
80
+	.net_addr_len = 0,
81
+};
82
+
83
+/**
84
+ * Perform loopback test between two network devices
85
+ *
86
+ * @v sender		Sending network device
87
+ * @v receiver		Received network device
88
+ * @v mtu		Packet size (excluding link-layer headers)
89
+ * @ret rc		Return status code
90
+ */
91
+int loopback_test ( struct net_device *sender, struct net_device *receiver,
92
+		    size_t mtu ) {
93
+	uint8_t buf[mtu];
94
+	struct io_buffer *iobuf;
95
+	const void *ll_dest;
96
+	const void *ll_source;
97
+	uint16_t net_proto;
98
+	unsigned int i;
99
+	unsigned int successes;
100
+	int rc;
101
+
102
+	/* Open network devices */
103
+	if ( ( rc = ifopen ( sender ) ) != 0 )
104
+		return rc;
105
+	if ( ( rc = ifopen ( receiver ) ) != 0 )
106
+		return rc;
107
+
108
+	/* Wait for link-up */
109
+	if ( ( rc = iflinkwait ( sender, LINK_WAIT_MS ) ) != 0 )
110
+		return rc;
111
+	if ( ( rc = iflinkwait ( receiver, LINK_WAIT_MS ) ) != 0 )
112
+		return rc;
113
+
114
+	/* Print initial statistics */
115
+	printf ( "Performing loopback test from %s to %s with %zd byte MTU\n",
116
+		 sender->name, receiver->name, mtu );
117
+	ifstat ( sender );
118
+	ifstat ( receiver );
119
+
120
+	/* Perform loopback test */
121
+	for ( successes = 0 ; ; successes++ ) {
122
+
123
+		/* Print running total */
124
+		printf ( "\r%d", successes );
125
+
126
+		/* Generate random packet */
127
+		for ( i = 0 ; i < sizeof ( buf ) ; i++ )
128
+			buf[i] = random();
129
+		iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( buf ) );
130
+		if ( ! iobuf ) {
131
+			printf ( "\nFailed to allocate I/O buffer" );
132
+			rc = -ENOMEM;
133
+			goto done;
134
+		}
135
+		iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
136
+		memcpy ( iob_put ( iobuf, sizeof ( buf ) ),
137
+			 buf, sizeof ( buf ) );
138
+
139
+		/* Transmit packet */
140
+		if ( ( rc = net_tx ( iob_disown ( iobuf ), sender,
141
+				     &lotest_protocol,
142
+				     receiver->ll_addr ) ) != 0 ) {
143
+			printf ( "\nFailed to transmit packet: %s",
144
+				 strerror ( rc ) );
145
+			goto done;
146
+		}
147
+
148
+		/* Poll until packet arrives */
149
+		do {
150
+			/* Check for cancellation */
151
+			if ( iskey() && ( getchar() == CTRL_C ) ) {
152
+				rc = -ECANCELED;
153
+				goto done;
154
+			}
155
+			/* Poll network devices */
156
+			netdev_poll ( sender );
157
+			netdev_poll ( receiver );
158
+		} while ( ( iobuf = netdev_rx_dequeue ( receiver ) ) == NULL );
159
+
160
+		/* Check received packet */
161
+		if ( ( rc = receiver->ll_protocol->pull ( receiver, iobuf,
162
+							  &ll_dest, &ll_source,
163
+							  &net_proto ) ) != 0 ){
164
+			printf ( "\nFailed to strip link-layer header: %s",
165
+				 strerror ( rc ) );
166
+			goto done;
167
+		}
168
+		if ( net_proto == lotest_protocol.net_proto ) {
169
+			if ( iob_len ( iobuf ) != sizeof ( buf ) ) {
170
+				printf ( "\nLength mismatch: sent %zd, "
171
+					 "received %zd",
172
+					 sizeof ( buf ), iob_len ( iobuf ) );
173
+				DBG ( "\nSent:\n" );
174
+				DBG_HDA ( 0, buf, sizeof ( buf ) );
175
+				DBG ( "Received:\n" );
176
+				DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
177
+				rc = -EINVAL;
178
+				goto done;
179
+			}
180
+			if ( memcmp ( iobuf->data, buf, sizeof ( buf ) ) != 0){
181
+				printf ( "\nContent mismatch" );
182
+				DBG ( "\nSent:\n" );
183
+				DBG_HDA ( 0, buf, sizeof ( buf ) );
184
+				DBG ( "Received:\n" );
185
+				DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
186
+				rc = -EINVAL;
187
+				goto done;
188
+			}
189
+		} else {
190
+			printf ( "\nReceived spurious packet type %04x\n",
191
+				 net_proto );
192
+			/* Continue; this allows for the fact that
193
+			 * there may have been packets outstanding on
194
+			 * the wire when we started the test.
195
+			 */
196
+		}
197
+
198
+		free_iob ( iob_disown ( iobuf ) );
199
+	}
200
+
201
+ done:
202
+	printf ( "\n");
203
+	free_iob ( iobuf );
204
+
205
+	/* Dump final statistics */
206
+	ifstat ( sender );
207
+	ifstat ( receiver );
208
+
209
+	return 0;
210
+}

+ 15
- 0
src/usr/lotest.h View File

@@ -0,0 +1,15 @@
1
+#ifndef _USR_LOTEST_H
2
+#define _USR_LOTEST_H
3
+
4
+/** @file
5
+ *
6
+ * Loopback testing
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+extern int loopback_test ( struct net_device *sender,
13
+			   struct net_device *receiver, size_t mtu );
14
+
15
+#endif /* _USR_LOTEST_H */

Loading…
Cancel
Save