1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Author: Justin Iurman (justin.iurman@uliege.be) 4 * 5 * IOAM tester for IPv6, see ioam6.sh for details on each test case. 6 */ 7 #include <arpa/inet.h> 8 #include <errno.h> 9 #include <limits.h> 10 #include <linux/const.h> 11 #include <linux/if_ether.h> 12 #include <linux/ioam6.h> 13 #include <linux/ipv6.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <unistd.h> 17 18 struct ioam_config { 19 __u32 id; 20 __u64 wide; 21 __u16 ingr_id; 22 __u16 egr_id; 23 __u32 ingr_wide; 24 __u32 egr_wide; 25 __u32 ns_data; 26 __u64 ns_wide; 27 __u32 sc_id; 28 __u8 hlim; 29 char *sc_data; 30 }; 31 32 /* 33 * Be careful if you modify structs below - everything MUST be kept synchronized 34 * with configurations inside ioam6.sh and always reflect the same. 35 */ 36 37 static struct ioam_config node1 = { 38 .id = 1, 39 .wide = 11111111, 40 .ingr_id = 0xffff, /* default value */ 41 .egr_id = 101, 42 .ingr_wide = 0xffffffff, /* default value */ 43 .egr_wide = 101101, 44 .ns_data = 0xdeadbee0, 45 .ns_wide = 0xcafec0caf00dc0de, 46 .sc_id = 777, 47 .sc_data = "something that will be 4n-aligned", 48 .hlim = 64, 49 }; 50 51 static struct ioam_config node2 = { 52 .id = 2, 53 .wide = 22222222, 54 .ingr_id = 201, 55 .egr_id = 202, 56 .ingr_wide = 201201, 57 .egr_wide = 202202, 58 .ns_data = 0xdeadbee1, 59 .ns_wide = 0xcafec0caf11dc0de, 60 .sc_id = 666, 61 .sc_data = "Hello there -Obi", 62 .hlim = 63, 63 }; 64 65 static struct ioam_config node3 = { 66 .id = 3, 67 .wide = 33333333, 68 .ingr_id = 301, 69 .egr_id = 0xffff, /* default value */ 70 .ingr_wide = 301301, 71 .egr_wide = 0xffffffff, /* default value */ 72 .ns_data = 0xdeadbee2, 73 .ns_wide = 0xcafec0caf22dc0de, 74 .sc_id = 0xffffff, /* default value */ 75 .sc_data = NULL, 76 .hlim = 62, 77 }; 78 79 enum { 80 /********** 81 * OUTPUT * 82 **********/ 83 TEST_OUT_UNDEF_NS, 84 TEST_OUT_NO_ROOM, 85 TEST_OUT_BIT0, 86 TEST_OUT_BIT1, 87 TEST_OUT_BIT2, 88 TEST_OUT_BIT3, 89 TEST_OUT_BIT4, 90 TEST_OUT_BIT5, 91 TEST_OUT_BIT6, 92 TEST_OUT_BIT7, 93 TEST_OUT_BIT8, 94 TEST_OUT_BIT9, 95 TEST_OUT_BIT10, 96 TEST_OUT_BIT11, 97 TEST_OUT_BIT22, 98 TEST_OUT_FULL_SUPP_TRACE, 99 100 /********* 101 * INPUT * 102 *********/ 103 TEST_IN_UNDEF_NS, 104 TEST_IN_NO_ROOM, 105 TEST_IN_OFLAG, 106 TEST_IN_BIT0, 107 TEST_IN_BIT1, 108 TEST_IN_BIT2, 109 TEST_IN_BIT3, 110 TEST_IN_BIT4, 111 TEST_IN_BIT5, 112 TEST_IN_BIT6, 113 TEST_IN_BIT7, 114 TEST_IN_BIT8, 115 TEST_IN_BIT9, 116 TEST_IN_BIT10, 117 TEST_IN_BIT11, 118 TEST_IN_BIT22, 119 TEST_IN_FULL_SUPP_TRACE, 120 121 /********** 122 * GLOBAL * 123 **********/ 124 TEST_FWD_FULL_SUPP_TRACE, 125 126 __TEST_MAX, 127 }; 128 129 static int check_ioam_header(int tid, struct ioam6_trace_hdr *ioam6h, 130 __u32 trace_type, __u16 ioam_ns) 131 { 132 if (__be16_to_cpu(ioam6h->namespace_id) != ioam_ns || 133 __be32_to_cpu(ioam6h->type_be32) != (trace_type << 8)) 134 return 1; 135 136 switch (tid) { 137 case TEST_OUT_UNDEF_NS: 138 case TEST_IN_UNDEF_NS: 139 return ioam6h->overflow || 140 ioam6h->nodelen != 1 || 141 ioam6h->remlen != 1; 142 143 case TEST_OUT_NO_ROOM: 144 case TEST_IN_NO_ROOM: 145 case TEST_IN_OFLAG: 146 return !ioam6h->overflow || 147 ioam6h->nodelen != 2 || 148 ioam6h->remlen != 1; 149 150 case TEST_OUT_BIT0: 151 case TEST_IN_BIT0: 152 case TEST_OUT_BIT1: 153 case TEST_IN_BIT1: 154 case TEST_OUT_BIT2: 155 case TEST_IN_BIT2: 156 case TEST_OUT_BIT3: 157 case TEST_IN_BIT3: 158 case TEST_OUT_BIT4: 159 case TEST_IN_BIT4: 160 case TEST_OUT_BIT5: 161 case TEST_IN_BIT5: 162 case TEST_OUT_BIT6: 163 case TEST_IN_BIT6: 164 case TEST_OUT_BIT7: 165 case TEST_IN_BIT7: 166 case TEST_OUT_BIT11: 167 case TEST_IN_BIT11: 168 return ioam6h->overflow || 169 ioam6h->nodelen != 1 || 170 ioam6h->remlen; 171 172 case TEST_OUT_BIT8: 173 case TEST_IN_BIT8: 174 case TEST_OUT_BIT9: 175 case TEST_IN_BIT9: 176 case TEST_OUT_BIT10: 177 case TEST_IN_BIT10: 178 return ioam6h->overflow || 179 ioam6h->nodelen != 2 || 180 ioam6h->remlen; 181 182 case TEST_OUT_BIT22: 183 case TEST_IN_BIT22: 184 return ioam6h->overflow || 185 ioam6h->nodelen || 186 ioam6h->remlen; 187 188 case TEST_OUT_FULL_SUPP_TRACE: 189 case TEST_IN_FULL_SUPP_TRACE: 190 case TEST_FWD_FULL_SUPP_TRACE: 191 return ioam6h->overflow || 192 ioam6h->nodelen != 15 || 193 ioam6h->remlen; 194 195 default: 196 break; 197 } 198 199 return 1; 200 } 201 202 static int check_ioam6_data(__u8 **p, struct ioam6_trace_hdr *ioam6h, 203 const struct ioam_config cnf) 204 { 205 unsigned int len; 206 __u8 aligned; 207 __u64 raw64; 208 __u32 raw32; 209 210 if (ioam6h->type.bit0) { 211 raw32 = __be32_to_cpu(*((__u32 *)*p)); 212 if (cnf.hlim != (raw32 >> 24) || cnf.id != (raw32 & 0xffffff)) 213 return 1; 214 *p += sizeof(__u32); 215 } 216 217 if (ioam6h->type.bit1) { 218 raw32 = __be32_to_cpu(*((__u32 *)*p)); 219 if (cnf.ingr_id != (raw32 >> 16) || 220 cnf.egr_id != (raw32 & 0xffff)) 221 return 1; 222 *p += sizeof(__u32); 223 } 224 225 if (ioam6h->type.bit2) 226 *p += sizeof(__u32); 227 228 if (ioam6h->type.bit3) 229 *p += sizeof(__u32); 230 231 if (ioam6h->type.bit4) { 232 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 233 return 1; 234 *p += sizeof(__u32); 235 } 236 237 if (ioam6h->type.bit5) { 238 if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ns_data) 239 return 1; 240 *p += sizeof(__u32); 241 } 242 243 if (ioam6h->type.bit6) { 244 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 245 return 1; 246 *p += sizeof(__u32); 247 } 248 249 if (ioam6h->type.bit7) { 250 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 251 return 1; 252 *p += sizeof(__u32); 253 } 254 255 if (ioam6h->type.bit8) { 256 raw64 = __be64_to_cpu(*((__u64 *)*p)); 257 if (cnf.hlim != (raw64 >> 56) || 258 cnf.wide != (raw64 & 0xffffffffffffff)) 259 return 1; 260 *p += sizeof(__u64); 261 } 262 263 if (ioam6h->type.bit9) { 264 if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ingr_wide) 265 return 1; 266 *p += sizeof(__u32); 267 268 if (__be32_to_cpu(*((__u32 *)*p)) != cnf.egr_wide) 269 return 1; 270 *p += sizeof(__u32); 271 } 272 273 if (ioam6h->type.bit10) { 274 if (__be64_to_cpu(*((__u64 *)*p)) != cnf.ns_wide) 275 return 1; 276 *p += sizeof(__u64); 277 } 278 279 if (ioam6h->type.bit11) { 280 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 281 return 1; 282 *p += sizeof(__u32); 283 } 284 285 if (ioam6h->type.bit12) { 286 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 287 return 1; 288 *p += sizeof(__u32); 289 } 290 291 if (ioam6h->type.bit13) { 292 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 293 return 1; 294 *p += sizeof(__u32); 295 } 296 297 if (ioam6h->type.bit14) { 298 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 299 return 1; 300 *p += sizeof(__u32); 301 } 302 303 if (ioam6h->type.bit15) { 304 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 305 return 1; 306 *p += sizeof(__u32); 307 } 308 309 if (ioam6h->type.bit16) { 310 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 311 return 1; 312 *p += sizeof(__u32); 313 } 314 315 if (ioam6h->type.bit17) { 316 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 317 return 1; 318 *p += sizeof(__u32); 319 } 320 321 if (ioam6h->type.bit18) { 322 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 323 return 1; 324 *p += sizeof(__u32); 325 } 326 327 if (ioam6h->type.bit19) { 328 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 329 return 1; 330 *p += sizeof(__u32); 331 } 332 333 if (ioam6h->type.bit20) { 334 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 335 return 1; 336 *p += sizeof(__u32); 337 } 338 339 if (ioam6h->type.bit21) { 340 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 341 return 1; 342 *p += sizeof(__u32); 343 } 344 345 if (ioam6h->type.bit22) { 346 len = cnf.sc_data ? strlen(cnf.sc_data) : 0; 347 aligned = cnf.sc_data ? __ALIGN_KERNEL(len, 4) : 0; 348 349 raw32 = __be32_to_cpu(*((__u32 *)*p)); 350 if (aligned != (raw32 >> 24) * 4 || 351 cnf.sc_id != (raw32 & 0xffffff)) 352 return 1; 353 *p += sizeof(__u32); 354 355 if (cnf.sc_data) { 356 if (strncmp((char *)*p, cnf.sc_data, len)) 357 return 1; 358 359 *p += len; 360 aligned -= len; 361 362 while (aligned--) { 363 if (**p != '\0') 364 return 1; 365 *p += sizeof(__u8); 366 } 367 } 368 } 369 370 return 0; 371 } 372 373 static int check_ioam_header_and_data(int tid, struct ioam6_trace_hdr *ioam6h, 374 __u32 trace_type, __u16 ioam_ns) 375 { 376 __u8 *p; 377 378 if (check_ioam_header(tid, ioam6h, trace_type, ioam_ns)) 379 return 1; 380 381 p = ioam6h->data + ioam6h->remlen * 4; 382 383 switch (tid) { 384 case TEST_OUT_BIT0: 385 case TEST_OUT_BIT1: 386 case TEST_OUT_BIT2: 387 case TEST_OUT_BIT3: 388 case TEST_OUT_BIT4: 389 case TEST_OUT_BIT5: 390 case TEST_OUT_BIT6: 391 case TEST_OUT_BIT7: 392 case TEST_OUT_BIT8: 393 case TEST_OUT_BIT9: 394 case TEST_OUT_BIT10: 395 case TEST_OUT_BIT11: 396 case TEST_OUT_BIT22: 397 case TEST_OUT_FULL_SUPP_TRACE: 398 return check_ioam6_data(&p, ioam6h, node1); 399 400 case TEST_IN_BIT0: 401 case TEST_IN_BIT1: 402 case TEST_IN_BIT2: 403 case TEST_IN_BIT3: 404 case TEST_IN_BIT4: 405 case TEST_IN_BIT5: 406 case TEST_IN_BIT6: 407 case TEST_IN_BIT7: 408 case TEST_IN_BIT8: 409 case TEST_IN_BIT9: 410 case TEST_IN_BIT10: 411 case TEST_IN_BIT11: 412 case TEST_IN_BIT22: 413 case TEST_IN_FULL_SUPP_TRACE: 414 { 415 __u32 tmp32 = node2.egr_wide; 416 __u16 tmp16 = node2.egr_id; 417 int res; 418 419 node2.egr_id = 0xffff; 420 node2.egr_wide = 0xffffffff; 421 422 res = check_ioam6_data(&p, ioam6h, node2); 423 424 node2.egr_id = tmp16; 425 node2.egr_wide = tmp32; 426 427 return res; 428 } 429 430 case TEST_FWD_FULL_SUPP_TRACE: 431 if (check_ioam6_data(&p, ioam6h, node3)) 432 return 1; 433 if (check_ioam6_data(&p, ioam6h, node2)) 434 return 1; 435 return check_ioam6_data(&p, ioam6h, node1); 436 437 default: 438 break; 439 } 440 441 return 1; 442 } 443 444 static int str2id(const char *tname) 445 { 446 if (!strcmp("out_undef_ns", tname)) 447 return TEST_OUT_UNDEF_NS; 448 if (!strcmp("out_no_room", tname)) 449 return TEST_OUT_NO_ROOM; 450 if (!strcmp("out_bit0", tname)) 451 return TEST_OUT_BIT0; 452 if (!strcmp("out_bit1", tname)) 453 return TEST_OUT_BIT1; 454 if (!strcmp("out_bit2", tname)) 455 return TEST_OUT_BIT2; 456 if (!strcmp("out_bit3", tname)) 457 return TEST_OUT_BIT3; 458 if (!strcmp("out_bit4", tname)) 459 return TEST_OUT_BIT4; 460 if (!strcmp("out_bit5", tname)) 461 return TEST_OUT_BIT5; 462 if (!strcmp("out_bit6", tname)) 463 return TEST_OUT_BIT6; 464 if (!strcmp("out_bit7", tname)) 465 return TEST_OUT_BIT7; 466 if (!strcmp("out_bit8", tname)) 467 return TEST_OUT_BIT8; 468 if (!strcmp("out_bit9", tname)) 469 return TEST_OUT_BIT9; 470 if (!strcmp("out_bit10", tname)) 471 return TEST_OUT_BIT10; 472 if (!strcmp("out_bit11", tname)) 473 return TEST_OUT_BIT11; 474 if (!strcmp("out_bit22", tname)) 475 return TEST_OUT_BIT22; 476 if (!strcmp("out_full_supp_trace", tname)) 477 return TEST_OUT_FULL_SUPP_TRACE; 478 if (!strcmp("in_undef_ns", tname)) 479 return TEST_IN_UNDEF_NS; 480 if (!strcmp("in_no_room", tname)) 481 return TEST_IN_NO_ROOM; 482 if (!strcmp("in_oflag", tname)) 483 return TEST_IN_OFLAG; 484 if (!strcmp("in_bit0", tname)) 485 return TEST_IN_BIT0; 486 if (!strcmp("in_bit1", tname)) 487 return TEST_IN_BIT1; 488 if (!strcmp("in_bit2", tname)) 489 return TEST_IN_BIT2; 490 if (!strcmp("in_bit3", tname)) 491 return TEST_IN_BIT3; 492 if (!strcmp("in_bit4", tname)) 493 return TEST_IN_BIT4; 494 if (!strcmp("in_bit5", tname)) 495 return TEST_IN_BIT5; 496 if (!strcmp("in_bit6", tname)) 497 return TEST_IN_BIT6; 498 if (!strcmp("in_bit7", tname)) 499 return TEST_IN_BIT7; 500 if (!strcmp("in_bit8", tname)) 501 return TEST_IN_BIT8; 502 if (!strcmp("in_bit9", tname)) 503 return TEST_IN_BIT9; 504 if (!strcmp("in_bit10", tname)) 505 return TEST_IN_BIT10; 506 if (!strcmp("in_bit11", tname)) 507 return TEST_IN_BIT11; 508 if (!strcmp("in_bit22", tname)) 509 return TEST_IN_BIT22; 510 if (!strcmp("in_full_supp_trace", tname)) 511 return TEST_IN_FULL_SUPP_TRACE; 512 if (!strcmp("fwd_full_supp_trace", tname)) 513 return TEST_FWD_FULL_SUPP_TRACE; 514 515 return -1; 516 } 517 518 static int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2) 519 { 520 return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) | 521 (a1->s6_addr32[1] ^ a2->s6_addr32[1]) | 522 (a1->s6_addr32[2] ^ a2->s6_addr32[2]) | 523 (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0; 524 } 525 526 static int get_u32(__u32 *val, const char *arg, int base) 527 { 528 unsigned long res; 529 char *ptr; 530 531 if (!arg || !*arg) 532 return -1; 533 res = strtoul(arg, &ptr, base); 534 535 if (!ptr || ptr == arg || *ptr) 536 return -1; 537 538 if (res == ULONG_MAX && errno == ERANGE) 539 return -1; 540 541 if (res > 0xFFFFFFFFUL) 542 return -1; 543 544 *val = res; 545 return 0; 546 } 547 548 static int get_u16(__u16 *val, const char *arg, int base) 549 { 550 unsigned long res; 551 char *ptr; 552 553 if (!arg || !*arg) 554 return -1; 555 res = strtoul(arg, &ptr, base); 556 557 if (!ptr || ptr == arg || *ptr) 558 return -1; 559 560 if (res == ULONG_MAX && errno == ERANGE) 561 return -1; 562 563 if (res > 0xFFFFUL) 564 return -1; 565 566 *val = res; 567 return 0; 568 } 569 570 static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = { 571 [TEST_OUT_UNDEF_NS] = check_ioam_header, 572 [TEST_OUT_NO_ROOM] = check_ioam_header, 573 [TEST_OUT_BIT0] = check_ioam_header_and_data, 574 [TEST_OUT_BIT1] = check_ioam_header_and_data, 575 [TEST_OUT_BIT2] = check_ioam_header_and_data, 576 [TEST_OUT_BIT3] = check_ioam_header_and_data, 577 [TEST_OUT_BIT4] = check_ioam_header_and_data, 578 [TEST_OUT_BIT5] = check_ioam_header_and_data, 579 [TEST_OUT_BIT6] = check_ioam_header_and_data, 580 [TEST_OUT_BIT7] = check_ioam_header_and_data, 581 [TEST_OUT_BIT8] = check_ioam_header_and_data, 582 [TEST_OUT_BIT9] = check_ioam_header_and_data, 583 [TEST_OUT_BIT10] = check_ioam_header_and_data, 584 [TEST_OUT_BIT11] = check_ioam_header_and_data, 585 [TEST_OUT_BIT22] = check_ioam_header_and_data, 586 [TEST_OUT_FULL_SUPP_TRACE] = check_ioam_header_and_data, 587 [TEST_IN_UNDEF_NS] = check_ioam_header, 588 [TEST_IN_NO_ROOM] = check_ioam_header, 589 [TEST_IN_OFLAG] = check_ioam_header, 590 [TEST_IN_BIT0] = check_ioam_header_and_data, 591 [TEST_IN_BIT1] = check_ioam_header_and_data, 592 [TEST_IN_BIT2] = check_ioam_header_and_data, 593 [TEST_IN_BIT3] = check_ioam_header_and_data, 594 [TEST_IN_BIT4] = check_ioam_header_and_data, 595 [TEST_IN_BIT5] = check_ioam_header_and_data, 596 [TEST_IN_BIT6] = check_ioam_header_and_data, 597 [TEST_IN_BIT7] = check_ioam_header_and_data, 598 [TEST_IN_BIT8] = check_ioam_header_and_data, 599 [TEST_IN_BIT9] = check_ioam_header_and_data, 600 [TEST_IN_BIT10] = check_ioam_header_and_data, 601 [TEST_IN_BIT11] = check_ioam_header_and_data, 602 [TEST_IN_BIT22] = check_ioam_header_and_data, 603 [TEST_IN_FULL_SUPP_TRACE] = check_ioam_header_and_data, 604 [TEST_FWD_FULL_SUPP_TRACE] = check_ioam_header_and_data, 605 }; 606 607 int main(int argc, char **argv) 608 { 609 int fd, size, hoplen, tid, ret = 1; 610 struct in6_addr src, dst; 611 struct ioam6_hdr *opt; 612 struct ipv6hdr *ip6h; 613 __u8 buffer[400], *p; 614 __u16 ioam_ns; 615 __u32 tr_type; 616 617 if (argc != 7) 618 goto out; 619 620 tid = str2id(argv[2]); 621 if (tid < 0 || !func[tid]) 622 goto out; 623 624 if (inet_pton(AF_INET6, argv[3], &src) != 1 || 625 inet_pton(AF_INET6, argv[4], &dst) != 1) 626 goto out; 627 628 if (get_u32(&tr_type, argv[5], 16) || 629 get_u16(&ioam_ns, argv[6], 0)) 630 goto out; 631 632 fd = socket(AF_PACKET, SOCK_DGRAM, __cpu_to_be16(ETH_P_IPV6)); 633 if (!fd) 634 goto out; 635 636 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, 637 argv[1], strlen(argv[1]))) 638 goto close; 639 640 recv: 641 size = recv(fd, buffer, sizeof(buffer), 0); 642 if (size <= 0) 643 goto close; 644 645 ip6h = (struct ipv6hdr *)buffer; 646 647 if (!ipv6_addr_equal(&ip6h->saddr, &src) || 648 !ipv6_addr_equal(&ip6h->daddr, &dst)) 649 goto recv; 650 651 if (ip6h->nexthdr != IPPROTO_HOPOPTS) 652 goto close; 653 654 p = buffer + sizeof(*ip6h); 655 hoplen = (p[1] + 1) << 3; 656 p += sizeof(struct ipv6_hopopt_hdr); 657 658 while (hoplen > 0) { 659 opt = (struct ioam6_hdr *)p; 660 661 if (opt->opt_type == IPV6_TLV_IOAM && 662 opt->type == IOAM6_TYPE_PREALLOC) { 663 p += sizeof(*opt); 664 ret = func[tid](tid, (struct ioam6_trace_hdr *)p, 665 tr_type, ioam_ns); 666 break; 667 } 668 669 p += opt->opt_len + 2; 670 hoplen -= opt->opt_len + 2; 671 } 672 close: 673 close(fd); 674 out: 675 return ret; 676 } 677