Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
Note: File does not exist in v4.10.11.
  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/ioam6.h>
 12#include <linux/ipv6.h>
 13#include <stdlib.h>
 14#include <string.h>
 15#include <unistd.h>
 16
 17struct ioam_config {
 18	__u32 id;
 19	__u64 wide;
 20	__u16 ingr_id;
 21	__u16 egr_id;
 22	__u32 ingr_wide;
 23	__u32 egr_wide;
 24	__u32 ns_data;
 25	__u64 ns_wide;
 26	__u32 sc_id;
 27	__u8 hlim;
 28	char *sc_data;
 29};
 30
 31/*
 32 * Be careful if you modify structs below - everything MUST be kept synchronized
 33 * with configurations inside ioam6.sh and always reflect the same.
 34 */
 35
 36static struct ioam_config node1 = {
 37	.id = 1,
 38	.wide = 11111111,
 39	.ingr_id = 0xffff, /* default value */
 40	.egr_id = 101,
 41	.ingr_wide = 0xffffffff, /* default value */
 42	.egr_wide = 101101,
 43	.ns_data = 0xdeadbee0,
 44	.ns_wide = 0xcafec0caf00dc0de,
 45	.sc_id = 777,
 46	.sc_data = "something that will be 4n-aligned",
 47	.hlim = 64,
 48};
 49
 50static struct ioam_config node2 = {
 51	.id = 2,
 52	.wide = 22222222,
 53	.ingr_id = 201,
 54	.egr_id = 202,
 55	.ingr_wide = 201201,
 56	.egr_wide = 202202,
 57	.ns_data = 0xdeadbee1,
 58	.ns_wide = 0xcafec0caf11dc0de,
 59	.sc_id = 666,
 60	.sc_data = "Hello there -Obi",
 61	.hlim = 63,
 62};
 63
 64static struct ioam_config node3 = {
 65	.id = 3,
 66	.wide = 33333333,
 67	.ingr_id = 301,
 68	.egr_id = 0xffff, /* default value */
 69	.ingr_wide = 301301,
 70	.egr_wide = 0xffffffff, /* default value */
 71	.ns_data = 0xdeadbee2,
 72	.ns_wide = 0xcafec0caf22dc0de,
 73	.sc_id = 0xffffff, /* default value */
 74	.sc_data = NULL,
 75	.hlim = 62,
 76};
 77
 78enum {
 79	/**********
 80	 * OUTPUT *
 81	 **********/
 82	TEST_OUT_UNDEF_NS,
 83	TEST_OUT_NO_ROOM,
 84	TEST_OUT_BIT0,
 85	TEST_OUT_BIT1,
 86	TEST_OUT_BIT2,
 87	TEST_OUT_BIT3,
 88	TEST_OUT_BIT4,
 89	TEST_OUT_BIT5,
 90	TEST_OUT_BIT6,
 91	TEST_OUT_BIT7,
 92	TEST_OUT_BIT8,
 93	TEST_OUT_BIT9,
 94	TEST_OUT_BIT10,
 95	TEST_OUT_BIT11,
 96	TEST_OUT_BIT22,
 97	TEST_OUT_FULL_SUPP_TRACE,
 98
 99	/*********
100	 * INPUT *
101	 *********/
102	TEST_IN_UNDEF_NS,
103	TEST_IN_NO_ROOM,
104	TEST_IN_OFLAG,
105	TEST_IN_BIT0,
106	TEST_IN_BIT1,
107	TEST_IN_BIT2,
108	TEST_IN_BIT3,
109	TEST_IN_BIT4,
110	TEST_IN_BIT5,
111	TEST_IN_BIT6,
112	TEST_IN_BIT7,
113	TEST_IN_BIT8,
114	TEST_IN_BIT9,
115	TEST_IN_BIT10,
116	TEST_IN_BIT11,
117	TEST_IN_BIT22,
118	TEST_IN_FULL_SUPP_TRACE,
119
120	/**********
121	 * GLOBAL *
122	 **********/
123	TEST_FWD_FULL_SUPP_TRACE,
124
125	__TEST_MAX,
126};
127
128static int check_ioam_header(int tid, struct ioam6_trace_hdr *ioam6h,
129			     __u32 trace_type, __u16 ioam_ns)
130{
131	if (__be16_to_cpu(ioam6h->namespace_id) != ioam_ns ||
132	    __be32_to_cpu(ioam6h->type_be32) != (trace_type << 8))
133		return 1;
134
135	switch (tid) {
136	case TEST_OUT_UNDEF_NS:
137	case TEST_IN_UNDEF_NS:
138		return ioam6h->overflow ||
139		       ioam6h->nodelen != 1 ||
140		       ioam6h->remlen != 1;
141
142	case TEST_OUT_NO_ROOM:
143	case TEST_IN_NO_ROOM:
144	case TEST_IN_OFLAG:
145		return !ioam6h->overflow ||
146		       ioam6h->nodelen != 2 ||
147		       ioam6h->remlen != 1;
148
149	case TEST_OUT_BIT0:
150	case TEST_IN_BIT0:
151	case TEST_OUT_BIT1:
152	case TEST_IN_BIT1:
153	case TEST_OUT_BIT2:
154	case TEST_IN_BIT2:
155	case TEST_OUT_BIT3:
156	case TEST_IN_BIT3:
157	case TEST_OUT_BIT4:
158	case TEST_IN_BIT4:
159	case TEST_OUT_BIT5:
160	case TEST_IN_BIT5:
161	case TEST_OUT_BIT6:
162	case TEST_IN_BIT6:
163	case TEST_OUT_BIT7:
164	case TEST_IN_BIT7:
165	case TEST_OUT_BIT11:
166	case TEST_IN_BIT11:
167		return ioam6h->overflow ||
168		       ioam6h->nodelen != 1 ||
169		       ioam6h->remlen;
170
171	case TEST_OUT_BIT8:
172	case TEST_IN_BIT8:
173	case TEST_OUT_BIT9:
174	case TEST_IN_BIT9:
175	case TEST_OUT_BIT10:
176	case TEST_IN_BIT10:
177		return ioam6h->overflow ||
178		       ioam6h->nodelen != 2 ||
179		       ioam6h->remlen;
180
181	case TEST_OUT_BIT22:
182	case TEST_IN_BIT22:
183		return ioam6h->overflow ||
184		       ioam6h->nodelen ||
185		       ioam6h->remlen;
186
187	case TEST_OUT_FULL_SUPP_TRACE:
188	case TEST_IN_FULL_SUPP_TRACE:
189	case TEST_FWD_FULL_SUPP_TRACE:
190		return ioam6h->overflow ||
191		       ioam6h->nodelen != 15 ||
192		       ioam6h->remlen;
193
194	default:
195		break;
196	}
197
198	return 1;
199}
200
201static int check_ioam6_data(__u8 **p, struct ioam6_trace_hdr *ioam6h,
202			    const struct ioam_config cnf)
203{
204	unsigned int len;
205	__u8 aligned;
206	__u64 raw64;
207	__u32 raw32;
208
209	if (ioam6h->type.bit0) {
210		raw32 = __be32_to_cpu(*((__u32 *)*p));
211		if (cnf.hlim != (raw32 >> 24) || cnf.id != (raw32 & 0xffffff))
212			return 1;
213		*p += sizeof(__u32);
214	}
215
216	if (ioam6h->type.bit1) {
217		raw32 = __be32_to_cpu(*((__u32 *)*p));
218		if (cnf.ingr_id != (raw32 >> 16) ||
219		    cnf.egr_id != (raw32 & 0xffff))
220			return 1;
221		*p += sizeof(__u32);
222	}
223
224	if (ioam6h->type.bit2)
225		*p += sizeof(__u32);
226
227	if (ioam6h->type.bit3)
228		*p += sizeof(__u32);
229
230	if (ioam6h->type.bit4) {
231		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
232			return 1;
233		*p += sizeof(__u32);
234	}
235
236	if (ioam6h->type.bit5) {
237		if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ns_data)
238			return 1;
239		*p += sizeof(__u32);
240	}
241
242	if (ioam6h->type.bit6)
243		*p += sizeof(__u32);
244
245	if (ioam6h->type.bit7) {
246		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
247			return 1;
248		*p += sizeof(__u32);
249	}
250
251	if (ioam6h->type.bit8) {
252		raw64 = __be64_to_cpu(*((__u64 *)*p));
253		if (cnf.hlim != (raw64 >> 56) ||
254		    cnf.wide != (raw64 & 0xffffffffffffff))
255			return 1;
256		*p += sizeof(__u64);
257	}
258
259	if (ioam6h->type.bit9) {
260		if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ingr_wide)
261			return 1;
262		*p += sizeof(__u32);
263
264		if (__be32_to_cpu(*((__u32 *)*p)) != cnf.egr_wide)
265			return 1;
266		*p += sizeof(__u32);
267	}
268
269	if (ioam6h->type.bit10) {
270		if (__be64_to_cpu(*((__u64 *)*p)) != cnf.ns_wide)
271			return 1;
272		*p += sizeof(__u64);
273	}
274
275	if (ioam6h->type.bit11) {
276		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
277			return 1;
278		*p += sizeof(__u32);
279	}
280
281	if (ioam6h->type.bit12) {
282		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
283			return 1;
284		*p += sizeof(__u32);
285	}
286
287	if (ioam6h->type.bit13) {
288		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
289			return 1;
290		*p += sizeof(__u32);
291	}
292
293	if (ioam6h->type.bit14) {
294		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
295			return 1;
296		*p += sizeof(__u32);
297	}
298
299	if (ioam6h->type.bit15) {
300		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
301			return 1;
302		*p += sizeof(__u32);
303	}
304
305	if (ioam6h->type.bit16) {
306		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
307			return 1;
308		*p += sizeof(__u32);
309	}
310
311	if (ioam6h->type.bit17) {
312		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
313			return 1;
314		*p += sizeof(__u32);
315	}
316
317	if (ioam6h->type.bit18) {
318		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
319			return 1;
320		*p += sizeof(__u32);
321	}
322
323	if (ioam6h->type.bit19) {
324		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
325			return 1;
326		*p += sizeof(__u32);
327	}
328
329	if (ioam6h->type.bit20) {
330		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
331			return 1;
332		*p += sizeof(__u32);
333	}
334
335	if (ioam6h->type.bit21) {
336		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
337			return 1;
338		*p += sizeof(__u32);
339	}
340
341	if (ioam6h->type.bit22) {
342		len = cnf.sc_data ? strlen(cnf.sc_data) : 0;
343		aligned = cnf.sc_data ? __ALIGN_KERNEL(len, 4) : 0;
344
345		raw32 = __be32_to_cpu(*((__u32 *)*p));
346		if (aligned != (raw32 >> 24) * 4 ||
347		    cnf.sc_id != (raw32 & 0xffffff))
348			return 1;
349		*p += sizeof(__u32);
350
351		if (cnf.sc_data) {
352			if (strncmp((char *)*p, cnf.sc_data, len))
353				return 1;
354
355			*p += len;
356			aligned -= len;
357
358			while (aligned--) {
359				if (**p != '\0')
360					return 1;
361				*p += sizeof(__u8);
362			}
363		}
364	}
365
366	return 0;
367}
368
369static int check_ioam_header_and_data(int tid, struct ioam6_trace_hdr *ioam6h,
370				      __u32 trace_type, __u16 ioam_ns)
371{
372	__u8 *p;
373
374	if (check_ioam_header(tid, ioam6h, trace_type, ioam_ns))
375		return 1;
376
377	p = ioam6h->data + ioam6h->remlen * 4;
378
379	switch (tid) {
380	case TEST_OUT_BIT0:
381	case TEST_OUT_BIT1:
382	case TEST_OUT_BIT2:
383	case TEST_OUT_BIT3:
384	case TEST_OUT_BIT4:
385	case TEST_OUT_BIT5:
386	case TEST_OUT_BIT6:
387	case TEST_OUT_BIT7:
388	case TEST_OUT_BIT8:
389	case TEST_OUT_BIT9:
390	case TEST_OUT_BIT10:
391	case TEST_OUT_BIT11:
392	case TEST_OUT_BIT22:
393	case TEST_OUT_FULL_SUPP_TRACE:
394		return check_ioam6_data(&p, ioam6h, node1);
395
396	case TEST_IN_BIT0:
397	case TEST_IN_BIT1:
398	case TEST_IN_BIT2:
399	case TEST_IN_BIT3:
400	case TEST_IN_BIT4:
401	case TEST_IN_BIT5:
402	case TEST_IN_BIT6:
403	case TEST_IN_BIT7:
404	case TEST_IN_BIT8:
405	case TEST_IN_BIT9:
406	case TEST_IN_BIT10:
407	case TEST_IN_BIT11:
408	case TEST_IN_BIT22:
409	case TEST_IN_FULL_SUPP_TRACE:
410	{
411		__u32 tmp32 = node2.egr_wide;
412		__u16 tmp16 = node2.egr_id;
413		int res;
414
415		node2.egr_id = 0xffff;
416		node2.egr_wide = 0xffffffff;
417
418		res = check_ioam6_data(&p, ioam6h, node2);
419
420		node2.egr_id = tmp16;
421		node2.egr_wide = tmp32;
422
423		return res;
424	}
425
426	case TEST_FWD_FULL_SUPP_TRACE:
427		if (check_ioam6_data(&p, ioam6h, node3))
428			return 1;
429		if (check_ioam6_data(&p, ioam6h, node2))
430			return 1;
431		return check_ioam6_data(&p, ioam6h, node1);
432
433	default:
434		break;
435	}
436
437	return 1;
438}
439
440static int str2id(const char *tname)
441{
442	if (!strcmp("out_undef_ns", tname))
443		return TEST_OUT_UNDEF_NS;
444	if (!strcmp("out_no_room", tname))
445		return TEST_OUT_NO_ROOM;
446	if (!strcmp("out_bit0", tname))
447		return TEST_OUT_BIT0;
448	if (!strcmp("out_bit1", tname))
449		return TEST_OUT_BIT1;
450	if (!strcmp("out_bit2", tname))
451		return TEST_OUT_BIT2;
452	if (!strcmp("out_bit3", tname))
453		return TEST_OUT_BIT3;
454	if (!strcmp("out_bit4", tname))
455		return TEST_OUT_BIT4;
456	if (!strcmp("out_bit5", tname))
457		return TEST_OUT_BIT5;
458	if (!strcmp("out_bit6", tname))
459		return TEST_OUT_BIT6;
460	if (!strcmp("out_bit7", tname))
461		return TEST_OUT_BIT7;
462	if (!strcmp("out_bit8", tname))
463		return TEST_OUT_BIT8;
464	if (!strcmp("out_bit9", tname))
465		return TEST_OUT_BIT9;
466	if (!strcmp("out_bit10", tname))
467		return TEST_OUT_BIT10;
468	if (!strcmp("out_bit11", tname))
469		return TEST_OUT_BIT11;
470	if (!strcmp("out_bit22", tname))
471		return TEST_OUT_BIT22;
472	if (!strcmp("out_full_supp_trace", tname))
473		return TEST_OUT_FULL_SUPP_TRACE;
474	if (!strcmp("in_undef_ns", tname))
475		return TEST_IN_UNDEF_NS;
476	if (!strcmp("in_no_room", tname))
477		return TEST_IN_NO_ROOM;
478	if (!strcmp("in_oflag", tname))
479		return TEST_IN_OFLAG;
480	if (!strcmp("in_bit0", tname))
481		return TEST_IN_BIT0;
482	if (!strcmp("in_bit1", tname))
483		return TEST_IN_BIT1;
484	if (!strcmp("in_bit2", tname))
485		return TEST_IN_BIT2;
486	if (!strcmp("in_bit3", tname))
487		return TEST_IN_BIT3;
488	if (!strcmp("in_bit4", tname))
489		return TEST_IN_BIT4;
490	if (!strcmp("in_bit5", tname))
491		return TEST_IN_BIT5;
492	if (!strcmp("in_bit6", tname))
493		return TEST_IN_BIT6;
494	if (!strcmp("in_bit7", tname))
495		return TEST_IN_BIT7;
496	if (!strcmp("in_bit8", tname))
497		return TEST_IN_BIT8;
498	if (!strcmp("in_bit9", tname))
499		return TEST_IN_BIT9;
500	if (!strcmp("in_bit10", tname))
501		return TEST_IN_BIT10;
502	if (!strcmp("in_bit11", tname))
503		return TEST_IN_BIT11;
504	if (!strcmp("in_bit22", tname))
505		return TEST_IN_BIT22;
506	if (!strcmp("in_full_supp_trace", tname))
507		return TEST_IN_FULL_SUPP_TRACE;
508	if (!strcmp("fwd_full_supp_trace", tname))
509		return TEST_FWD_FULL_SUPP_TRACE;
510
511	return -1;
512}
513
514static int get_u32(__u32 *val, const char *arg, int base)
515{
516	unsigned long res;
517	char *ptr;
518
519	if (!arg || !*arg)
520		return -1;
521	res = strtoul(arg, &ptr, base);
522
523	if (!ptr || ptr == arg || *ptr)
524		return -1;
525
526	if (res == ULONG_MAX && errno == ERANGE)
527		return -1;
528
529	if (res > 0xFFFFFFFFUL)
530		return -1;
531
532	*val = res;
533	return 0;
534}
535
536static int get_u16(__u16 *val, const char *arg, int base)
537{
538	unsigned long res;
539	char *ptr;
540
541	if (!arg || !*arg)
542		return -1;
543	res = strtoul(arg, &ptr, base);
544
545	if (!ptr || ptr == arg || *ptr)
546		return -1;
547
548	if (res == ULONG_MAX && errno == ERANGE)
549		return -1;
550
551	if (res > 0xFFFFUL)
552		return -1;
553
554	*val = res;
555	return 0;
556}
557
558static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = {
559	[TEST_OUT_UNDEF_NS]		= check_ioam_header,
560	[TEST_OUT_NO_ROOM]		= check_ioam_header,
561	[TEST_OUT_BIT0]		= check_ioam_header_and_data,
562	[TEST_OUT_BIT1]		= check_ioam_header_and_data,
563	[TEST_OUT_BIT2]		= check_ioam_header_and_data,
564	[TEST_OUT_BIT3]		= check_ioam_header_and_data,
565	[TEST_OUT_BIT4]		= check_ioam_header_and_data,
566	[TEST_OUT_BIT5]		= check_ioam_header_and_data,
567	[TEST_OUT_BIT6]		= check_ioam_header_and_data,
568	[TEST_OUT_BIT7]		= check_ioam_header_and_data,
569	[TEST_OUT_BIT8]		= check_ioam_header_and_data,
570	[TEST_OUT_BIT9]		= check_ioam_header_and_data,
571	[TEST_OUT_BIT10]		= check_ioam_header_and_data,
572	[TEST_OUT_BIT11]		= check_ioam_header_and_data,
573	[TEST_OUT_BIT22]		= check_ioam_header_and_data,
574	[TEST_OUT_FULL_SUPP_TRACE]	= check_ioam_header_and_data,
575	[TEST_IN_UNDEF_NS]		= check_ioam_header,
576	[TEST_IN_NO_ROOM]		= check_ioam_header,
577	[TEST_IN_OFLAG]		= check_ioam_header,
578	[TEST_IN_BIT0]			= check_ioam_header_and_data,
579	[TEST_IN_BIT1]			= check_ioam_header_and_data,
580	[TEST_IN_BIT2]			= check_ioam_header_and_data,
581	[TEST_IN_BIT3]			= check_ioam_header_and_data,
582	[TEST_IN_BIT4]			= check_ioam_header_and_data,
583	[TEST_IN_BIT5]			= check_ioam_header_and_data,
584	[TEST_IN_BIT6]			= check_ioam_header_and_data,
585	[TEST_IN_BIT7]			= check_ioam_header_and_data,
586	[TEST_IN_BIT8]			= check_ioam_header_and_data,
587	[TEST_IN_BIT9]			= check_ioam_header_and_data,
588	[TEST_IN_BIT10]		= check_ioam_header_and_data,
589	[TEST_IN_BIT11]		= check_ioam_header_and_data,
590	[TEST_IN_BIT22]		= check_ioam_header_and_data,
591	[TEST_IN_FULL_SUPP_TRACE]	= check_ioam_header_and_data,
592	[TEST_FWD_FULL_SUPP_TRACE]	= check_ioam_header_and_data,
593};
594
595int main(int argc, char **argv)
596{
597	int fd, size, hoplen, tid, ret = 1, on = 1;
598	struct ioam6_hdr *opt;
599	struct cmsghdr *cmsg;
600	struct msghdr msg;
601	struct iovec iov;
602	__u8 buffer[512];
603	__u32 tr_type;
604	__u16 ioam_ns;
605	__u8 *ptr;
606
607	if (argc != 5)
608		goto out;
609
610	tid = str2id(argv[1]);
611	if (tid < 0 || !func[tid])
612		goto out;
613
614	if (get_u32(&tr_type, argv[2], 16) ||
615	    get_u16(&ioam_ns, argv[3], 0))
616		goto out;
617
618	fd = socket(PF_INET6, SOCK_RAW,
619		    !strcmp(argv[4], "encap") ? IPPROTO_IPV6 : IPPROTO_ICMPV6);
620	if (fd < 0)
621		goto out;
622
623	setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPOPTS,  &on, sizeof(on));
624
625	iov.iov_len = 1;
626	iov.iov_base = malloc(CMSG_SPACE(sizeof(buffer)));
627	if (!iov.iov_base)
628		goto close;
629recv:
630	memset(&msg, 0, sizeof(msg));
631	msg.msg_iov = &iov;
632	msg.msg_iovlen = 1;
633	msg.msg_control = buffer;
634	msg.msg_controllen = CMSG_SPACE(sizeof(buffer));
635
636	size = recvmsg(fd, &msg, 0);
637	if (size <= 0)
638		goto close;
639
640	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
641		if (cmsg->cmsg_level != IPPROTO_IPV6 ||
642		    cmsg->cmsg_type != IPV6_HOPOPTS ||
643		    cmsg->cmsg_len < sizeof(struct ipv6_hopopt_hdr))
644			continue;
645
646		ptr = (__u8 *)CMSG_DATA(cmsg);
647
648		hoplen = (ptr[1] + 1) << 3;
649		ptr += sizeof(struct ipv6_hopopt_hdr);
650
651		while (hoplen > 0) {
652			opt = (struct ioam6_hdr *)ptr;
653
654			if (opt->opt_type == IPV6_TLV_IOAM &&
655			    opt->type == IOAM6_TYPE_PREALLOC) {
656				ptr += sizeof(*opt);
657				ret = func[tid](tid,
658						(struct ioam6_trace_hdr *)ptr,
659						tr_type, ioam_ns);
660				goto close;
661			}
662
663			ptr += opt->opt_len + 2;
664			hoplen -= opt->opt_len + 2;
665		}
666	}
667
668	goto recv;
669close:
670	free(iov.iov_base);
671	close(fd);
672out:
673	return ret;
674}