xref: /openbmc/linux/tools/testing/selftests/net/ioam6_parser.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
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  
check_ioam_header(int tid,struct ioam6_trace_hdr * ioam6h,__u32 trace_type,__u16 ioam_ns)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  
check_ioam6_data(__u8 ** p,struct ioam6_trace_hdr * ioam6h,const struct ioam_config cnf)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  		*p += sizeof(__u32);
245  
246  	if (ioam6h->type.bit7) {
247  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
248  			return 1;
249  		*p += sizeof(__u32);
250  	}
251  
252  	if (ioam6h->type.bit8) {
253  		raw64 = __be64_to_cpu(*((__u64 *)*p));
254  		if (cnf.hlim != (raw64 >> 56) ||
255  		    cnf.wide != (raw64 & 0xffffffffffffff))
256  			return 1;
257  		*p += sizeof(__u64);
258  	}
259  
260  	if (ioam6h->type.bit9) {
261  		if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ingr_wide)
262  			return 1;
263  		*p += sizeof(__u32);
264  
265  		if (__be32_to_cpu(*((__u32 *)*p)) != cnf.egr_wide)
266  			return 1;
267  		*p += sizeof(__u32);
268  	}
269  
270  	if (ioam6h->type.bit10) {
271  		if (__be64_to_cpu(*((__u64 *)*p)) != cnf.ns_wide)
272  			return 1;
273  		*p += sizeof(__u64);
274  	}
275  
276  	if (ioam6h->type.bit11) {
277  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
278  			return 1;
279  		*p += sizeof(__u32);
280  	}
281  
282  	if (ioam6h->type.bit12) {
283  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
284  			return 1;
285  		*p += sizeof(__u32);
286  	}
287  
288  	if (ioam6h->type.bit13) {
289  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
290  			return 1;
291  		*p += sizeof(__u32);
292  	}
293  
294  	if (ioam6h->type.bit14) {
295  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
296  			return 1;
297  		*p += sizeof(__u32);
298  	}
299  
300  	if (ioam6h->type.bit15) {
301  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
302  			return 1;
303  		*p += sizeof(__u32);
304  	}
305  
306  	if (ioam6h->type.bit16) {
307  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
308  			return 1;
309  		*p += sizeof(__u32);
310  	}
311  
312  	if (ioam6h->type.bit17) {
313  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
314  			return 1;
315  		*p += sizeof(__u32);
316  	}
317  
318  	if (ioam6h->type.bit18) {
319  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
320  			return 1;
321  		*p += sizeof(__u32);
322  	}
323  
324  	if (ioam6h->type.bit19) {
325  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
326  			return 1;
327  		*p += sizeof(__u32);
328  	}
329  
330  	if (ioam6h->type.bit20) {
331  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
332  			return 1;
333  		*p += sizeof(__u32);
334  	}
335  
336  	if (ioam6h->type.bit21) {
337  		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
338  			return 1;
339  		*p += sizeof(__u32);
340  	}
341  
342  	if (ioam6h->type.bit22) {
343  		len = cnf.sc_data ? strlen(cnf.sc_data) : 0;
344  		aligned = cnf.sc_data ? __ALIGN_KERNEL(len, 4) : 0;
345  
346  		raw32 = __be32_to_cpu(*((__u32 *)*p));
347  		if (aligned != (raw32 >> 24) * 4 ||
348  		    cnf.sc_id != (raw32 & 0xffffff))
349  			return 1;
350  		*p += sizeof(__u32);
351  
352  		if (cnf.sc_data) {
353  			if (strncmp((char *)*p, cnf.sc_data, len))
354  				return 1;
355  
356  			*p += len;
357  			aligned -= len;
358  
359  			while (aligned--) {
360  				if (**p != '\0')
361  					return 1;
362  				*p += sizeof(__u8);
363  			}
364  		}
365  	}
366  
367  	return 0;
368  }
369  
check_ioam_header_and_data(int tid,struct ioam6_trace_hdr * ioam6h,__u32 trace_type,__u16 ioam_ns)370  static int check_ioam_header_and_data(int tid, struct ioam6_trace_hdr *ioam6h,
371  				      __u32 trace_type, __u16 ioam_ns)
372  {
373  	__u8 *p;
374  
375  	if (check_ioam_header(tid, ioam6h, trace_type, ioam_ns))
376  		return 1;
377  
378  	p = ioam6h->data + ioam6h->remlen * 4;
379  
380  	switch (tid) {
381  	case TEST_OUT_BIT0:
382  	case TEST_OUT_BIT1:
383  	case TEST_OUT_BIT2:
384  	case TEST_OUT_BIT3:
385  	case TEST_OUT_BIT4:
386  	case TEST_OUT_BIT5:
387  	case TEST_OUT_BIT6:
388  	case TEST_OUT_BIT7:
389  	case TEST_OUT_BIT8:
390  	case TEST_OUT_BIT9:
391  	case TEST_OUT_BIT10:
392  	case TEST_OUT_BIT11:
393  	case TEST_OUT_BIT22:
394  	case TEST_OUT_FULL_SUPP_TRACE:
395  		return check_ioam6_data(&p, ioam6h, node1);
396  
397  	case TEST_IN_BIT0:
398  	case TEST_IN_BIT1:
399  	case TEST_IN_BIT2:
400  	case TEST_IN_BIT3:
401  	case TEST_IN_BIT4:
402  	case TEST_IN_BIT5:
403  	case TEST_IN_BIT6:
404  	case TEST_IN_BIT7:
405  	case TEST_IN_BIT8:
406  	case TEST_IN_BIT9:
407  	case TEST_IN_BIT10:
408  	case TEST_IN_BIT11:
409  	case TEST_IN_BIT22:
410  	case TEST_IN_FULL_SUPP_TRACE:
411  	{
412  		__u32 tmp32 = node2.egr_wide;
413  		__u16 tmp16 = node2.egr_id;
414  		int res;
415  
416  		node2.egr_id = 0xffff;
417  		node2.egr_wide = 0xffffffff;
418  
419  		res = check_ioam6_data(&p, ioam6h, node2);
420  
421  		node2.egr_id = tmp16;
422  		node2.egr_wide = tmp32;
423  
424  		return res;
425  	}
426  
427  	case TEST_FWD_FULL_SUPP_TRACE:
428  		if (check_ioam6_data(&p, ioam6h, node3))
429  			return 1;
430  		if (check_ioam6_data(&p, ioam6h, node2))
431  			return 1;
432  		return check_ioam6_data(&p, ioam6h, node1);
433  
434  	default:
435  		break;
436  	}
437  
438  	return 1;
439  }
440  
str2id(const char * tname)441  static int str2id(const char *tname)
442  {
443  	if (!strcmp("out_undef_ns", tname))
444  		return TEST_OUT_UNDEF_NS;
445  	if (!strcmp("out_no_room", tname))
446  		return TEST_OUT_NO_ROOM;
447  	if (!strcmp("out_bit0", tname))
448  		return TEST_OUT_BIT0;
449  	if (!strcmp("out_bit1", tname))
450  		return TEST_OUT_BIT1;
451  	if (!strcmp("out_bit2", tname))
452  		return TEST_OUT_BIT2;
453  	if (!strcmp("out_bit3", tname))
454  		return TEST_OUT_BIT3;
455  	if (!strcmp("out_bit4", tname))
456  		return TEST_OUT_BIT4;
457  	if (!strcmp("out_bit5", tname))
458  		return TEST_OUT_BIT5;
459  	if (!strcmp("out_bit6", tname))
460  		return TEST_OUT_BIT6;
461  	if (!strcmp("out_bit7", tname))
462  		return TEST_OUT_BIT7;
463  	if (!strcmp("out_bit8", tname))
464  		return TEST_OUT_BIT8;
465  	if (!strcmp("out_bit9", tname))
466  		return TEST_OUT_BIT9;
467  	if (!strcmp("out_bit10", tname))
468  		return TEST_OUT_BIT10;
469  	if (!strcmp("out_bit11", tname))
470  		return TEST_OUT_BIT11;
471  	if (!strcmp("out_bit22", tname))
472  		return TEST_OUT_BIT22;
473  	if (!strcmp("out_full_supp_trace", tname))
474  		return TEST_OUT_FULL_SUPP_TRACE;
475  	if (!strcmp("in_undef_ns", tname))
476  		return TEST_IN_UNDEF_NS;
477  	if (!strcmp("in_no_room", tname))
478  		return TEST_IN_NO_ROOM;
479  	if (!strcmp("in_oflag", tname))
480  		return TEST_IN_OFLAG;
481  	if (!strcmp("in_bit0", tname))
482  		return TEST_IN_BIT0;
483  	if (!strcmp("in_bit1", tname))
484  		return TEST_IN_BIT1;
485  	if (!strcmp("in_bit2", tname))
486  		return TEST_IN_BIT2;
487  	if (!strcmp("in_bit3", tname))
488  		return TEST_IN_BIT3;
489  	if (!strcmp("in_bit4", tname))
490  		return TEST_IN_BIT4;
491  	if (!strcmp("in_bit5", tname))
492  		return TEST_IN_BIT5;
493  	if (!strcmp("in_bit6", tname))
494  		return TEST_IN_BIT6;
495  	if (!strcmp("in_bit7", tname))
496  		return TEST_IN_BIT7;
497  	if (!strcmp("in_bit8", tname))
498  		return TEST_IN_BIT8;
499  	if (!strcmp("in_bit9", tname))
500  		return TEST_IN_BIT9;
501  	if (!strcmp("in_bit10", tname))
502  		return TEST_IN_BIT10;
503  	if (!strcmp("in_bit11", tname))
504  		return TEST_IN_BIT11;
505  	if (!strcmp("in_bit22", tname))
506  		return TEST_IN_BIT22;
507  	if (!strcmp("in_full_supp_trace", tname))
508  		return TEST_IN_FULL_SUPP_TRACE;
509  	if (!strcmp("fwd_full_supp_trace", tname))
510  		return TEST_FWD_FULL_SUPP_TRACE;
511  
512  	return -1;
513  }
514  
ipv6_addr_equal(const struct in6_addr * a1,const struct in6_addr * a2)515  static int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2)
516  {
517  	return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) |
518  		(a1->s6_addr32[1] ^ a2->s6_addr32[1]) |
519  		(a1->s6_addr32[2] ^ a2->s6_addr32[2]) |
520  		(a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0;
521  }
522  
get_u32(__u32 * val,const char * arg,int base)523  static int get_u32(__u32 *val, const char *arg, int base)
524  {
525  	unsigned long res;
526  	char *ptr;
527  
528  	if (!arg || !*arg)
529  		return -1;
530  	res = strtoul(arg, &ptr, base);
531  
532  	if (!ptr || ptr == arg || *ptr)
533  		return -1;
534  
535  	if (res == ULONG_MAX && errno == ERANGE)
536  		return -1;
537  
538  	if (res > 0xFFFFFFFFUL)
539  		return -1;
540  
541  	*val = res;
542  	return 0;
543  }
544  
get_u16(__u16 * val,const char * arg,int base)545  static int get_u16(__u16 *val, const char *arg, int base)
546  {
547  	unsigned long res;
548  	char *ptr;
549  
550  	if (!arg || !*arg)
551  		return -1;
552  	res = strtoul(arg, &ptr, base);
553  
554  	if (!ptr || ptr == arg || *ptr)
555  		return -1;
556  
557  	if (res == ULONG_MAX && errno == ERANGE)
558  		return -1;
559  
560  	if (res > 0xFFFFUL)
561  		return -1;
562  
563  	*val = res;
564  	return 0;
565  }
566  
567  static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = {
568  	[TEST_OUT_UNDEF_NS]		= check_ioam_header,
569  	[TEST_OUT_NO_ROOM]		= check_ioam_header,
570  	[TEST_OUT_BIT0]		= check_ioam_header_and_data,
571  	[TEST_OUT_BIT1]		= check_ioam_header_and_data,
572  	[TEST_OUT_BIT2]		= check_ioam_header_and_data,
573  	[TEST_OUT_BIT3]		= check_ioam_header_and_data,
574  	[TEST_OUT_BIT4]		= check_ioam_header_and_data,
575  	[TEST_OUT_BIT5]		= check_ioam_header_and_data,
576  	[TEST_OUT_BIT6]		= check_ioam_header_and_data,
577  	[TEST_OUT_BIT7]		= check_ioam_header_and_data,
578  	[TEST_OUT_BIT8]		= check_ioam_header_and_data,
579  	[TEST_OUT_BIT9]		= check_ioam_header_and_data,
580  	[TEST_OUT_BIT10]		= check_ioam_header_and_data,
581  	[TEST_OUT_BIT11]		= check_ioam_header_and_data,
582  	[TEST_OUT_BIT22]		= check_ioam_header_and_data,
583  	[TEST_OUT_FULL_SUPP_TRACE]	= check_ioam_header_and_data,
584  	[TEST_IN_UNDEF_NS]		= check_ioam_header,
585  	[TEST_IN_NO_ROOM]		= check_ioam_header,
586  	[TEST_IN_OFLAG]		= check_ioam_header,
587  	[TEST_IN_BIT0]			= check_ioam_header_and_data,
588  	[TEST_IN_BIT1]			= check_ioam_header_and_data,
589  	[TEST_IN_BIT2]			= check_ioam_header_and_data,
590  	[TEST_IN_BIT3]			= check_ioam_header_and_data,
591  	[TEST_IN_BIT4]			= check_ioam_header_and_data,
592  	[TEST_IN_BIT5]			= check_ioam_header_and_data,
593  	[TEST_IN_BIT6]			= check_ioam_header_and_data,
594  	[TEST_IN_BIT7]			= check_ioam_header_and_data,
595  	[TEST_IN_BIT8]			= check_ioam_header_and_data,
596  	[TEST_IN_BIT9]			= check_ioam_header_and_data,
597  	[TEST_IN_BIT10]		= check_ioam_header_and_data,
598  	[TEST_IN_BIT11]		= check_ioam_header_and_data,
599  	[TEST_IN_BIT22]		= check_ioam_header_and_data,
600  	[TEST_IN_FULL_SUPP_TRACE]	= check_ioam_header_and_data,
601  	[TEST_FWD_FULL_SUPP_TRACE]	= check_ioam_header_and_data,
602  };
603  
main(int argc,char ** argv)604  int main(int argc, char **argv)
605  {
606  	int fd, size, hoplen, tid, ret = 1;
607  	struct in6_addr src, dst;
608  	struct ioam6_hdr *opt;
609  	struct ipv6hdr *ip6h;
610  	__u8 buffer[400], *p;
611  	__u16 ioam_ns;
612  	__u32 tr_type;
613  
614  	if (argc != 7)
615  		goto out;
616  
617  	tid = str2id(argv[2]);
618  	if (tid < 0 || !func[tid])
619  		goto out;
620  
621  	if (inet_pton(AF_INET6, argv[3], &src) != 1 ||
622  	    inet_pton(AF_INET6, argv[4], &dst) != 1)
623  		goto out;
624  
625  	if (get_u32(&tr_type, argv[5], 16) ||
626  	    get_u16(&ioam_ns, argv[6], 0))
627  		goto out;
628  
629  	fd = socket(AF_PACKET, SOCK_DGRAM, __cpu_to_be16(ETH_P_IPV6));
630  	if (!fd)
631  		goto out;
632  
633  	if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
634  		       argv[1], strlen(argv[1])))
635  		goto close;
636  
637  recv:
638  	size = recv(fd, buffer, sizeof(buffer), 0);
639  	if (size <= 0)
640  		goto close;
641  
642  	ip6h = (struct ipv6hdr *)buffer;
643  
644  	if (!ipv6_addr_equal(&ip6h->saddr, &src) ||
645  	    !ipv6_addr_equal(&ip6h->daddr, &dst))
646  		goto recv;
647  
648  	if (ip6h->nexthdr != IPPROTO_HOPOPTS)
649  		goto close;
650  
651  	p = buffer + sizeof(*ip6h);
652  	hoplen = (p[1] + 1) << 3;
653  	p += sizeof(struct ipv6_hopopt_hdr);
654  
655  	while (hoplen > 0) {
656  		opt = (struct ioam6_hdr *)p;
657  
658  		if (opt->opt_type == IPV6_TLV_IOAM &&
659  		    opt->type == IOAM6_TYPE_PREALLOC) {
660  			p += sizeof(*opt);
661  			ret = func[tid](tid, (struct ioam6_trace_hdr *)p,
662  					   tr_type, ioam_ns);
663  			break;
664  		}
665  
666  		p += opt->opt_len + 2;
667  		hoplen -= opt->opt_len + 2;
668  	}
669  close:
670  	close(fd);
671  out:
672  	return ret;
673  }
674