0001
0002
0003
0004
0005
0006
0007 #include <arpa/inet.h>
0008 #include <errno.h>
0009 #include <limits.h>
0010 #include <linux/const.h>
0011 #include <linux/if_ether.h>
0012 #include <linux/ioam6.h>
0013 #include <linux/ipv6.h>
0014 #include <stdlib.h>
0015 #include <string.h>
0016 #include <unistd.h>
0017
0018 struct ioam_config {
0019 __u32 id;
0020 __u64 wide;
0021 __u16 ingr_id;
0022 __u16 egr_id;
0023 __u32 ingr_wide;
0024 __u32 egr_wide;
0025 __u32 ns_data;
0026 __u64 ns_wide;
0027 __u32 sc_id;
0028 __u8 hlim;
0029 char *sc_data;
0030 };
0031
0032
0033
0034
0035
0036
0037 static struct ioam_config node1 = {
0038 .id = 1,
0039 .wide = 11111111,
0040 .ingr_id = 0xffff,
0041 .egr_id = 101,
0042 .ingr_wide = 0xffffffff,
0043 .egr_wide = 101101,
0044 .ns_data = 0xdeadbee0,
0045 .ns_wide = 0xcafec0caf00dc0de,
0046 .sc_id = 777,
0047 .sc_data = "something that will be 4n-aligned",
0048 .hlim = 64,
0049 };
0050
0051 static struct ioam_config node2 = {
0052 .id = 2,
0053 .wide = 22222222,
0054 .ingr_id = 201,
0055 .egr_id = 202,
0056 .ingr_wide = 201201,
0057 .egr_wide = 202202,
0058 .ns_data = 0xdeadbee1,
0059 .ns_wide = 0xcafec0caf11dc0de,
0060 .sc_id = 666,
0061 .sc_data = "Hello there -Obi",
0062 .hlim = 63,
0063 };
0064
0065 static struct ioam_config node3 = {
0066 .id = 3,
0067 .wide = 33333333,
0068 .ingr_id = 301,
0069 .egr_id = 0xffff,
0070 .ingr_wide = 301301,
0071 .egr_wide = 0xffffffff,
0072 .ns_data = 0xdeadbee2,
0073 .ns_wide = 0xcafec0caf22dc0de,
0074 .sc_id = 0xffffff,
0075 .sc_data = NULL,
0076 .hlim = 62,
0077 };
0078
0079 enum {
0080
0081
0082
0083 TEST_OUT_UNDEF_NS,
0084 TEST_OUT_NO_ROOM,
0085 TEST_OUT_BIT0,
0086 TEST_OUT_BIT1,
0087 TEST_OUT_BIT2,
0088 TEST_OUT_BIT3,
0089 TEST_OUT_BIT4,
0090 TEST_OUT_BIT5,
0091 TEST_OUT_BIT6,
0092 TEST_OUT_BIT7,
0093 TEST_OUT_BIT8,
0094 TEST_OUT_BIT9,
0095 TEST_OUT_BIT10,
0096 TEST_OUT_BIT11,
0097 TEST_OUT_BIT22,
0098 TEST_OUT_FULL_SUPP_TRACE,
0099
0100
0101
0102
0103 TEST_IN_UNDEF_NS,
0104 TEST_IN_NO_ROOM,
0105 TEST_IN_OFLAG,
0106 TEST_IN_BIT0,
0107 TEST_IN_BIT1,
0108 TEST_IN_BIT2,
0109 TEST_IN_BIT3,
0110 TEST_IN_BIT4,
0111 TEST_IN_BIT5,
0112 TEST_IN_BIT6,
0113 TEST_IN_BIT7,
0114 TEST_IN_BIT8,
0115 TEST_IN_BIT9,
0116 TEST_IN_BIT10,
0117 TEST_IN_BIT11,
0118 TEST_IN_BIT22,
0119 TEST_IN_FULL_SUPP_TRACE,
0120
0121
0122
0123
0124 TEST_FWD_FULL_SUPP_TRACE,
0125
0126 __TEST_MAX,
0127 };
0128
0129 static int check_ioam_header(int tid, struct ioam6_trace_hdr *ioam6h,
0130 __u32 trace_type, __u16 ioam_ns)
0131 {
0132 if (__be16_to_cpu(ioam6h->namespace_id) != ioam_ns ||
0133 __be32_to_cpu(ioam6h->type_be32) != (trace_type << 8))
0134 return 1;
0135
0136 switch (tid) {
0137 case TEST_OUT_UNDEF_NS:
0138 case TEST_IN_UNDEF_NS:
0139 return ioam6h->overflow ||
0140 ioam6h->nodelen != 1 ||
0141 ioam6h->remlen != 1;
0142
0143 case TEST_OUT_NO_ROOM:
0144 case TEST_IN_NO_ROOM:
0145 case TEST_IN_OFLAG:
0146 return !ioam6h->overflow ||
0147 ioam6h->nodelen != 2 ||
0148 ioam6h->remlen != 1;
0149
0150 case TEST_OUT_BIT0:
0151 case TEST_IN_BIT0:
0152 case TEST_OUT_BIT1:
0153 case TEST_IN_BIT1:
0154 case TEST_OUT_BIT2:
0155 case TEST_IN_BIT2:
0156 case TEST_OUT_BIT3:
0157 case TEST_IN_BIT3:
0158 case TEST_OUT_BIT4:
0159 case TEST_IN_BIT4:
0160 case TEST_OUT_BIT5:
0161 case TEST_IN_BIT5:
0162 case TEST_OUT_BIT6:
0163 case TEST_IN_BIT6:
0164 case TEST_OUT_BIT7:
0165 case TEST_IN_BIT7:
0166 case TEST_OUT_BIT11:
0167 case TEST_IN_BIT11:
0168 return ioam6h->overflow ||
0169 ioam6h->nodelen != 1 ||
0170 ioam6h->remlen;
0171
0172 case TEST_OUT_BIT8:
0173 case TEST_IN_BIT8:
0174 case TEST_OUT_BIT9:
0175 case TEST_IN_BIT9:
0176 case TEST_OUT_BIT10:
0177 case TEST_IN_BIT10:
0178 return ioam6h->overflow ||
0179 ioam6h->nodelen != 2 ||
0180 ioam6h->remlen;
0181
0182 case TEST_OUT_BIT22:
0183 case TEST_IN_BIT22:
0184 return ioam6h->overflow ||
0185 ioam6h->nodelen ||
0186 ioam6h->remlen;
0187
0188 case TEST_OUT_FULL_SUPP_TRACE:
0189 case TEST_IN_FULL_SUPP_TRACE:
0190 case TEST_FWD_FULL_SUPP_TRACE:
0191 return ioam6h->overflow ||
0192 ioam6h->nodelen != 15 ||
0193 ioam6h->remlen;
0194
0195 default:
0196 break;
0197 }
0198
0199 return 1;
0200 }
0201
0202 static int check_ioam6_data(__u8 **p, struct ioam6_trace_hdr *ioam6h,
0203 const struct ioam_config cnf)
0204 {
0205 unsigned int len;
0206 __u8 aligned;
0207 __u64 raw64;
0208 __u32 raw32;
0209
0210 if (ioam6h->type.bit0) {
0211 raw32 = __be32_to_cpu(*((__u32 *)*p));
0212 if (cnf.hlim != (raw32 >> 24) || cnf.id != (raw32 & 0xffffff))
0213 return 1;
0214 *p += sizeof(__u32);
0215 }
0216
0217 if (ioam6h->type.bit1) {
0218 raw32 = __be32_to_cpu(*((__u32 *)*p));
0219 if (cnf.ingr_id != (raw32 >> 16) ||
0220 cnf.egr_id != (raw32 & 0xffff))
0221 return 1;
0222 *p += sizeof(__u32);
0223 }
0224
0225 if (ioam6h->type.bit2)
0226 *p += sizeof(__u32);
0227
0228 if (ioam6h->type.bit3)
0229 *p += sizeof(__u32);
0230
0231 if (ioam6h->type.bit4) {
0232 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0233 return 1;
0234 *p += sizeof(__u32);
0235 }
0236
0237 if (ioam6h->type.bit5) {
0238 if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ns_data)
0239 return 1;
0240 *p += sizeof(__u32);
0241 }
0242
0243 if (ioam6h->type.bit6)
0244 *p += sizeof(__u32);
0245
0246 if (ioam6h->type.bit7) {
0247 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0248 return 1;
0249 *p += sizeof(__u32);
0250 }
0251
0252 if (ioam6h->type.bit8) {
0253 raw64 = __be64_to_cpu(*((__u64 *)*p));
0254 if (cnf.hlim != (raw64 >> 56) ||
0255 cnf.wide != (raw64 & 0xffffffffffffff))
0256 return 1;
0257 *p += sizeof(__u64);
0258 }
0259
0260 if (ioam6h->type.bit9) {
0261 if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ingr_wide)
0262 return 1;
0263 *p += sizeof(__u32);
0264
0265 if (__be32_to_cpu(*((__u32 *)*p)) != cnf.egr_wide)
0266 return 1;
0267 *p += sizeof(__u32);
0268 }
0269
0270 if (ioam6h->type.bit10) {
0271 if (__be64_to_cpu(*((__u64 *)*p)) != cnf.ns_wide)
0272 return 1;
0273 *p += sizeof(__u64);
0274 }
0275
0276 if (ioam6h->type.bit11) {
0277 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0278 return 1;
0279 *p += sizeof(__u32);
0280 }
0281
0282 if (ioam6h->type.bit12) {
0283 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0284 return 1;
0285 *p += sizeof(__u32);
0286 }
0287
0288 if (ioam6h->type.bit13) {
0289 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0290 return 1;
0291 *p += sizeof(__u32);
0292 }
0293
0294 if (ioam6h->type.bit14) {
0295 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0296 return 1;
0297 *p += sizeof(__u32);
0298 }
0299
0300 if (ioam6h->type.bit15) {
0301 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0302 return 1;
0303 *p += sizeof(__u32);
0304 }
0305
0306 if (ioam6h->type.bit16) {
0307 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0308 return 1;
0309 *p += sizeof(__u32);
0310 }
0311
0312 if (ioam6h->type.bit17) {
0313 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0314 return 1;
0315 *p += sizeof(__u32);
0316 }
0317
0318 if (ioam6h->type.bit18) {
0319 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0320 return 1;
0321 *p += sizeof(__u32);
0322 }
0323
0324 if (ioam6h->type.bit19) {
0325 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0326 return 1;
0327 *p += sizeof(__u32);
0328 }
0329
0330 if (ioam6h->type.bit20) {
0331 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0332 return 1;
0333 *p += sizeof(__u32);
0334 }
0335
0336 if (ioam6h->type.bit21) {
0337 if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0338 return 1;
0339 *p += sizeof(__u32);
0340 }
0341
0342 if (ioam6h->type.bit22) {
0343 len = cnf.sc_data ? strlen(cnf.sc_data) : 0;
0344 aligned = cnf.sc_data ? __ALIGN_KERNEL(len, 4) : 0;
0345
0346 raw32 = __be32_to_cpu(*((__u32 *)*p));
0347 if (aligned != (raw32 >> 24) * 4 ||
0348 cnf.sc_id != (raw32 & 0xffffff))
0349 return 1;
0350 *p += sizeof(__u32);
0351
0352 if (cnf.sc_data) {
0353 if (strncmp((char *)*p, cnf.sc_data, len))
0354 return 1;
0355
0356 *p += len;
0357 aligned -= len;
0358
0359 while (aligned--) {
0360 if (**p != '\0')
0361 return 1;
0362 *p += sizeof(__u8);
0363 }
0364 }
0365 }
0366
0367 return 0;
0368 }
0369
0370 static int check_ioam_header_and_data(int tid, struct ioam6_trace_hdr *ioam6h,
0371 __u32 trace_type, __u16 ioam_ns)
0372 {
0373 __u8 *p;
0374
0375 if (check_ioam_header(tid, ioam6h, trace_type, ioam_ns))
0376 return 1;
0377
0378 p = ioam6h->data + ioam6h->remlen * 4;
0379
0380 switch (tid) {
0381 case TEST_OUT_BIT0:
0382 case TEST_OUT_BIT1:
0383 case TEST_OUT_BIT2:
0384 case TEST_OUT_BIT3:
0385 case TEST_OUT_BIT4:
0386 case TEST_OUT_BIT5:
0387 case TEST_OUT_BIT6:
0388 case TEST_OUT_BIT7:
0389 case TEST_OUT_BIT8:
0390 case TEST_OUT_BIT9:
0391 case TEST_OUT_BIT10:
0392 case TEST_OUT_BIT11:
0393 case TEST_OUT_BIT22:
0394 case TEST_OUT_FULL_SUPP_TRACE:
0395 return check_ioam6_data(&p, ioam6h, node1);
0396
0397 case TEST_IN_BIT0:
0398 case TEST_IN_BIT1:
0399 case TEST_IN_BIT2:
0400 case TEST_IN_BIT3:
0401 case TEST_IN_BIT4:
0402 case TEST_IN_BIT5:
0403 case TEST_IN_BIT6:
0404 case TEST_IN_BIT7:
0405 case TEST_IN_BIT8:
0406 case TEST_IN_BIT9:
0407 case TEST_IN_BIT10:
0408 case TEST_IN_BIT11:
0409 case TEST_IN_BIT22:
0410 case TEST_IN_FULL_SUPP_TRACE:
0411 {
0412 __u32 tmp32 = node2.egr_wide;
0413 __u16 tmp16 = node2.egr_id;
0414 int res;
0415
0416 node2.egr_id = 0xffff;
0417 node2.egr_wide = 0xffffffff;
0418
0419 res = check_ioam6_data(&p, ioam6h, node2);
0420
0421 node2.egr_id = tmp16;
0422 node2.egr_wide = tmp32;
0423
0424 return res;
0425 }
0426
0427 case TEST_FWD_FULL_SUPP_TRACE:
0428 if (check_ioam6_data(&p, ioam6h, node3))
0429 return 1;
0430 if (check_ioam6_data(&p, ioam6h, node2))
0431 return 1;
0432 return check_ioam6_data(&p, ioam6h, node1);
0433
0434 default:
0435 break;
0436 }
0437
0438 return 1;
0439 }
0440
0441 static int str2id(const char *tname)
0442 {
0443 if (!strcmp("out_undef_ns", tname))
0444 return TEST_OUT_UNDEF_NS;
0445 if (!strcmp("out_no_room", tname))
0446 return TEST_OUT_NO_ROOM;
0447 if (!strcmp("out_bit0", tname))
0448 return TEST_OUT_BIT0;
0449 if (!strcmp("out_bit1", tname))
0450 return TEST_OUT_BIT1;
0451 if (!strcmp("out_bit2", tname))
0452 return TEST_OUT_BIT2;
0453 if (!strcmp("out_bit3", tname))
0454 return TEST_OUT_BIT3;
0455 if (!strcmp("out_bit4", tname))
0456 return TEST_OUT_BIT4;
0457 if (!strcmp("out_bit5", tname))
0458 return TEST_OUT_BIT5;
0459 if (!strcmp("out_bit6", tname))
0460 return TEST_OUT_BIT6;
0461 if (!strcmp("out_bit7", tname))
0462 return TEST_OUT_BIT7;
0463 if (!strcmp("out_bit8", tname))
0464 return TEST_OUT_BIT8;
0465 if (!strcmp("out_bit9", tname))
0466 return TEST_OUT_BIT9;
0467 if (!strcmp("out_bit10", tname))
0468 return TEST_OUT_BIT10;
0469 if (!strcmp("out_bit11", tname))
0470 return TEST_OUT_BIT11;
0471 if (!strcmp("out_bit22", tname))
0472 return TEST_OUT_BIT22;
0473 if (!strcmp("out_full_supp_trace", tname))
0474 return TEST_OUT_FULL_SUPP_TRACE;
0475 if (!strcmp("in_undef_ns", tname))
0476 return TEST_IN_UNDEF_NS;
0477 if (!strcmp("in_no_room", tname))
0478 return TEST_IN_NO_ROOM;
0479 if (!strcmp("in_oflag", tname))
0480 return TEST_IN_OFLAG;
0481 if (!strcmp("in_bit0", tname))
0482 return TEST_IN_BIT0;
0483 if (!strcmp("in_bit1", tname))
0484 return TEST_IN_BIT1;
0485 if (!strcmp("in_bit2", tname))
0486 return TEST_IN_BIT2;
0487 if (!strcmp("in_bit3", tname))
0488 return TEST_IN_BIT3;
0489 if (!strcmp("in_bit4", tname))
0490 return TEST_IN_BIT4;
0491 if (!strcmp("in_bit5", tname))
0492 return TEST_IN_BIT5;
0493 if (!strcmp("in_bit6", tname))
0494 return TEST_IN_BIT6;
0495 if (!strcmp("in_bit7", tname))
0496 return TEST_IN_BIT7;
0497 if (!strcmp("in_bit8", tname))
0498 return TEST_IN_BIT8;
0499 if (!strcmp("in_bit9", tname))
0500 return TEST_IN_BIT9;
0501 if (!strcmp("in_bit10", tname))
0502 return TEST_IN_BIT10;
0503 if (!strcmp("in_bit11", tname))
0504 return TEST_IN_BIT11;
0505 if (!strcmp("in_bit22", tname))
0506 return TEST_IN_BIT22;
0507 if (!strcmp("in_full_supp_trace", tname))
0508 return TEST_IN_FULL_SUPP_TRACE;
0509 if (!strcmp("fwd_full_supp_trace", tname))
0510 return TEST_FWD_FULL_SUPP_TRACE;
0511
0512 return -1;
0513 }
0514
0515 static int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2)
0516 {
0517 return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) |
0518 (a1->s6_addr32[1] ^ a2->s6_addr32[1]) |
0519 (a1->s6_addr32[2] ^ a2->s6_addr32[2]) |
0520 (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0;
0521 }
0522
0523 static int get_u32(__u32 *val, const char *arg, int base)
0524 {
0525 unsigned long res;
0526 char *ptr;
0527
0528 if (!arg || !*arg)
0529 return -1;
0530 res = strtoul(arg, &ptr, base);
0531
0532 if (!ptr || ptr == arg || *ptr)
0533 return -1;
0534
0535 if (res == ULONG_MAX && errno == ERANGE)
0536 return -1;
0537
0538 if (res > 0xFFFFFFFFUL)
0539 return -1;
0540
0541 *val = res;
0542 return 0;
0543 }
0544
0545 static int get_u16(__u16 *val, const char *arg, int base)
0546 {
0547 unsigned long res;
0548 char *ptr;
0549
0550 if (!arg || !*arg)
0551 return -1;
0552 res = strtoul(arg, &ptr, base);
0553
0554 if (!ptr || ptr == arg || *ptr)
0555 return -1;
0556
0557 if (res == ULONG_MAX && errno == ERANGE)
0558 return -1;
0559
0560 if (res > 0xFFFFUL)
0561 return -1;
0562
0563 *val = res;
0564 return 0;
0565 }
0566
0567 static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = {
0568 [TEST_OUT_UNDEF_NS] = check_ioam_header,
0569 [TEST_OUT_NO_ROOM] = check_ioam_header,
0570 [TEST_OUT_BIT0] = check_ioam_header_and_data,
0571 [TEST_OUT_BIT1] = check_ioam_header_and_data,
0572 [TEST_OUT_BIT2] = check_ioam_header_and_data,
0573 [TEST_OUT_BIT3] = check_ioam_header_and_data,
0574 [TEST_OUT_BIT4] = check_ioam_header_and_data,
0575 [TEST_OUT_BIT5] = check_ioam_header_and_data,
0576 [TEST_OUT_BIT6] = check_ioam_header_and_data,
0577 [TEST_OUT_BIT7] = check_ioam_header_and_data,
0578 [TEST_OUT_BIT8] = check_ioam_header_and_data,
0579 [TEST_OUT_BIT9] = check_ioam_header_and_data,
0580 [TEST_OUT_BIT10] = check_ioam_header_and_data,
0581 [TEST_OUT_BIT11] = check_ioam_header_and_data,
0582 [TEST_OUT_BIT22] = check_ioam_header_and_data,
0583 [TEST_OUT_FULL_SUPP_TRACE] = check_ioam_header_and_data,
0584 [TEST_IN_UNDEF_NS] = check_ioam_header,
0585 [TEST_IN_NO_ROOM] = check_ioam_header,
0586 [TEST_IN_OFLAG] = check_ioam_header,
0587 [TEST_IN_BIT0] = check_ioam_header_and_data,
0588 [TEST_IN_BIT1] = check_ioam_header_and_data,
0589 [TEST_IN_BIT2] = check_ioam_header_and_data,
0590 [TEST_IN_BIT3] = check_ioam_header_and_data,
0591 [TEST_IN_BIT4] = check_ioam_header_and_data,
0592 [TEST_IN_BIT5] = check_ioam_header_and_data,
0593 [TEST_IN_BIT6] = check_ioam_header_and_data,
0594 [TEST_IN_BIT7] = check_ioam_header_and_data,
0595 [TEST_IN_BIT8] = check_ioam_header_and_data,
0596 [TEST_IN_BIT9] = check_ioam_header_and_data,
0597 [TEST_IN_BIT10] = check_ioam_header_and_data,
0598 [TEST_IN_BIT11] = check_ioam_header_and_data,
0599 [TEST_IN_BIT22] = check_ioam_header_and_data,
0600 [TEST_IN_FULL_SUPP_TRACE] = check_ioam_header_and_data,
0601 [TEST_FWD_FULL_SUPP_TRACE] = check_ioam_header_and_data,
0602 };
0603
0604 int main(int argc, char **argv)
0605 {
0606 int fd, size, hoplen, tid, ret = 1;
0607 struct in6_addr src, dst;
0608 struct ioam6_hdr *opt;
0609 struct ipv6hdr *ip6h;
0610 __u8 buffer[400], *p;
0611 __u16 ioam_ns;
0612 __u32 tr_type;
0613
0614 if (argc != 7)
0615 goto out;
0616
0617 tid = str2id(argv[2]);
0618 if (tid < 0 || !func[tid])
0619 goto out;
0620
0621 if (inet_pton(AF_INET6, argv[3], &src) != 1 ||
0622 inet_pton(AF_INET6, argv[4], &dst) != 1)
0623 goto out;
0624
0625 if (get_u32(&tr_type, argv[5], 16) ||
0626 get_u16(&ioam_ns, argv[6], 0))
0627 goto out;
0628
0629 fd = socket(AF_PACKET, SOCK_DGRAM, __cpu_to_be16(ETH_P_IPV6));
0630 if (!fd)
0631 goto out;
0632
0633 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
0634 argv[1], strlen(argv[1])))
0635 goto close;
0636
0637 recv:
0638 size = recv(fd, buffer, sizeof(buffer), 0);
0639 if (size <= 0)
0640 goto close;
0641
0642 ip6h = (struct ipv6hdr *)buffer;
0643
0644 if (!ipv6_addr_equal(&ip6h->saddr, &src) ||
0645 !ipv6_addr_equal(&ip6h->daddr, &dst))
0646 goto recv;
0647
0648 if (ip6h->nexthdr != IPPROTO_HOPOPTS)
0649 goto close;
0650
0651 p = buffer + sizeof(*ip6h);
0652 hoplen = (p[1] + 1) << 3;
0653 p += sizeof(struct ipv6_hopopt_hdr);
0654
0655 while (hoplen > 0) {
0656 opt = (struct ioam6_hdr *)p;
0657
0658 if (opt->opt_type == IPV6_TLV_IOAM &&
0659 opt->type == IOAM6_TYPE_PREALLOC) {
0660 p += sizeof(*opt);
0661 ret = func[tid](tid, (struct ioam6_trace_hdr *)p,
0662 tr_type, ioam_ns);
0663 break;
0664 }
0665
0666 p += opt->opt_len + 2;
0667 hoplen -= opt->opt_len + 2;
0668 }
0669 close:
0670 close(fd);
0671 out:
0672 return ret;
0673 }