4 * Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
37 #include <netinet/in.h>
40 #include <net/socket.h>
43 #include <rte_string_fns.h>
45 #include <cmdline_parse.h>
46 #include <cmdline_parse_ipaddr.h>
48 #include "test_cmdline.h"
50 #define IP4(a,b,c,d) {((uint32_t)(((a) & 0xff)) | \
51 (((b) & 0xff) << 8) | \
52 (((c) & 0xff) << 16) | \
56 (((x & 0xFF) << 8) | ((x & 0xFF00) >> 8))
58 /* create IPv6 address, swapping bytes where needed */
59 #define IP6(a,b,c,d,e,f,g,h) .ipv6 = \
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)}}
64 /** these are defined in netinet/in.h but not present in linux headers */
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]
73 #define NIP6_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"
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])
97 cmdline_ipaddr_t addr;
101 const struct ipaddr_str ipaddr_valid_strs[] = {
102 {"0.0.0.0", {AF_INET, {IP4(0,0,0,0)}, 0},
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},
116 {"::1", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 0},
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)},
127 {"1234::1234/64", {AF_INET6,
128 {IP6(0x1234,0,0,0,0,0,0,0x1234)},
130 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
131 {"1234::/64", {AF_INET6,
132 {IP6(0x1234,0,0,0,0,0,0,0)},
134 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
135 {"1:1::1/32", {AF_INET6,
136 {IP6(1,1,0,0,0,0,0,1)},
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)},
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)},
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)},
154 const char * ipaddr_garbage_addr4_strs[] = {
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",
163 #define IPv4_GARBAGE_ADDR IP4(192,168,1,0)
165 const char * ipaddr_garbage_addr6_strs[] = {
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",
174 #define IPv6_GARBAGE_ADDR {IP6(1,2,3,4,0,0,0,8)}
176 const char * ipaddr_garbage_network4_strs[] = {
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",
185 #define IPv4_GARBAGE_PREFIX 24
187 const char * ipaddr_garbage_network6_strs[] = {
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",
196 #define IPv6_GARBAGE_PREFIX 64
200 const char * ipaddr_invalid_strs[] = {
203 /* invalid numbers */
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 */
231 "123.123.123.123.123",
236 "123.123.123.123./24",
237 "123.123.123..123/24",
238 "123.123.123.123.123/24",
240 ".123.123.123.123/24",
241 /* invalid characters */
249 "123.123.123.123/4F",
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",
275 "1::2:3:4:5:6:7:8/64",
277 /* invalid network mask */
278 "1:2:3:4:5:6:7:8/129",
279 "1:2:3:4:5:6:7:8/-1",
281 /* invalid characters */
287 "1234:1234:1234:1234:1234:1234:1234:1234:1234:1234:1234"
288 "random invalid text",
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]))
308 dump_addr(cmdline_ipaddr_t addr)
310 switch (addr.family) {
313 printf(NIPQUAD_FMT " prefixlen=%u\n",
314 NIPQUAD(addr.addr.ipv4.s_addr), addr.prefixlen);
319 printf(NIP6_FMT " prefixlen=%u\n",
320 NIP6(addr.addr.ipv6), addr.prefixlen);
324 printf("Can't dump: unknown address family.\n");
331 is_addr_different(cmdline_ipaddr_t addr1, cmdline_ipaddr_t addr2)
333 if (addr1.family != addr2.family)
336 if (addr1.prefixlen != addr2.prefixlen)
339 switch (addr1.family) {
342 if (memcmp(&addr1.addr.ipv4, &addr2.addr.ipv4,
343 sizeof(struct in_addr)) != 0)
349 if (memcmp(&addr1.addr.ipv6, &addr2.addr.ipv6,
350 sizeof(struct in6_addr)) != 0)
354 /* thing that should not be */
362 can_parse_addr(unsigned addr_flags, unsigned test_flags)
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)
368 /* if this is a network address */
369 else if (addr_flags & CMDLINE_IPADDR_NETWORK)
376 test_parse_ipaddr_valid(void)
378 cmdline_parse_token_ipaddr_t token;
379 char buf[CMDLINE_TEST_BUFSIZE];
380 cmdline_ipaddr_t result;
385 /* cover all cases in help */
386 for (flags = 0x1; flags < 0x8; flags++) {
387 token.ipaddr_data.flags = flags;
389 memset(buf, 0, sizeof(buf));
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");
398 /* test valid strings */
399 for (i = 0; i < IPADDR_VALID_STRS_SIZE; i++) {
401 /* test each valid string against different flags */
402 for (flags = 1; flags < 0x8; flags++) {
405 if (flags == CMDLINE_IPADDR_NETWORK)
408 /* clear out everything */
409 memset(buf, 0, sizeof(buf));
410 memset(&result, 0, sizeof(result));
411 memset(&token, 0, sizeof(token));
413 token.ipaddr_data.flags = flags;
415 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
418 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
419 ipaddr_valid_strs[i].str, (void*)&result);
421 /* if should have passed, or should have failed */
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: ");
428 printf("Expected result: ");
429 dump_addr(ipaddr_valid_strs[i].addr);
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: ");
438 printf("Expected result: ");
439 dump_addr(ipaddr_valid_strs[i].addr);
445 /* test garbage ipv4 address strings */
446 for (i = 0; i < IPADDR_GARBAGE_ADDR4_STRS_SIZE; i++) {
448 struct in_addr tmp = IPv4_GARBAGE_ADDR;
450 /* test each valid string against different flags */
451 for (flags = 1; flags < 0x8; flags++) {
454 if (flags == CMDLINE_IPADDR_NETWORK)
457 /* clear out everything */
458 memset(buf, 0, sizeof(buf));
459 memset(&result, 0, sizeof(result));
460 memset(&token, 0, sizeof(token));
462 token.ipaddr_data.flags = flags;
464 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
467 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
468 ipaddr_garbage_addr4_strs[i], (void*)&result);
470 /* if should have passed, or should have failed */
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);
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);
486 /* test garbage ipv6 address strings */
487 for (i = 0; i < IPADDR_GARBAGE_ADDR6_STRS_SIZE; i++) {
489 cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
491 /* test each valid string against different flags */
492 for (flags = 1; flags < 0x8; flags++) {
495 if (flags == CMDLINE_IPADDR_NETWORK)
498 /* clear out everything */
499 memset(buf, 0, sizeof(buf));
500 memset(&result, 0, sizeof(result));
501 memset(&token, 0, sizeof(token));
503 token.ipaddr_data.flags = flags;
505 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
508 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
509 ipaddr_garbage_addr6_strs[i], (void*)&result);
511 /* if should have passed, or should have failed */
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);
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);
528 /* test garbage ipv4 network strings */
529 for (i = 0; i < IPADDR_GARBAGE_NETWORK4_STRS_SIZE; i++) {
531 struct in_addr tmp = IPv4_GARBAGE_ADDR;
533 /* test each valid string against different flags */
534 for (flags = 1; flags < 0x8; flags++) {
537 if (flags == CMDLINE_IPADDR_NETWORK)
540 /* clear out everything */
541 memset(buf, 0, sizeof(buf));
542 memset(&result, 0, sizeof(result));
543 memset(&token, 0, sizeof(token));
545 token.ipaddr_data.flags = flags;
547 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
550 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
551 ipaddr_garbage_network4_strs[i], (void*)&result);
553 /* if should have passed, or should have failed */
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);
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);
569 /* test garbage ipv6 address strings */
570 for (i = 0; i < IPADDR_GARBAGE_NETWORK6_STRS_SIZE; i++) {
572 cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
574 /* test each valid string against different flags */
575 for (flags = 1; flags < 0x8; flags++) {
578 if (flags == CMDLINE_IPADDR_NETWORK)
581 /* clear out everything */
582 memset(buf, 0, sizeof(buf));
583 memset(&result, 0, sizeof(result));
584 memset(&token, 0, sizeof(token));
586 token.ipaddr_data.flags = flags;
588 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
591 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
592 ipaddr_garbage_network6_strs[i], (void*)&result);
594 /* if should have passed, or should have failed */
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);
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);
614 test_parse_ipaddr_invalid_data(void)
616 cmdline_parse_token_ipaddr_t token;
617 char buf[CMDLINE_TEST_BUFSIZE];
618 cmdline_ipaddr_t result;
623 memset(&result, 0, sizeof(result));
625 /* test invalid strings */
626 for (i = 0; i < IPADDR_INVALID_STRS_SIZE; i++) {
628 /* test each valid string against different flags */
629 for (flags = 1; flags < 0x8; flags++) {
632 if (flags == CMDLINE_IPADDR_NETWORK)
635 /* clear out everything */
636 memset(buf, 0, sizeof(buf));
637 memset(&token, 0, sizeof(token));
639 token.ipaddr_data.flags = flags;
641 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
644 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
645 ipaddr_invalid_strs[i], (void*)&result);
648 printf("Error: parsing %s as %s succeeded!\n",
649 ipaddr_invalid_strs[i], buf);
650 printf("Parsed result: ");
661 test_parse_ipaddr_invalid_param(void)
663 cmdline_parse_token_ipaddr_t token;
664 char buf[CMDLINE_TEST_BUFSIZE];
665 cmdline_ipaddr_t result;
667 rte_snprintf(buf, sizeof(buf), "1.2.3.4");
668 token.ipaddr_data.flags = CMDLINE_IPADDR_V4;
671 if (cmdline_parse_ipaddr(NULL, buf, (void*)&result) != -1) {
672 printf("Error: parser accepted invalid parameters!\n");
676 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
677 NULL, (void*)&result) != -1) {
678 printf("Error: parser accepted invalid parameters!\n");
682 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
683 "", (void*)&result) != -1) {
684 printf("Error: parser accepted invalid parameters!\n");
688 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
690 printf("Error: parser rejected null result!\n");
695 if (cmdline_get_help_ipaddr(NULL, buf, 0) != -1) {
696 printf("Error: help accepted invalid parameters!\n");
700 if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
702 printf("Error: help accepted invalid parameters!\n");