brintos

brintos / linux-shallow public Read only

0
0
Text · 14.4 KiB · 895e5bb Raw
675 lines · c
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 synchronized33 * 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}675