xref: /dpdk/app/test/test_cmdline_ipaddr.c (revision e9d48c0072d36eb6423b45fba4ec49d0def6c36f)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <stdio.h>
35 #include <string.h>
36 #include <inttypes.h>
37 #include <netinet/in.h>
38 
39 #ifndef __linux__
40 #include <net/socket.h>
41 #endif
42 
43 #include <rte_string_fns.h>
44 
45 #include <cmdline_parse.h>
46 #include <cmdline_parse_ipaddr.h>
47 
48 #include "test_cmdline.h"
49 
50 #define IP4(a,b,c,d) {((uint32_t)(((a) & 0xff)) | \
51 					   (((b) & 0xff) << 8) | \
52 					   (((c) & 0xff) << 16)  | \
53 					   ((d) & 0xff)  << 24)}
54 
55 #define U16_SWAP(x) \
56 		(((x & 0xFF) << 8) | ((x & 0xFF00) >> 8))
57 
58 /* create IPv6 address, swapping bytes where needed */
59 #define IP6(a,b,c,d,e,f,g,h) .ipv6 = \
60 		{.s6_addr16 = \
61 		{U16_SWAP(a),U16_SWAP(b),U16_SWAP(c),U16_SWAP(d),\
62 		 U16_SWAP(e),U16_SWAP(f),U16_SWAP(g),U16_SWAP(h)}}
63 
64 /** these are defined in netinet/in.h but not present in linux headers */
65 #ifdef __linux__
66 #define NIPQUAD_FMT "%u.%u.%u.%u"
67 #define NIPQUAD(addr)				\
68 	(unsigned)((unsigned char *)&addr)[0],	\
69 	(unsigned)((unsigned char *)&addr)[1],	\
70 	(unsigned)((unsigned char *)&addr)[2],	\
71 	(unsigned)((unsigned char *)&addr)[3]
72 
73 #define NIP6_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"
74 #define NIP6(addr)					\
75 	(unsigned)((addr).s6_addr[0]),			\
76 	(unsigned)((addr).s6_addr[1]),			\
77 	(unsigned)((addr).s6_addr[2]),			\
78 	(unsigned)((addr).s6_addr[3]),			\
79 	(unsigned)((addr).s6_addr[4]),			\
80 	(unsigned)((addr).s6_addr[5]),			\
81 	(unsigned)((addr).s6_addr[6]),			\
82 	(unsigned)((addr).s6_addr[7]),			\
83 	(unsigned)((addr).s6_addr[8]),			\
84 	(unsigned)((addr).s6_addr[9]),			\
85 	(unsigned)((addr).s6_addr[10]),			\
86 	(unsigned)((addr).s6_addr[11]),			\
87 	(unsigned)((addr).s6_addr[12]),			\
88 	(unsigned)((addr).s6_addr[13]),			\
89 	(unsigned)((addr).s6_addr[14]),			\
90 	(unsigned)((addr).s6_addr[15])
91 #endif
92 
93 
94 
95 struct ipaddr_str {
96 	const char * str;
97 	cmdline_ipaddr_t addr;
98 	unsigned flags;
99 };
100 
101 const struct ipaddr_str ipaddr_valid_strs[] = {
102 		{"0.0.0.0", {AF_INET, {IP4(0,0,0,0)}, 0},
103 				CMDLINE_IPADDR_V4},
104 		{"0.0.0.0/0", {AF_INET, {IP4(0,0,0,0)}, 0},
105 				CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
106 		{"0.0.0.0/24", {AF_INET, {IP4(0,0,0,0)}, 24},
107 				CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
108 		{"192.168.1.0/24", {AF_INET, {IP4(192,168,1,0)}, 24},
109 				CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
110 		{"012.34.56.78/24", {AF_INET, {IP4(12,34,56,78)}, 24},
111 				CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
112 		{"34.56.78.90/1", {AF_INET, {IP4(34,56,78,90)}, 1},
113 				CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
114 		{"::", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 0},
115 					CMDLINE_IPADDR_V6},
116 		{"::1", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 0},
117 				CMDLINE_IPADDR_V6},
118 		{"::1/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 32},
119 				CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
120 		{"::/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 32},
121 					CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
122 		/* RFC5952 requests that only lowercase should be used */
123 		{"1234:5678:90ab:cdef:4321:8765:BA09:FEDC", {AF_INET6,
124 				{IP6(0x1234,0x5678,0x90AB,0xCDEF,0x4321,0x8765,0xBA09,0xFEDC)},
125 				0},
126 				CMDLINE_IPADDR_V6},
127 		{"1234::1234/64", {AF_INET6,
128 				{IP6(0x1234,0,0,0,0,0,0,0x1234)},
129 				64},
130 				CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
131 		{"1234::/64", {AF_INET6,
132 				{IP6(0x1234,0,0,0,0,0,0,0)},
133 				64},
134 				CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
135 		{"1:1::1/32", {AF_INET6,
136 				{IP6(1,1,0,0,0,0,0,1)},
137 				32},
138 				CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
139 		{"1:2:3:4::/64", {AF_INET6,
140 				{IP6(1,2,3,4,0,0,0,0)},
141 				64},
142 			CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
143 		{"::ffff:192.168.1.0/64", {AF_INET6,
144 				{IP6(0,0,0,0,0,0xFFFF,0xC0A8,0x100)},
145 				64},
146 			CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
147 		/* RFC5952 requests not using :: to skip one block of zeros*/
148 		{"1::2:3:4:5:6:7", {AF_INET6,
149 				{IP6(1,0,2,3,4,5,6,7)},
150 				0},
151 			CMDLINE_IPADDR_V6},
152 };
153 
154 const char * ipaddr_garbage_addr4_strs[] = {
155 		/* IPv4 */
156 		"192.168.1.0 garbage",
157 		"192.168.1.0\0garbage",
158 		"192.168.1.0#garbage",
159 		"192.168.1.0\tgarbage",
160 		"192.168.1.0\rgarbage",
161 		"192.168.1.0\ngarbage",
162 };
163 #define IPv4_GARBAGE_ADDR IP4(192,168,1,0)
164 
165 const char * ipaddr_garbage_addr6_strs[] = {
166 		/* IPv6 */
167 		"1:2:3:4::8 garbage",
168 		"1:2:3:4::8#garbage",
169 		"1:2:3:4::8\0garbage",
170 		"1:2:3:4::8\rgarbage",
171 		"1:2:3:4::8\ngarbage",
172 		"1:2:3:4::8\tgarbage",
173 };
174 #define IPv6_GARBAGE_ADDR {IP6(1,2,3,4,0,0,0,8)}
175 
176 const char * ipaddr_garbage_network4_strs[] = {
177 		/* IPv4 */
178 		"192.168.1.0/24 garbage",
179 		"192.168.1.0/24\0garbage",
180 		"192.168.1.0/24#garbage",
181 		"192.168.1.0/24\tgarbage",
182 		"192.168.1.0/24\rgarbage",
183 		"192.168.1.0/24\ngarbage",
184 };
185 #define IPv4_GARBAGE_PREFIX 24
186 
187 const char * ipaddr_garbage_network6_strs[] = {
188 		/* IPv6 */
189 		"1:2:3:4::8/64 garbage",
190 		"1:2:3:4::8/64#garbage",
191 		"1:2:3:4::8/64\0garbage",
192 		"1:2:3:4::8/64\rgarbage",
193 		"1:2:3:4::8/64\ngarbage",
194 		"1:2:3:4::8/64\tgarbage",
195 };
196 #define IPv6_GARBAGE_PREFIX 64
197 
198 
199 
200 const char * ipaddr_invalid_strs[] = {
201 		/** IPv4 **/
202 
203 		/* invalid numbers */
204 		"0.0.0.-1",
205 		"0.0.-1.0",
206 		"0.-1.0.0",
207 		"-1.0.0.0",
208 		"0.0.0.-1/24",
209 		"256.123.123.123",
210 		"255.256.123.123",
211 		"255.255.256.123",
212 		"255.255.255.256",
213 		"256.123.123.123/24",
214 		"255.256.123.123/24",
215 		"255.255.256.123/24",
216 		"255.255.255.256/24",
217 		/* invalid network mask */
218 		"1.2.3.4/33",
219 		"1.2.3.4/33231313",
220 		"1.2.3.4/-1",
221 		"1.2.3.4/24/33",
222 		"1.2.3.4/24/-1",
223 		"1.2.3.4/24/",
224 		/* wrong format */
225 		"1/24"
226 		"/24"
227 		"123.123.123",
228 		"123.123.123.",
229 		"123.123.123.123.",
230 		"123.123.123..123",
231 		"123.123.123.123.123",
232 		".123.123.123",
233 		".123.123.123.123",
234 		"123.123.123/24",
235 		"123.123.123./24",
236 		"123.123.123.123./24",
237 		"123.123.123..123/24",
238 		"123.123.123.123.123/24",
239 		".123.123.123/24",
240 		".123.123.123.123/24",
241 		/* invalid characters */
242 		"123.123.123.12F",
243 		"123.123.12F.123",
244 		"123.12F.123.123",
245 		"12F.123.123.123",
246 		"12J.123.123.123",
247 		"123,123,123,123",
248 		"123!123!123!12F",
249 		"123.123.123.123/4F",
250 
251 		/** IPv6 **/
252 
253 		/* wrong format */
254 		"::fffff",
255 		"ffff:",
256 		"1:2:3:4:5:6:7:192.168.1.1",
257 		"1234:192.168.1.1:ffff::",
258 		"1:2:3:4:5:6:7:890ab",
259 		"1:2:3:4:5:6:7890a:b",
260 		"1:2:3:4:5:67890:a:b",
261 		"1:2:3:4:56789:0:a:b",
262 		"1:2:3:45678:9:0:a:b",
263 		"1:2:34567:8:9:0:a:b",
264 		"1:23456:7:8:9:0:a:b",
265 		"12345:6:7:8:9:0:a:b",
266 		"1:::2",
267 		"1::::2",
268 		"::fffff/64",
269 		"1::2::3",
270 		"1::2::3/64",
271 		":1:2",
272 		":1:2/64",
273 		":1::2",
274 		":1::2/64",
275 		"1::2:3:4:5:6:7:8/64",
276 
277 		/* invalid network mask */
278 		"1:2:3:4:5:6:7:8/129",
279 		"1:2:3:4:5:6:7:8/-1",
280 
281 		/* invalid characters */
282 		"a:b:c:d:e:f:g::",
283 
284 		/** misc **/
285 
286 		/* too long */
287 		"1234:1234:1234:1234:1234:1234:1234:1234:1234:1234:1234"
288 		"random invalid text",
289 		"",
290 		"\0",
291 		" ",
292 };
293 
294 #define IPADDR_VALID_STRS_SIZE \
295 	(sizeof(ipaddr_valid_strs) / sizeof(ipaddr_valid_strs[0]))
296 #define IPADDR_GARBAGE_ADDR4_STRS_SIZE \
297 	(sizeof(ipaddr_garbage_addr4_strs) / sizeof(ipaddr_garbage_addr4_strs[0]))
298 #define IPADDR_GARBAGE_ADDR6_STRS_SIZE \
299 	(sizeof(ipaddr_garbage_addr6_strs) / sizeof(ipaddr_garbage_addr6_strs[0]))
300 #define IPADDR_GARBAGE_NETWORK4_STRS_SIZE \
301 	(sizeof(ipaddr_garbage_network4_strs) / sizeof(ipaddr_garbage_network4_strs[0]))
302 #define IPADDR_GARBAGE_NETWORK6_STRS_SIZE \
303 	(sizeof(ipaddr_garbage_network6_strs) / sizeof(ipaddr_garbage_network6_strs[0]))
304 #define IPADDR_INVALID_STRS_SIZE \
305 	(sizeof(ipaddr_invalid_strs) / sizeof(ipaddr_invalid_strs[0]))
306 
307 static void
308 dump_addr(cmdline_ipaddr_t addr)
309 {
310 	switch (addr.family) {
311 	case AF_INET:
312 	{
313 		printf(NIPQUAD_FMT " prefixlen=%u\n",
314 				NIPQUAD(addr.addr.ipv4.s_addr), addr.prefixlen);
315 		break;
316 	}
317 	case AF_INET6:
318 	{
319 		printf(NIP6_FMT " prefixlen=%u\n",
320 				NIP6(addr.addr.ipv6), addr.prefixlen);
321 		break;
322 	}
323 	default:
324 		printf("Can't dump: unknown address family.\n");
325 		return;
326 	}
327 }
328 
329 
330 static int
331 is_addr_different(cmdline_ipaddr_t addr1, cmdline_ipaddr_t addr2)
332 {
333 	if (addr1.family != addr2.family)
334 		return 1;
335 
336 	if (addr1.prefixlen != addr2.prefixlen)
337 		return 1;
338 
339 	switch (addr1.family) {
340 	/* IPv4 */
341 	case AF_INET:
342 		if (memcmp(&addr1.addr.ipv4, &addr2.addr.ipv4,
343 				sizeof(struct in_addr)) != 0)
344 			return 1;
345 		break;
346 	/* IPv6 */
347 	case AF_INET6:
348 	{
349 		if (memcmp(&addr1.addr.ipv6, &addr2.addr.ipv6,
350 				sizeof(struct in6_addr)) != 0)
351 			return 1;
352 		break;
353 	}
354 	/* thing that should not be */
355 	default:
356 		return -1;
357 	}
358 	return 0;
359 }
360 
361 static int
362 can_parse_addr(unsigned addr_flags, unsigned test_flags)
363 {
364 	if ((test_flags & addr_flags) == addr_flags) {
365 		/* if we are not trying to parse network addresses */
366 		if (test_flags < CMDLINE_IPADDR_NETWORK)
367 			return 1;
368 		/* if this is a network address */
369 		else if (addr_flags & CMDLINE_IPADDR_NETWORK)
370 			return 1;
371 	}
372 	return 0;
373 }
374 
375 int
376 test_parse_ipaddr_valid(void)
377 {
378 	cmdline_parse_token_ipaddr_t token;
379 	char buf[CMDLINE_TEST_BUFSIZE];
380 	cmdline_ipaddr_t result;
381 	unsigned i;
382 	uint8_t flags;
383 	int ret;
384 
385 	/* cover all cases in help */
386 	for (flags = 0x1; flags < 0x8; flags++) {
387 		token.ipaddr_data.flags = flags;
388 
389 		memset(buf, 0, sizeof(buf));
390 
391 		if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
392 				buf, sizeof(buf)) == -1) {
393 			printf("Error: help rejected valid parameters!\n");
394 			return -1;
395 		}
396 	}
397 
398 	/* test valid strings */
399 	for (i = 0; i < IPADDR_VALID_STRS_SIZE; i++) {
400 
401 		/* test each valid string against different flags */
402 		for (flags = 1; flags < 0x8; flags++) {
403 
404 			/* skip bad flag */
405 			if (flags == CMDLINE_IPADDR_NETWORK)
406 				continue;
407 
408 			/* clear out everything */
409 			memset(buf, 0, sizeof(buf));
410 			memset(&result, 0, sizeof(result));
411 			memset(&token, 0, sizeof(token));
412 
413 			token.ipaddr_data.flags = flags;
414 
415 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
416 							buf, sizeof(buf));
417 
418 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
419 					ipaddr_valid_strs[i].str, (void*)&result);
420 
421 			/* if should have passed, or should have failed */
422 			if ((ret < 0) ==
423 					(can_parse_addr(ipaddr_valid_strs[i].flags, flags))) {
424 				printf("Error: unexpected behavior when parsing %s as %s!\n",
425 						ipaddr_valid_strs[i].str, buf);
426 				printf("Parsed result: ");
427 				dump_addr(result);
428 				printf("Expected result: ");
429 				dump_addr(ipaddr_valid_strs[i].addr);
430 				return -1;
431 			}
432 			if (ret != -1 &&
433 					is_addr_different(result, ipaddr_valid_strs[i].addr)) {
434 				printf("Error: result mismatch when parsing %s as %s!\n",
435 						ipaddr_valid_strs[i].str, buf);
436 				printf("Parsed result: ");
437 				dump_addr(result);
438 				printf("Expected result: ");
439 				dump_addr(ipaddr_valid_strs[i].addr);
440 				return -1;
441 			}
442 		}
443 	}
444 
445 	/* test garbage ipv4 address strings */
446 	for (i = 0; i < IPADDR_GARBAGE_ADDR4_STRS_SIZE; i++) {
447 
448 		struct in_addr tmp = IPv4_GARBAGE_ADDR;
449 
450 		/* test each valid string against different flags */
451 		for (flags = 1; flags < 0x8; flags++) {
452 
453 			/* skip bad flag */
454 			if (flags == CMDLINE_IPADDR_NETWORK)
455 				continue;
456 
457 			/* clear out everything */
458 			memset(buf, 0, sizeof(buf));
459 			memset(&result, 0, sizeof(result));
460 			memset(&token, 0, sizeof(token));
461 
462 			token.ipaddr_data.flags = flags;
463 
464 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
465 							buf, sizeof(buf));
466 
467 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
468 					ipaddr_garbage_addr4_strs[i], (void*)&result);
469 
470 			/* if should have passed, or should have failed */
471 			if ((ret < 0) ==
472 					(can_parse_addr(CMDLINE_IPADDR_V4, flags))) {
473 				printf("Error: unexpected behavior when parsing %s as %s!\n",
474 						ipaddr_garbage_addr4_strs[i], buf);
475 				return -1;
476 			}
477 			if (ret != -1 &&
478 					memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
479 				printf("Error: result mismatch when parsing %s as %s!\n",
480 						ipaddr_garbage_addr4_strs[i], buf);
481 				return -1;
482 			}
483 		}
484 	}
485 
486 	/* test garbage ipv6 address strings */
487 	for (i = 0; i < IPADDR_GARBAGE_ADDR6_STRS_SIZE; i++) {
488 
489 		cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
490 
491 		/* test each valid string against different flags */
492 		for (flags = 1; flags < 0x8; flags++) {
493 
494 			/* skip bad flag */
495 			if (flags == CMDLINE_IPADDR_NETWORK)
496 				continue;
497 
498 			/* clear out everything */
499 			memset(buf, 0, sizeof(buf));
500 			memset(&result, 0, sizeof(result));
501 			memset(&token, 0, sizeof(token));
502 
503 			token.ipaddr_data.flags = flags;
504 
505 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
506 							buf, sizeof(buf));
507 
508 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
509 					ipaddr_garbage_addr6_strs[i], (void*)&result);
510 
511 			/* if should have passed, or should have failed */
512 			if ((ret < 0) ==
513 					(can_parse_addr(CMDLINE_IPADDR_V6, flags))) {
514 				printf("Error: unexpected behavior when parsing %s as %s!\n",
515 						ipaddr_garbage_addr6_strs[i], buf);
516 				return -1;
517 			}
518 			if (ret != -1 &&
519 					memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
520 				printf("Error: result mismatch when parsing %s as %s!\n",
521 						ipaddr_garbage_addr6_strs[i], buf);
522 				return -1;
523 			}
524 		}
525 	}
526 
527 
528 	/* test garbage ipv4 network strings */
529 	for (i = 0; i < IPADDR_GARBAGE_NETWORK4_STRS_SIZE; i++) {
530 
531 		struct in_addr tmp = IPv4_GARBAGE_ADDR;
532 
533 		/* test each valid string against different flags */
534 		for (flags = 1; flags < 0x8; flags++) {
535 
536 			/* skip bad flag */
537 			if (flags == CMDLINE_IPADDR_NETWORK)
538 				continue;
539 
540 			/* clear out everything */
541 			memset(buf, 0, sizeof(buf));
542 			memset(&result, 0, sizeof(result));
543 			memset(&token, 0, sizeof(token));
544 
545 			token.ipaddr_data.flags = flags;
546 
547 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
548 							buf, sizeof(buf));
549 
550 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
551 					ipaddr_garbage_network4_strs[i], (void*)&result);
552 
553 			/* if should have passed, or should have failed */
554 			if ((ret < 0) ==
555 					(can_parse_addr(CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK, flags))) {
556 				printf("Error: unexpected behavior when parsing %s as %s!\n",
557 						ipaddr_garbage_network4_strs[i], buf);
558 				return -1;
559 			}
560 			if (ret != -1 &&
561 					memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
562 				printf("Error: result mismatch when parsing %s as %s!\n",
563 						ipaddr_garbage_network4_strs[i], buf);
564 				return -1;
565 			}
566 		}
567 	}
568 
569 	/* test garbage ipv6 address strings */
570 	for (i = 0; i < IPADDR_GARBAGE_NETWORK6_STRS_SIZE; i++) {
571 
572 		cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
573 
574 		/* test each valid string against different flags */
575 		for (flags = 1; flags < 0x8; flags++) {
576 
577 			/* skip bad flag */
578 			if (flags == CMDLINE_IPADDR_NETWORK)
579 				continue;
580 
581 			/* clear out everything */
582 			memset(buf, 0, sizeof(buf));
583 			memset(&result, 0, sizeof(result));
584 			memset(&token, 0, sizeof(token));
585 
586 			token.ipaddr_data.flags = flags;
587 
588 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
589 							buf, sizeof(buf));
590 
591 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
592 					ipaddr_garbage_network6_strs[i], (void*)&result);
593 
594 			/* if should have passed, or should have failed */
595 			if ((ret < 0) ==
596 					(can_parse_addr(CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK, flags))) {
597 				printf("Error: unexpected behavior when parsing %s as %s!\n",
598 						ipaddr_garbage_network6_strs[i], buf);
599 				return -1;
600 			}
601 			if (ret != -1 &&
602 					memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
603 				printf("Error: result mismatch when parsing %s as %s!\n",
604 						ipaddr_garbage_network6_strs[i], buf);
605 				return -1;
606 			}
607 		}
608 	}
609 
610 	return 0;
611 }
612 
613 int
614 test_parse_ipaddr_invalid_data(void)
615 {
616 	cmdline_parse_token_ipaddr_t token;
617 	char buf[CMDLINE_TEST_BUFSIZE];
618 	cmdline_ipaddr_t result;
619 	unsigned i;
620 	uint8_t flags;
621 	int ret;
622 
623 	memset(&result, 0, sizeof(result));
624 
625 	/* test invalid strings */
626 	for (i = 0; i < IPADDR_INVALID_STRS_SIZE; i++) {
627 
628 		/* test each valid string against different flags */
629 		for (flags = 1; flags < 0x8; flags++) {
630 
631 			/* skip bad flag */
632 			if (flags == CMDLINE_IPADDR_NETWORK)
633 				continue;
634 
635 			/* clear out everything */
636 			memset(buf, 0, sizeof(buf));
637 			memset(&token, 0, sizeof(token));
638 
639 			token.ipaddr_data.flags = flags;
640 
641 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
642 					buf, sizeof(buf));
643 
644 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
645 					ipaddr_invalid_strs[i], (void*)&result);
646 
647 			if (ret != -1) {
648 				printf("Error: parsing %s as %s succeeded!\n",
649 						ipaddr_invalid_strs[i], buf);
650 				printf("Parsed result: ");
651 				dump_addr(result);
652 				return -1;
653 			}
654 		}
655 	}
656 
657 	return 0;
658 }
659 
660 int
661 test_parse_ipaddr_invalid_param(void)
662 {
663 	cmdline_parse_token_ipaddr_t token;
664 	char buf[CMDLINE_TEST_BUFSIZE];
665 	cmdline_ipaddr_t result;
666 
667 	rte_snprintf(buf, sizeof(buf), "1.2.3.4");
668 	token.ipaddr_data.flags = CMDLINE_IPADDR_V4;
669 
670 	/* null token */
671 	if (cmdline_parse_ipaddr(NULL, buf, (void*)&result) != -1) {
672 		printf("Error: parser accepted invalid parameters!\n");
673 		return -1;
674 	}
675 	/* null buffer */
676 	if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
677 			NULL, (void*)&result) != -1) {
678 		printf("Error: parser accepted invalid parameters!\n");
679 		return -1;
680 	}
681 	/* empty buffer */
682 	if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
683 			"", (void*)&result) != -1) {
684 		printf("Error: parser accepted invalid parameters!\n");
685 		return -1;
686 	}
687 	/* null result */
688 	if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
689 			buf, NULL) == -1) {
690 		printf("Error: parser rejected null result!\n");
691 		return -1;
692 	}
693 
694 	/* null token */
695 	if (cmdline_get_help_ipaddr(NULL, buf, 0) != -1) {
696 		printf("Error: help accepted invalid parameters!\n");
697 		return -1;
698 	}
699 	/* null buffer */
700 	if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
701 			NULL, 0) != -1) {
702 		printf("Error: help accepted invalid parameters!\n");
703 		return -1;
704 	}
705 	return 0;
706 }
707