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