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