iPXE
ipv4_test.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 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 (at your option) 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/** @file
27 *
28 * IPv4 tests
29 *
30 */
31
32/* Forcibly enable assertions */
33#undef NDEBUG
34
35#include <stdint.h>
36#include <string.h>
37#include <assert.h>
38#include <byteswap.h>
39#include <ipxe/in.h>
40#include <ipxe/ip.h>
41#include <ipxe/test.h>
42#include "netdev_test.h"
43
44/**
45 * Report an inet_ntoa() test result
46 *
47 * @v addr IPv4 address
48 * @v text Expected textual representation
49 * @v file Test code file
50 * @v line Test code line
51 */
52static void inet_ntoa_okx ( uint32_t addr, const char *text, const char *file,
53 unsigned int line ) {
54 struct in_addr in = { .s_addr = addr };
55 char *actual;
56
57 /* Format address */
58 actual = inet_ntoa ( in );
59 DBG ( "inet_ntoa ( %d.%d.%d.%d ) = %s\n",
60 ( ( ntohl ( addr ) >> 24 ) & 0xff ),
61 ( ( ntohl ( addr ) >> 16 ) & 0xff ),
62 ( ( ntohl ( addr ) >> 8 ) & 0xff ),
63 ( ( ntohl ( addr ) >> 0 ) & 0xff ), actual );
64 okx ( strcmp ( actual, text ) == 0, file, line );
65}
66#define inet_ntoa_ok( addr, text ) \
67 inet_ntoa_okx ( addr, text, __FILE__, __LINE__ )
68
69/**
70 * Report an inet_aton() test result
71 *
72 * @v text Textual representation
73 * @v addr Expected IPv4 address
74 * @v file Test code file
75 * @v line Test code line
76 */
77static void inet_aton_okx ( const char *text, uint32_t addr, const char *file,
78 unsigned int line ) {
79 struct in_addr actual;
80
81 /* Parse address */
82 okx ( inet_aton ( text, &actual ) != 0, file, line );
83 DBG ( "inet_aton ( \"%s\" ) = %s\n", text, inet_ntoa ( actual ) );
84 okx ( actual.s_addr == addr, file, line );
85};
86#define inet_aton_ok( text, addr ) \
87 inet_aton_okx ( text, addr, __FILE__, __LINE__ )
88
89/**
90 * Report an inet_aton() failure test result
91 *
92 * @v text Textual representation
93 * @v file Test code file
94 * @v line Test code line
95 */
96static void inet_aton_fail_okx ( const char *text, const char *file,
97 unsigned int line ) {
98 struct in_addr actual;
99
100 /* Attempt to parse address */
101 okx ( inet_aton ( text, &actual ) == 0, file, line );
102}
103#define inet_aton_fail_ok( text ) \
104 inet_aton_fail_okx ( text, __FILE__, __LINE__ )
105
106/**
107 * Report an ipv4_route() test result
108 *
109 * @v dest Destination address
110 * @v scope Destination scope test network device, or NULL
111 * @v next Expected next hop address (on success)
112 * @v egress Expected egress device, or NULL to expect failure
113 * @v src Expected source address (on success)
114 * @v bcast Expected broadcast packet (on success)
115 * @v file Test code file
116 * @v line Test code line
117 */
118static void ipv4_route_okx ( const char *dest, struct testnet *scope,
119 const char *next, struct testnet *egress,
120 const char *src, int bcast,
121 const char *file, unsigned int line ) {
122 struct ipv4_miniroute *miniroute;
123 struct in_addr in_dest;
124 struct in_addr in_src;
125 struct in_addr in_next;
126 struct in_addr actual;
127 unsigned int scope_id;
128
129 /* Sanity checks */
130 assert ( ( scope == NULL ) || ( scope->netdev != NULL ) );
131 assert ( ( egress == NULL ) == ( src == NULL ) );
132
133 /* Parse addresses */
134 okx ( inet_aton ( dest, &in_dest ) != 0, file, line );
135 if ( src )
136 okx ( inet_aton ( src, &in_src ) != 0, file, line );
137 if ( next ) {
138 okx ( inet_aton ( next, &in_next ) != 0, file, line );
139 } else {
140 in_next.s_addr = in_dest.s_addr;
141 }
142
143 /* Perform routing */
144 actual.s_addr = in_dest.s_addr;
145 scope_id = ( scope ? scope->netdev->scope_id : 0 );
146 miniroute = ipv4_route ( scope_id, &actual );
147
148 /* Validate result */
149 if ( src ) {
150
151 /* Check that a route was found */
152 okx ( miniroute != NULL, file, line );
153 DBG ( "ipv4_route ( %s, %s ) = %s",
154 ( scope ? scope->dev.name : "<any>" ), dest,
155 inet_ntoa ( actual ) );
156 DBG ( " from %s via %s\n",
157 inet_ntoa ( miniroute->address ), egress->dev.name );
158
159 /* Check that expected network device was used */
160 okx ( miniroute->netdev == egress->netdev, file, line );
161
162 /* Check that expected source address was used */
163 okx ( miniroute->address.s_addr == in_src.s_addr, file, line );
164
165 /* Check that expected next hop address was used */
166 okx ( actual.s_addr == in_next.s_addr, file, line );
167
168 /* Check that expected broadcast choice was used */
169 okx ( ( ! ( ( ~actual.s_addr ) & miniroute->hostmask.s_addr ) )
170 == ( !! bcast ), file, line );
171
172 } else {
173
174 /* Routing is expected to fail */
175 okx ( miniroute == NULL, file, line );
176 DBG ( "ipv4_route ( %s, %s ) = <unreachable>\n",
177 ( scope ? scope->dev.name : "<any>" ), dest );
178 }
179}
180#define ipv4_route_ok( dest, scope, next, egress, src, bcast ) \
181 ipv4_route_okx ( dest, scope, next, egress, src, bcast, \
182 __FILE__, __LINE__ )
183
184/** net0: Single address and gateway (DHCP assignment) */
185TESTNET ( net0, "52:54:00:59:ba:c9",
186 { "dhcp/ip", "192.168.0.1" },
187 { "dhcp/netmask", "255.255.255.0" },
188 { "dhcp/gateway", "192.168.0.254" } );
189
190/** net1: Single address and gateway (DHCP assignment) */
191TESTNET ( net1, "52:54:00:1a:db:95",
192 { "dhcp/ip", "192.168.0.2" },
193 { "dhcp/netmask", "255.255.255.0" },
194 { "dhcp/gateway", "192.168.0.254" } );
195
196/** net2: Small /31 subnet mask */
197TESTNET ( net2, "52:54:00:f9:ee:21",
198 { "ip", "10.31.31.0" },
199 { "netmask", "255.255.255.254" },
200 { "gateway", "10.31.31.1" } );
201
202/** net3: Small /32 subnet mask */
203TESTNET ( net3, "52:54:00:4a:88:ec",
204 { "ip", "10.32.32.32" },
205 { "netmask", "255.255.255.255" },
206 { "gateway", "192.168.32.254" } );
207
208/** net4: Local subnet with no gateway */
209TESTNET ( net4, "52:54:00:68:ad:cd",
210 { "ip", "192.168.86.1" },
211 { "netmask", "255.255.240.0" } );
212
213/** net5: Static routes */
214TESTNET ( net5, "52:54:00:b0:d5:07",
215 { "ip", "10.42.0.1" },
216 { "netmask", "255.255.0.0" },
217 { "gateway", "10.42.0.254" /* should be ignored */ },
218 { "static-routes",
219 "19:0a:2b:2b:80:0a:2a:2b:2b:" /* 10.43.43.128/25 via 10.42.43.43 */
220 "10:c0:a8:0a:2a:c0:a8:" /* 192.168.0.0/16 via 10.42.192.168 */
221 "18:c0:a8:00:00:00:00:00:" /* 192.168.0.0/24 on-link */
222 "00:0a:2a:01:01" /* default via 10.42.1.1 */ } );
223
224/**
225 * Perform IPv4 self-tests
226 *
227 */
228static void ipv4_test_exec ( void ) {
229
230 /* Address testing macros */
231 ok ( IN_IS_CLASSA ( IPV4 ( 10, 0, 0, 1 ) ) );
232 ok ( ! IN_IS_CLASSB ( IPV4 ( 10, 0, 0, 1 ) ) );
233 ok ( ! IN_IS_CLASSC ( IPV4 ( 10, 0, 0, 1 ) ) );
234 ok ( ! IN_IS_CLASSA ( IPV4 ( 172, 16, 0, 1 ) ) );
235 ok ( IN_IS_CLASSB ( IPV4 ( 172, 16, 0, 1 ) ) );
236 ok ( ! IN_IS_CLASSC ( IPV4 ( 172, 16, 0, 1 ) ) );
237 ok ( ! IN_IS_CLASSA ( IPV4 ( 192, 168, 0, 1 ) ) );
238 ok ( ! IN_IS_CLASSB ( IPV4 ( 192, 168, 0, 1 ) ) );
239 ok ( IN_IS_CLASSC ( IPV4 ( 192, 168, 0, 1 ) ) );
240 ok ( ! IN_IS_MULTICAST ( IPV4 ( 127, 0, 0, 1 ) ) );
241 ok ( ! IN_IS_MULTICAST ( IPV4 ( 8, 8, 8, 8 ) ) );
242 ok ( ! IN_IS_MULTICAST ( IPV4 ( 0, 0, 0, 0 ) ) );
243 ok ( ! IN_IS_MULTICAST ( IPV4 ( 223, 0, 0, 1 ) ) );
244 ok ( ! IN_IS_MULTICAST ( IPV4 ( 240, 0, 0, 1 ) ) );
245 ok ( IN_IS_MULTICAST ( IPV4 ( 224, 0, 0, 1 ) ) );
246 ok ( IN_IS_MULTICAST ( IPV4 ( 231, 89, 0, 2 ) ) );
247 ok ( IN_IS_MULTICAST ( IPV4 ( 239, 6, 1, 17 ) ) );
248
249 /* inet_ntoa() tests */
250 inet_ntoa_ok ( IPV4 ( 127, 0, 0, 1 ), "127.0.0.1" );
251 inet_ntoa_ok ( IPV4 ( 0, 0, 0, 0 ), "0.0.0.0" );
252 inet_ntoa_ok ( IPV4 ( 255, 255, 255, 255 ), "255.255.255.255" );
253 inet_ntoa_ok ( IPV4 ( 212, 13, 204, 60 ), "212.13.204.60" );
254
255 /* inet_aton() tests */
256 inet_aton_ok ( "212.13.204.60", IPV4 ( 212, 13, 204, 60 ) );
257 inet_aton_ok ( "127.0.0.1", IPV4 ( 127, 0, 0, 1 ) );
258
259 /* inet_aton() failure tests */
260 inet_aton_fail_ok ( "256.0.0.1" ); /* Byte out of range */
261 inet_aton_fail_ok ( "212.13.204.60.1" ); /* Too long */
262 inet_aton_fail_ok ( "127.0.0" ); /* Too short */
263 inet_aton_fail_ok ( "1.2.3.a" ); /* Invalid characters */
264 inet_aton_fail_ok ( "127.0..1" ); /* Missing bytes */
265
266 /* Single address and gateway */
267 testnet_ok ( &net0 );
268 ipv4_route_ok ( "192.168.0.10", NULL,
269 "192.168.0.10", &net0, "192.168.0.1", 0 );
270 ipv4_route_ok ( "10.0.0.6", NULL,
271 "192.168.0.254", &net0, "192.168.0.1", 0 );
272 ipv4_route_ok ( "192.168.0.255", NULL,
273 "192.168.0.255", &net0, "192.168.0.1", 1 );
274 testnet_remove_ok ( &net0 );
275
276 /* Overridden DHCP-assigned address */
277 testnet_ok ( &net1 );
278 ipv4_route_ok ( "192.168.1.3", NULL,
279 "192.168.0.254", &net1, "192.168.0.2", 0 );
280 testnet_set_ok ( &net1, "ip", "192.168.1.2" );
281 ipv4_route_ok ( "192.168.1.3", NULL,
282 "192.168.1.3", &net1, "192.168.1.2", 0 );
283 testnet_remove_ok ( &net1 );
284
285 /* Small /31 subnet */
286 testnet_ok ( &net2 );
287 ipv4_route_ok ( "10.31.31.1", NULL,
288 "10.31.31.1", &net2, "10.31.31.0", 0 );
289 ipv4_route_ok ( "212.13.204.60", NULL,
290 "10.31.31.1", &net2, "10.31.31.0", 0 );
291 testnet_remove_ok ( &net2 );
292
293 /* Small /32 subnet */
294 testnet_ok ( &net3 );
295 ipv4_route_ok ( "10.32.32.31", NULL,
296 "192.168.32.254", &net3, "10.32.32.32", 0 );
297 ipv4_route_ok ( "8.8.8.8", NULL,
298 "192.168.32.254", &net3, "10.32.32.32", 0 );
299 testnet_remove_ok ( &net3 );
300
301 /* No gateway */
302 testnet_ok ( &net4 );
303 ipv4_route_ok ( "192.168.87.1", NULL,
304 "192.168.87.1", &net4, "192.168.86.1", 0 );
305 ipv4_route_ok ( "192.168.96.1", NULL, NULL, NULL, NULL, 0 );
306 testnet_remove_ok ( &net4 );
307
308 /* Multiple interfaces */
309 testnet_ok ( &net0 );
310 testnet_ok ( &net1 );
311 testnet_ok ( &net2 );
312 testnet_close_ok ( &net1 );
313 ipv4_route_ok ( "192.168.0.9", NULL,
314 "192.168.0.9", &net0, "192.168.0.1", 0 );
315 ipv4_route_ok ( "10.31.31.1", NULL,
316 "10.31.31.1", &net2, "10.31.31.0", 0 );
317 testnet_close_ok ( &net0 );
318 testnet_open_ok ( &net1 );
319 ipv4_route_ok ( "192.168.0.9", NULL,
320 "192.168.0.9", &net1, "192.168.0.2", 0 );
321 ipv4_route_ok ( "10.31.31.1", NULL,
322 "10.31.31.1", &net2, "10.31.31.0", 0 );
323 testnet_close_ok ( &net2 );
324 ipv4_route_ok ( "8.8.8.8", NULL,
325 "192.168.0.254", &net1, "192.168.0.2", 0 );
326 testnet_close_ok ( &net1 );
327 testnet_open_ok ( &net0 );
328 ipv4_route_ok ( "8.8.8.8", NULL,
329 "192.168.0.254", &net0, "192.168.0.1", 0 );
330 testnet_close_ok ( &net0 );
331 testnet_open_ok ( &net2 );
332 ipv4_route_ok ( "8.8.8.8", NULL,
333 "10.31.31.1", &net2, "10.31.31.0", 0 );
334 testnet_remove_ok ( &net2 );
335 testnet_remove_ok ( &net1 );
336 testnet_remove_ok ( &net0 );
337
338 /* Static routes */
339 testnet_ok ( &net5 );
340 ipv4_route_ok ( "10.42.99.0", NULL,
341 "10.42.99.0", &net5, "10.42.0.1", 0 );
342 ipv4_route_ok ( "8.8.8.8", NULL,
343 "10.42.1.1", &net5, "10.42.0.1", 0 );
344 ipv4_route_ok ( "10.43.43.1", NULL,
345 "10.42.1.1", &net5, "10.42.0.1", 0 );
346 ipv4_route_ok ( "10.43.43.129", NULL,
347 "10.42.43.43", &net5, "10.42.0.1", 0 );
348 ipv4_route_ok ( "192.168.54.8", NULL,
349 "10.42.192.168", &net5, "10.42.0.1", 0 );
350 ipv4_route_ok ( "192.168.0.8", NULL,
351 "192.168.0.8", &net5, "10.42.0.1", 0 );
352 ipv4_route_ok ( "192.168.0.255", NULL,
353 "192.168.0.255", &net5, "10.42.0.1", 1 );
354 testnet_remove_ok ( &net5 );
355}
356
357/** IPv4 self-test */
358struct self_test ipv4_test __self_test = {
359 .name = "ipv4",
360 .exec = ipv4_test_exec,
361};
#define NULL
NULL pointer (VOID *).
Definition Base.h:321
__be32 in[4]
Definition CIB_PRM.h:7
unsigned int uint32_t
Definition stdint.h:12
if(len >=6 *4) __asm__ __volatile__("movsl" if(len >=5 *4) __asm__ __volatile__("movsl" if(len >=4 *4) __asm__ __volatile__("movsl" if(len >=3 *4) __asm__ __volatile__("movsl" if(len >=2 *4) __asm__ __volatile__("movsl" if(len >=1 *4) __asm__ __volatile__("movsl" if((len % 4) >=2) __asm__ __volatile__("movsw" if((len % 2) >=1) __asm__ __volatile__("movsb" retur dest)
Definition string.h:151
static const void * src
Definition string.h:48
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:61
uint32_t next
Next descriptor address.
Definition dwmac.h:11
uint32_t addr
Buffer address.
Definition dwmac.h:9
uint8_t scope
Scope.
Definition ena.h:7
#define DBG(...)
Print a debugging message.
Definition compiler.h:523
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:921
#define IN_IS_CLASSB(addr)
Definition in.h:30
#define IN_IS_CLASSA(addr)
Definition in.h:28
#define IN_IS_CLASSC(addr)
Definition in.h:32
#define IN_IS_MULTICAST(addr)
Definition in.h:34
#define ntohl(value)
Definition byteswap.h:135
String functions.
IP protocol.
#define IPV4(a, b, c, d)
Construct a literal IPv4 address.
Definition ip.h:36
struct ipv4_miniroute * ipv4_route(unsigned int scope_id, struct in_addr *dest)
Perform IPv4 routing.
Definition ipv4.c:311
char * inet_ntoa(struct in_addr in)
Convert IPv4 address to dotted-quad notation.
Definition ipv4.c:816
int inet_aton(const char *string, struct in_addr *in)
Parse IPv4 address.
Definition ipv4.c:789
static void inet_ntoa_okx(uint32_t addr, const char *text, const char *file, unsigned int line)
Report an inet_ntoa() test result.
Definition ipv4_test.c:52
static void ipv4_route_okx(const char *dest, struct testnet *scope, const char *next, struct testnet *egress, const char *src, int bcast, const char *file, unsigned int line)
Report an ipv4_route() test result.
Definition ipv4_test.c:118
#define inet_aton_fail_ok(text)
Definition ipv4_test.c:103
#define inet_aton_ok(text, addr)
Definition ipv4_test.c:86
static void ipv4_test_exec(void)
Perform IPv4 self-tests.
Definition ipv4_test.c:228
#define ipv4_route_ok(dest, scope, next, egress, src, bcast)
Definition ipv4_test.c:180
static void inet_aton_okx(const char *text, uint32_t addr, const char *file, unsigned int line)
Report an inet_aton() test result.
Definition ipv4_test.c:77
static void inet_aton_fail_okx(const char *text, const char *file, unsigned int line)
Report an inet_aton() failure test result.
Definition ipv4_test.c:96
#define inet_ntoa_ok(addr, text)
Definition ipv4_test.c:66
Network device tests.
#define testnet_ok(testnet)
Report a network device creation test result.
Definition netdev_test.h:68
#define testnet_open_ok(testnet)
Report a network device opening test result.
Definition netdev_test.h:77
#define testnet_set_ok(testnet, name, value)
Report a network device setting test result.
Definition netdev_test.h:89
#define TESTNET(NAME, HWADDR,...)
Declare a test network device.
Definition netdev_test.h:44
#define testnet_close_ok(testnet)
Report a network device closing test result.
#define testnet_remove_ok(testnet)
Report a network device removal test result.
int strcmp(const char *first, const char *second)
Compare strings.
Definition string.c:174
char name[40]
Name.
Definition device.h:79
IP address structure.
Definition in.h:42
uint32_t s_addr
Definition in.h:43
An IPv4 address/routing table entry.
Definition ip.h:71
struct net_device * netdev
Network device.
Definition ip.h:80
struct in_addr address
IPv4 address.
Definition ip.h:91
struct in_addr hostmask
Host mask.
Definition ip.h:141
A self-test set.
Definition test.h:15
A test network device.
Definition netdev_test.h:24
struct net_device * netdev
Network device.
Definition netdev_test.h:26
struct device dev
Dummy physical device.
Definition netdev_test.h:28
Self-test infrastructure.
#define okx(success, file, line)
Report test result.
Definition test.h:44
#define ok(success)
Definition test.h:46
#define __self_test
Declare a self-test.
Definition test.h:32