Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
18struct 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
37static 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
51static 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
65static 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
79enum {
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
149static 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
246static 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
357static 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
428static 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
542static 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
550static 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
572static 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
594static 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
651int 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
684recv:
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 }
716close:
717 close(fd);
718out:
719 return ret;
720}