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 
24 FILE_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  */
56 static 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  */
81 static 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  */
100 static 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  */
122 static 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) */
189 TESTNET ( 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) */
195 TESTNET ( 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 */
201 TESTNET ( 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 */
207 TESTNET ( 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 */
213 TESTNET ( net4,
214  { "ip", "192.168.86.1" },
215  { "netmask", "255.255.240.0" } );
216 
217 /** net5: Static routes */
218 TESTNET ( 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  */
232 static 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 */
362 struct self_test ipv4_test __self_test = {
363  .name = "ipv4",
364  .exec = ipv4_test_exec,
365 };
#define ipv4_route_ok(dest, scope, next, egress, src, bcast)
Definition: ipv4_test.c:184
#define IN_IS_CLASSA(addr)
Definition: in.h:27
struct device dev
Dummy physical device.
Definition: netdev_test.h:28
__be32 in[4]
Definition: CIB_PRM.h:35
A test network device.
Definition: netdev_test.h:24
uint8_t scope
Scope.
Definition: ena.h:18
#define testnet_set_ok(testnet, name, value)
Report a network device setting test result.
Definition: netdev_test.h:85
#define testnet_open_ok(testnet)
Report a network device opening test result.
Definition: netdev_test.h:73
struct net_device * netdev
Network device.
Definition: ip.h:72
struct net_device * netdev
Network device.
Definition: netdev_test.h:26
#define IN_IS_CLASSB(addr)
Definition: in.h:29
#define testnet_remove_ok(testnet)
Report a network device removal test result.
Definition: netdev_test.h:106
char name[40]
Name.
Definition: device.h:78
#define ntohl(value)
Definition: byteswap.h:134
Self-test infrastructure.
IP protocol.
const char * name
Test set name.
Definition: test.h:17
#define testnet_close_ok(testnet)
Report a network device closing test result.
Definition: netdev_test.h:96
A self-test set.
Definition: test.h:15
struct in_addr address
IPv4 address.
Definition: ip.h:83
struct in_addr hostmask
Host mask.
Definition: ip.h:133
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
struct self_test ipv4_test __self_test
IPv4 self-test.
Definition: ipv4_test.c:362
#define okx(success, file, line)
Report test result.
Definition: test.h:44
Assertions.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
static const void * src
Definition: string.h:47
An IPv4 address/routing table entry.
Definition: ip.h:63
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_ok(text, addr)
Definition: ipv4_test.c:90
struct ipv4_miniroute * ipv4_route(unsigned int scope_id, struct in_addr *dest)
Perform IPv4 routing.
Definition: ipv4.c:309
IP address structure.
Definition: in.h:41
uint32_t addr
Buffer address.
Definition: dwmac.h:20
int inet_aton(const char *string, struct in_addr *in)
Parse IPv4 address.
Definition: ipv4.c:786
char * inet_ntoa(struct in_addr in)
Convert IPv4 address to dotted-quad notation.
Definition: ipv4.c:813
#define inet_ntoa_ok(addr, text)
Definition: ipv4_test.c:70
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
unsigned int uint32_t
Definition: stdint.h:12
uint32_t next
Next descriptor address.
Definition: dwmac.h:22
#define testnet_ok(testnet)
Report a network device creation test result.
Definition: netdev_test.h:64
uint32_t s_addr
Definition: in.h:42
#define IPV4(a, b, c, d)
Define inline IPv4 address.
Definition: ipv4_test.c:45
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
int strcmp(const char *first, const char *second)
Compare strings.
Definition: string.c:173
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" return dest
Definition: string.h:150
#define inet_aton_fail_ok(text)
Definition: ipv4_test.c:107
#define IN_IS_MULTICAST(addr)
Definition: in.h:33
static void ipv4_test_exec(void)
Perform IPv4 self-tests.
Definition: ipv4_test.c:232
TESTNET(net0, { "dhcp/ip", "192.168.0.1" }, { "dhcp/netmask", "255.255.255.0" }, { "dhcp/gateway", "192.168.0.254" })
net0: Single address and gateway (DHCP assignment)
#define IN_IS_CLASSC(addr)
Definition: in.h:31
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
Network device tests.
#define ok(success)
Definition: test.h:46
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
String functions.
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