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_BIT12, 98 TEST_OUT_BIT13, 99 TEST_OUT_BIT14, 100 TEST_OUT_BIT15, 101 TEST_OUT_BIT16, 102 TEST_OUT_BIT17, 103 TEST_OUT_BIT18, 104 TEST_OUT_BIT19, 105 TEST_OUT_BIT20, 106 TEST_OUT_BIT21, 107 TEST_OUT_BIT22, 108 TEST_OUT_FULL_SUPP_TRACE, 109 110 /********* 111 * INPUT * 112 *********/ 113 TEST_IN_UNDEF_NS, 114 TEST_IN_NO_ROOM, 115 TEST_IN_OFLAG, 116 TEST_IN_BIT0, 117 TEST_IN_BIT1, 118 TEST_IN_BIT2, 119 TEST_IN_BIT3, 120 TEST_IN_BIT4, 121 TEST_IN_BIT5, 122 TEST_IN_BIT6, 123 TEST_IN_BIT7, 124 TEST_IN_BIT8, 125 TEST_IN_BIT9, 126 TEST_IN_BIT10, 127 TEST_IN_BIT11, 128 TEST_IN_BIT12, 129 TEST_IN_BIT13, 130 TEST_IN_BIT14, 131 TEST_IN_BIT15, 132 TEST_IN_BIT16, 133 TEST_IN_BIT17, 134 TEST_IN_BIT18, 135 TEST_IN_BIT19, 136 TEST_IN_BIT20, 137 TEST_IN_BIT21, 138 TEST_IN_BIT22, 139 TEST_IN_FULL_SUPP_TRACE, 140 141 /********** 142 * GLOBAL * 143 **********/ 144 TEST_FWD_FULL_SUPP_TRACE, 145 146 __TEST_MAX, 147 }; 148 149 static int check_ioam_header(int tid, struct ioam6_trace_hdr *ioam6h, 150 __u32 trace_type, __u16 ioam_ns) 151 { 152 if (__be16_to_cpu(ioam6h->namespace_id) != ioam_ns || 153 __be32_to_cpu(ioam6h->type_be32) != (trace_type << 8)) 154 return 1; 155 156 switch (tid) { 157 case TEST_OUT_UNDEF_NS: 158 case TEST_IN_UNDEF_NS: 159 return ioam6h->overflow || 160 ioam6h->nodelen != 1 || 161 ioam6h->remlen != 1; 162 163 case TEST_OUT_NO_ROOM: 164 case TEST_IN_NO_ROOM: 165 case TEST_IN_OFLAG: 166 return !ioam6h->overflow || 167 ioam6h->nodelen != 2 || 168 ioam6h->remlen != 1; 169 170 case TEST_OUT_BIT0: 171 case TEST_IN_BIT0: 172 case TEST_OUT_BIT1: 173 case TEST_IN_BIT1: 174 case TEST_OUT_BIT2: 175 case TEST_IN_BIT2: 176 case TEST_OUT_BIT3: 177 case TEST_IN_BIT3: 178 case TEST_OUT_BIT4: 179 case TEST_IN_BIT4: 180 case TEST_OUT_BIT5: 181 case TEST_IN_BIT5: 182 case TEST_OUT_BIT6: 183 case TEST_IN_BIT6: 184 case TEST_OUT_BIT7: 185 case TEST_IN_BIT7: 186 case TEST_OUT_BIT11: 187 case TEST_IN_BIT11: 188 return ioam6h->overflow || 189 ioam6h->nodelen != 1 || 190 ioam6h->remlen; 191 192 case TEST_OUT_BIT8: 193 case TEST_IN_BIT8: 194 case TEST_OUT_BIT9: 195 case TEST_IN_BIT9: 196 case TEST_OUT_BIT10: 197 case TEST_IN_BIT10: 198 return ioam6h->overflow || 199 ioam6h->nodelen != 2 || 200 ioam6h->remlen; 201 202 case TEST_OUT_BIT12: 203 case TEST_IN_BIT12: 204 case TEST_OUT_BIT13: 205 case TEST_IN_BIT13: 206 case TEST_OUT_BIT14: 207 case TEST_IN_BIT14: 208 case TEST_OUT_BIT15: 209 case TEST_IN_BIT15: 210 case TEST_OUT_BIT16: 211 case TEST_IN_BIT16: 212 case TEST_OUT_BIT17: 213 case TEST_IN_BIT17: 214 case TEST_OUT_BIT18: 215 case TEST_IN_BIT18: 216 case TEST_OUT_BIT19: 217 case TEST_IN_BIT19: 218 case TEST_OUT_BIT20: 219 case TEST_IN_BIT20: 220 case TEST_OUT_BIT21: 221 case TEST_IN_BIT21: 222 return ioam6h->overflow || 223 ioam6h->nodelen || 224 ioam6h->remlen != 1; 225 226 case TEST_OUT_BIT22: 227 case TEST_IN_BIT22: 228 return ioam6h->overflow || 229 ioam6h->nodelen || 230 ioam6h->remlen; 231 232 case TEST_OUT_FULL_SUPP_TRACE: 233 case TEST_IN_FULL_SUPP_TRACE: 234 case TEST_FWD_FULL_SUPP_TRACE: 235 return ioam6h->overflow || 236 ioam6h->nodelen != 15 || 237 ioam6h->remlen; 238 239 default: 240 break; 241 } 242 243 return 1; 244 } 245 246 static int check_ioam6_data(__u8 **p, struct ioam6_trace_hdr *ioam6h, 247 const struct ioam_config cnf) 248 { 249 unsigned int len; 250 __u8 aligned; 251 __u64 raw64; 252 __u32 raw32; 253 254 if (ioam6h->type.bit0) { 255 raw32 = __be32_to_cpu(*((__u32 *)*p)); 256 if (cnf.hlim != (raw32 >> 24) || cnf.id != (raw32 & 0xffffff)) 257 return 1; 258 *p += sizeof(__u32); 259 } 260 261 if (ioam6h->type.bit1) { 262 raw32 = __be32_to_cpu(*((__u32 *)*p)); 263 if (cnf.ingr_id != (raw32 >> 16) || 264 cnf.egr_id != (raw32 & 0xffff)) 265 return 1; 266 *p += sizeof(__u32); 267 } 268 269 if (ioam6h->type.bit2) 270 *p += sizeof(__u32); 271 272 if (ioam6h->type.bit3) 273 *p += sizeof(__u32); 274 275 if (ioam6h->type.bit4) { 276 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 277 return 1; 278 *p += sizeof(__u32); 279 } 280 281 if (ioam6h->type.bit5) { 282 if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ns_data) 283 return 1; 284 *p += sizeof(__u32); 285 } 286 287 if (ioam6h->type.bit6) { 288 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 289 return 1; 290 *p += sizeof(__u32); 291 } 292 293 if (ioam6h->type.bit7) { 294 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 295 return 1; 296 *p += sizeof(__u32); 297 } 298 299 if (ioam6h->type.bit8) { 300 raw64 = __be64_to_cpu(*((__u64 *)*p)); 301 if (cnf.hlim != (raw64 >> 56) || 302 cnf.wide != (raw64 & 0xffffffffffffff)) 303 return 1; 304 *p += sizeof(__u64); 305 } 306 307 if (ioam6h->type.bit9) { 308 if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ingr_wide) 309 return 1; 310 *p += sizeof(__u32); 311 312 if (__be32_to_cpu(*((__u32 *)*p)) != cnf.egr_wide) 313 return 1; 314 *p += sizeof(__u32); 315 } 316 317 if (ioam6h->type.bit10) { 318 if (__be64_to_cpu(*((__u64 *)*p)) != cnf.ns_wide) 319 return 1; 320 *p += sizeof(__u64); 321 } 322 323 if (ioam6h->type.bit11) { 324 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff) 325 return 1; 326 *p += sizeof(__u32); 327 } 328 329 if (ioam6h->type.bit22) { 330 len = cnf.sc_data ? strlen(cnf.sc_data) : 0; 331 aligned = cnf.sc_data ? __ALIGN_KERNEL(len, 4) : 0; 332 333 raw32 = __be32_to_cpu(*((__u32 *)*p)); 334 if (aligned != (raw32 >> 24) * 4 || 335 cnf.sc_id != (raw32 & 0xffffff)) 336 return 1; 337 *p += sizeof(__u32); 338 339 if (cnf.sc_data) { 340 if (strncmp((char *)*p, cnf.sc_data, len)) 341 return 1; 342 343 *p += len; 344 aligned -= len; 345 346 while (aligned--) { 347 if (**p != '\0') 348 return 1; 349 *p += sizeof(__u8); 350 } 351 } 352 } 353 354 return 0; 355 } 356 357 static int check_ioam_header_and_data(int tid, struct ioam6_trace_hdr *ioam6h, 358 __u32 trace_type, __u16 ioam_ns) 359 { 360 __u8 *p; 361 362 if (check_ioam_header(tid, ioam6h, trace_type, ioam_ns)) 363 return 1; 364 365 p = ioam6h->data + ioam6h->remlen * 4; 366 367 switch (tid) { 368 case TEST_OUT_BIT0: 369 case TEST_OUT_BIT1: 370 case TEST_OUT_BIT2: 371 case TEST_OUT_BIT3: 372 case TEST_OUT_BIT4: 373 case TEST_OUT_BIT5: 374 case TEST_OUT_BIT6: 375 case TEST_OUT_BIT7: 376 case TEST_OUT_BIT8: 377 case TEST_OUT_BIT9: 378 case TEST_OUT_BIT10: 379 case TEST_OUT_BIT11: 380 case TEST_OUT_BIT22: 381 case TEST_OUT_FULL_SUPP_TRACE: 382 return check_ioam6_data(&p, ioam6h, node1); 383 384 case TEST_IN_BIT0: 385 case TEST_IN_BIT1: 386 case TEST_IN_BIT2: 387 case TEST_IN_BIT3: 388 case TEST_IN_BIT4: 389 case TEST_IN_BIT5: 390 case TEST_IN_BIT6: 391 case TEST_IN_BIT7: 392 case TEST_IN_BIT8: 393 case TEST_IN_BIT9: 394 case TEST_IN_BIT10: 395 case TEST_IN_BIT11: 396 case TEST_IN_BIT22: 397 case TEST_IN_FULL_SUPP_TRACE: 398 { 399 __u32 tmp32 = node2.egr_wide; 400 __u16 tmp16 = node2.egr_id; 401 int res; 402 403 node2.egr_id = 0xffff; 404 node2.egr_wide = 0xffffffff; 405 406 res = check_ioam6_data(&p, ioam6h, node2); 407 408 node2.egr_id = tmp16; 409 node2.egr_wide = tmp32; 410 411 return res; 412 } 413 414 case TEST_FWD_FULL_SUPP_TRACE: 415 if (check_ioam6_data(&p, ioam6h, node3)) 416 return 1; 417 if (check_ioam6_data(&p, ioam6h, node2)) 418 return 1; 419 return check_ioam6_data(&p, ioam6h, node1); 420 421 default: 422 break; 423 } 424 425 return 1; 426 } 427 428 static int str2id(const char *tname) 429 { 430 if (!strcmp("out_undef_ns", tname)) 431 return TEST_OUT_UNDEF_NS; 432 if (!strcmp("out_no_room", tname)) 433 return TEST_OUT_NO_ROOM; 434 if (!strcmp("out_bit0", tname)) 435 return TEST_OUT_BIT0; 436 if (!strcmp("out_bit1", tname)) 437 return TEST_OUT_BIT1; 438 if (!strcmp("out_bit2", tname)) 439 return TEST_OUT_BIT2; 440 if (!strcmp("out_bit3", tname)) 441 return TEST_OUT_BIT3; 442 if (!strcmp("out_bit4", tname)) 443 return TEST_OUT_BIT4; 444 if (!strcmp("out_bit5", tname)) 445 return TEST_OUT_BIT5; 446 if (!strcmp("out_bit6", tname)) 447 return TEST_OUT_BIT6; 448 if (!strcmp("out_bit7", tname)) 449 return TEST_OUT_BIT7; 450 if (!strcmp("out_bit8", tname)) 451 return TEST_OUT_BIT8; 452 if (!strcmp("out_bit9", tname)) 453 return TEST_OUT_BIT9; 454 if (!strcmp("out_bit10", tname)) 455 return TEST_OUT_BIT10; 456 if (!strcmp("out_bit11", tname)) 457 return TEST_OUT_BIT11; 458 if (!strcmp("out_bit12", tname)) 459 return TEST_OUT_BIT12; 460 if (!strcmp("out_bit13", tname)) 461 return TEST_OUT_BIT13; 462 if (!strcmp("out_bit14", tname)) 463 return TEST_OUT_BIT14; 464 if (!strcmp("out_bit15", tname)) 465 return TEST_OUT_BIT15; 466 if (!strcmp("out_bit16", tname)) 467 return TEST_OUT_BIT16; 468 if (!strcmp("out_bit17", tname)) 469 return TEST_OUT_BIT17; 470 if (!strcmp("out_bit18", tname)) 471 return TEST_OUT_BIT18; 472 if (!strcmp("out_bit19", tname)) 473 return TEST_OUT_BIT19; 474 if (!strcmp("out_bit20", tname)) 475 return TEST_OUT_BIT20; 476 if (!strcmp("out_bit21", tname)) 477 return TEST_OUT_BIT21; 478 if (!strcmp("out_bit22", tname)) 479 return TEST_OUT_BIT22; 480 if (!strcmp("out_full_supp_trace", tname)) 481 return TEST_OUT_FULL_SUPP_TRACE; 482 if (!strcmp("in_undef_ns", tname)) 483 return TEST_IN_UNDEF_NS; 484 if (!strcmp("in_no_room", tname)) 485 return TEST_IN_NO_ROOM; 486 if (!strcmp("in_oflag", tname)) 487 return TEST_IN_OFLAG; 488 if (!strcmp("in_bit0", tname)) 489 return TEST_IN_BIT0; 490 if (!strcmp("in_bit1", tname)) 491 return TEST_IN_BIT1; 492 if (!strcmp("in_bit2", tname)) 493 return TEST_IN_BIT2; 494 if (!strcmp("in_bit3", tname)) 495 return TEST_IN_BIT3; 496 if (!strcmp("in_bit4", tname)) 497 return TEST_IN_BIT4; 498 if (!strcmp("in_bit5", tname)) 499 return TEST_IN_BIT5; 500 if (!strcmp("in_bit6", tname)) 501 return TEST_IN_BIT6; 502 if (!strcmp("in_bit7", tname)) 503 return TEST_IN_BIT7; 504 if (!strcmp("in_bit8", tname)) 505 return TEST_IN_BIT8; 506 if (!strcmp("in_bit9", tname)) 507 return TEST_IN_BIT9; 508 if (!strcmp("in_bit10", tname)) 509 return TEST_IN_BIT10; 510 if (!strcmp("in_bit11", tname)) 511 return TEST_IN_BIT11; 512 if (!strcmp("in_bit12", tname)) 513 return TEST_IN_BIT12; 514 if (!strcmp("in_bit13", tname)) 515 return TEST_IN_BIT13; 516 if (!strcmp("in_bit14", tname)) 517 return TEST_IN_BIT14; 518 if (!strcmp("in_bit15", tname)) 519 return TEST_IN_BIT15; 520 if (!strcmp("in_bit16", tname)) 521 return TEST_IN_BIT16; 522 if (!strcmp("in_bit17", tname)) 523 return TEST_IN_BIT17; 524 if (!strcmp("in_bit18", tname)) 525 return TEST_IN_BIT18; 526 if (!strcmp("in_bit19", tname)) 527 return TEST_IN_BIT19; 528 if (!strcmp("in_bit20", tname)) 529 return TEST_IN_BIT20; 530 if (!strcmp("in_bit21", tname)) 531 return TEST_IN_BIT21; 532 if (!strcmp("in_bit22", tname)) 533 return TEST_IN_BIT22; 534 if (!strcmp("in_full_supp_trace", tname)) 535 return TEST_IN_FULL_SUPP_TRACE; 536 if (!strcmp("fwd_full_supp_trace", tname)) 537 return TEST_FWD_FULL_SUPP_TRACE; 538 539 return -1; 540 } 541 542 static int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2) 543 { 544 return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) | 545 (a1->s6_addr32[1] ^ a2->s6_addr32[1]) | 546 (a1->s6_addr32[2] ^ a2->s6_addr32[2]) | 547 (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0; 548 } 549 550 static int get_u32(__u32 *val, const char *arg, int base) 551 { 552 unsigned long res; 553 char *ptr; 554 555 if (!arg || !*arg) 556 return -1; 557 res = strtoul(arg, &ptr, base); 558 559 if (!ptr || ptr == arg || *ptr) 560 return -1; 561 562 if (res == ULONG_MAX && errno == ERANGE) 563 return -1; 564 565 if (res > 0xFFFFFFFFUL) 566 return -1; 567 568 *val = res; 569 return 0; 570 } 571 572 static int get_u16(__u16 *val, const char *arg, int base) 573 { 574 unsigned long res; 575 char *ptr; 576 577 if (!arg || !*arg) 578 return -1; 579 res = strtoul(arg, &ptr, base); 580 581 if (!ptr || ptr == arg || *ptr) 582 return -1; 583 584 if (res == ULONG_MAX && errno == ERANGE) 585 return -1; 586 587 if (res > 0xFFFFUL) 588 return -1; 589 590 *val = res; 591 return 0; 592 } 593 594 static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = { 595 [TEST_OUT_UNDEF_NS] = check_ioam_header, 596 [TEST_OUT_NO_ROOM] = check_ioam_header, 597 [TEST_OUT_BIT0] = check_ioam_header_and_data, 598 [TEST_OUT_BIT1] = check_ioam_header_and_data, 599 [TEST_OUT_BIT2] = check_ioam_header_and_data, 600 [TEST_OUT_BIT3] = check_ioam_header_and_data, 601 [TEST_OUT_BIT4] = check_ioam_header_and_data, 602 [TEST_OUT_BIT5] = check_ioam_header_and_data, 603 [TEST_OUT_BIT6] = check_ioam_header_and_data, 604 [TEST_OUT_BIT7] = check_ioam_header_and_data, 605 [TEST_OUT_BIT8] = check_ioam_header_and_data, 606 [TEST_OUT_BIT9] = check_ioam_header_and_data, 607 [TEST_OUT_BIT10] = check_ioam_header_and_data, 608 [TEST_OUT_BIT11] = check_ioam_header_and_data, 609 [TEST_OUT_BIT12] = check_ioam_header, 610 [TEST_OUT_BIT13] = check_ioam_header, 611 [TEST_OUT_BIT14] = check_ioam_header, 612 [TEST_OUT_BIT15] = check_ioam_header, 613 [TEST_OUT_BIT16] = check_ioam_header, 614 [TEST_OUT_BIT17] = check_ioam_header, 615 [TEST_OUT_BIT18] = check_ioam_header, 616 [TEST_OUT_BIT19] = check_ioam_header, 617 [TEST_OUT_BIT20] = check_ioam_header, 618 [TEST_OUT_BIT21] = check_ioam_header, 619 [TEST_OUT_BIT22] = check_ioam_header_and_data, 620 [TEST_OUT_FULL_SUPP_TRACE] = check_ioam_header_and_data, 621 [TEST_IN_UNDEF_NS] = check_ioam_header, 622 [TEST_IN_NO_ROOM] = check_ioam_header, 623 [TEST_IN_OFLAG] = check_ioam_header, 624 [TEST_IN_BIT0] = check_ioam_header_and_data, 625 [TEST_IN_BIT1] = check_ioam_header_and_data, 626 [TEST_IN_BIT2] = check_ioam_header_and_data, 627 [TEST_IN_BIT3] = check_ioam_header_and_data, 628 [TEST_IN_BIT4] = check_ioam_header_and_data, 629 [TEST_IN_BIT5] = check_ioam_header_and_data, 630 [TEST_IN_BIT6] = check_ioam_header_and_data, 631 [TEST_IN_BIT7] = check_ioam_header_and_data, 632 [TEST_IN_BIT8] = check_ioam_header_and_data, 633 [TEST_IN_BIT9] = check_ioam_header_and_data, 634 [TEST_IN_BIT10] = check_ioam_header_and_data, 635 [TEST_IN_BIT11] = check_ioam_header_and_data, 636 [TEST_IN_BIT12] = check_ioam_header, 637 [TEST_IN_BIT13] = check_ioam_header, 638 [TEST_IN_BIT14] = check_ioam_header, 639 [TEST_IN_BIT15] = check_ioam_header, 640 [TEST_IN_BIT16] = check_ioam_header, 641 [TEST_IN_BIT17] = check_ioam_header, 642 [TEST_IN_BIT18] = check_ioam_header, 643 [TEST_IN_BIT19] = check_ioam_header, 644 [TEST_IN_BIT20] = check_ioam_header, 645 [TEST_IN_BIT21] = check_ioam_header, 646 [TEST_IN_BIT22] = check_ioam_header_and_data, 647 [TEST_IN_FULL_SUPP_TRACE] = check_ioam_header_and_data, 648 [TEST_FWD_FULL_SUPP_TRACE] = check_ioam_header_and_data, 649 }; 650 651 int main(int argc, char **argv) 652 { 653 int fd, size, hoplen, tid, ret = 1; 654 struct in6_addr src, dst; 655 struct ioam6_hdr *opt; 656 struct ipv6hdr *ip6h; 657 __u8 buffer[400], *p; 658 __u16 ioam_ns; 659 __u32 tr_type; 660 661 if (argc != 7) 662 goto out; 663 664 tid = str2id(argv[2]); 665 if (tid < 0 || !func[tid]) 666 goto out; 667 668 if (inet_pton(AF_INET6, argv[3], &src) != 1 || 669 inet_pton(AF_INET6, argv[4], &dst) != 1) 670 goto out; 671 672 if (get_u32(&tr_type, argv[5], 16) || 673 get_u16(&ioam_ns, argv[6], 0)) 674 goto out; 675 676 fd = socket(AF_PACKET, SOCK_DGRAM, __cpu_to_be16(ETH_P_IPV6)); 677 if (!fd) 678 goto out; 679 680 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, 681 argv[1], strlen(argv[1]))) 682 goto close; 683 684 recv: 685 size = recv(fd, buffer, sizeof(buffer), 0); 686 if (size <= 0) 687 goto close; 688 689 ip6h = (struct ipv6hdr *)buffer; 690 691 if (!ipv6_addr_equal(&ip6h->saddr, &src) || 692 !ipv6_addr_equal(&ip6h->daddr, &dst)) 693 goto recv; 694 695 if (ip6h->nexthdr != IPPROTO_HOPOPTS) 696 goto close; 697 698 p = buffer + sizeof(*ip6h); 699 hoplen = (p[1] + 1) << 3; 700 p += sizeof(struct ipv6_hopopt_hdr); 701 702 while (hoplen > 0) { 703 opt = (struct ioam6_hdr *)p; 704 705 if (opt->opt_type == IPV6_TLV_IOAM && 706 opt->type == IOAM6_TYPE_PREALLOC) { 707 p += sizeof(*opt); 708 ret = func[tid](tid, (struct ioam6_trace_hdr *)p, 709 tr_type, ioam_ns); 710 break; 711 } 712 713 p += opt->opt_len + 2; 714 hoplen -= opt->opt_len + 2; 715 } 716 close: 717 close(fd); 718 out: 719 return ret; 720 } 721