Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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_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
129static 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
202static 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
370static 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
441static 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
515static 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
523static 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
545static 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
567static 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
604int 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
637recv:
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	}
669close:
670	close(fd);
671out:
672	return ret;
673}