diff options
Diffstat (limited to 'tools/testing/selftests/bpf/prog_tests')
62 files changed, 1506 insertions, 541 deletions
| diff --git a/tools/testing/selftests/bpf/prog_tests/attach_probe.c b/tools/testing/selftests/bpf/prog_tests/attach_probe.c index 9566d9d2f6ee..56374c8b5436 100644 --- a/tools/testing/selftests/bpf/prog_tests/attach_probe.c +++ b/tools/testing/selftests/bpf/prog_tests/attach_probe.c @@ -33,8 +33,8 @@ void test_attach_probe(void)  	struct test_attach_probe* skel;  	ssize_t uprobe_offset, ref_ctr_offset;  	struct bpf_link *uprobe_err_link; +	FILE *devnull;  	bool legacy; -	char *mem;  	/* Check if new-style kprobe/uprobe API is supported.  	 * Kernels that support new FD-based kprobe and uprobe BPF attachment @@ -147,7 +147,7 @@ void test_attach_probe(void)  	/* test attach by name for a library function, using the library  	 * as the binary argument. libc.so.6 will be resolved via dlopen()/dlinfo().  	 */ -	uprobe_opts.func_name = "malloc"; +	uprobe_opts.func_name = "fopen";  	uprobe_opts.retprobe = false;  	skel->links.handle_uprobe_byname2 =  			bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe_byname2, @@ -157,7 +157,7 @@ void test_attach_probe(void)  	if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname2, "attach_uprobe_byname2"))  		goto cleanup; -	uprobe_opts.func_name = "free"; +	uprobe_opts.func_name = "fclose";  	uprobe_opts.retprobe = true;  	skel->links.handle_uretprobe_byname2 =  			bpf_program__attach_uprobe_opts(skel->progs.handle_uretprobe_byname2, @@ -195,8 +195,8 @@ void test_attach_probe(void)  	usleep(1);  	/* trigger & validate shared library u[ret]probes attached by name */ -	mem = malloc(1); -	free(mem); +	devnull = fopen("/dev/null", "r"); +	fclose(devnull);  	/* trigger & validate uprobe & uretprobe */  	trigger_func(); diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c index 2be2d61954bc..26b2d1bffdfd 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c @@ -472,6 +472,7 @@ static void lsm_subtest(struct test_bpf_cookie *skel)  	int prog_fd;  	int lsm_fd = -1;  	LIBBPF_OPTS(bpf_link_create_opts, link_opts); +	int err;  	skel->bss->lsm_res = 0; @@ -482,8 +483,9 @@ static void lsm_subtest(struct test_bpf_cookie *skel)  	if (!ASSERT_GE(lsm_fd, 0, "lsm.link_create"))  		goto cleanup; -	stack_mprotect(); -	if (!ASSERT_EQ(errno, EPERM, "stack_mprotect")) +	err = stack_mprotect(); +	if (!ASSERT_EQ(err, -1, "stack_mprotect") || +	    !ASSERT_EQ(errno, EPERM, "stack_mprotect"))  		goto cleanup;  	usleep(1); diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c index 3af6450763e9..1f02168103dd 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c @@ -195,8 +195,8 @@ static void check_bpf_link_info(const struct bpf_program *prog)  		return;  	info_len = sizeof(info); -	err = bpf_obj_get_info_by_fd(bpf_link__fd(link), &info, &info_len); -	ASSERT_OK(err, "bpf_obj_get_info_by_fd"); +	err = bpf_link_get_info_by_fd(bpf_link__fd(link), &info, &info_len); +	ASSERT_OK(err, "bpf_link_get_info_by_fd");  	ASSERT_EQ(info.iter.task.tid, getpid(), "check_task_tid");  	bpf_link__destroy(link); @@ -684,13 +684,13 @@ static void test_overflow(bool test_e2big_overflow, bool ret1)  	/* setup filtering map_id in bpf program */  	map_info_len = sizeof(map_info); -	err = bpf_obj_get_info_by_fd(map1_fd, &map_info, &map_info_len); +	err = bpf_map_get_info_by_fd(map1_fd, &map_info, &map_info_len);  	if (CHECK(err, "get_map_info", "get map info failed: %s\n",  		  strerror(errno)))  		goto free_map2;  	skel->bss->map1_id = map_info.id; -	err = bpf_obj_get_info_by_fd(map2_fd, &map_info, &map_info_len); +	err = bpf_map_get_info_by_fd(map2_fd, &map_info, &map_info_len);  	if (CHECK(err, "get_map_info", "get map info failed: %s\n",  		  strerror(errno)))  		goto free_map2; diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c b/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c index e1c1e521cca2..675b90b15280 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c @@ -44,7 +44,7 @@ void serial_test_bpf_obj_id(void)  	CHECK(err >= 0 || errno != ENOENT,  	      "get-fd-by-notexist-link-id", "err %d errno %d\n", err, errno); -	/* Check bpf_obj_get_info_by_fd() */ +	/* Check bpf_map_get_info_by_fd() */  	bzero(zeros, sizeof(zeros));  	for (i = 0; i < nr_iters; i++) {  		now = time(NULL); @@ -79,7 +79,7 @@ void serial_test_bpf_obj_id(void)  		/* Check getting map info */  		info_len = sizeof(struct bpf_map_info) * 2;  		bzero(&map_infos[i], info_len); -		err = bpf_obj_get_info_by_fd(map_fds[i], &map_infos[i], +		err = bpf_map_get_info_by_fd(map_fds[i], &map_infos[i],  					     &info_len);  		if (CHECK(err ||  			  map_infos[i].type != BPF_MAP_TYPE_ARRAY || @@ -118,8 +118,8 @@ void serial_test_bpf_obj_id(void)  		err = clock_gettime(CLOCK_BOOTTIME, &boot_time_ts);  		if (CHECK_FAIL(err))  			goto done; -		err = bpf_obj_get_info_by_fd(prog_fds[i], &prog_infos[i], -					     &info_len); +		err = bpf_prog_get_info_by_fd(prog_fds[i], &prog_infos[i], +					      &info_len);  		load_time = (real_time_ts.tv_sec - boot_time_ts.tv_sec)  			+ (prog_infos[i].load_time / nsec_per_sec);  		if (CHECK(err || @@ -161,8 +161,8 @@ void serial_test_bpf_obj_id(void)  		bzero(&link_infos[i], info_len);  		link_infos[i].raw_tracepoint.tp_name = ptr_to_u64(&tp_name);  		link_infos[i].raw_tracepoint.tp_name_len = sizeof(tp_name); -		err = bpf_obj_get_info_by_fd(bpf_link__fd(links[i]), -					     &link_infos[i], &info_len); +		err = bpf_link_get_info_by_fd(bpf_link__fd(links[i]), +					      &link_infos[i], &info_len);  		if (CHECK(err ||  			  link_infos[i].type != BPF_LINK_TYPE_RAW_TRACEPOINT ||  			  link_infos[i].prog_id != prog_infos[i].id || @@ -217,7 +217,7 @@ void serial_test_bpf_obj_id(void)  		 * prog_info.map_ids = NULL  		 */  		prog_info.nr_map_ids = 1; -		err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len); +		err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &info_len);  		if (CHECK(!err || errno != EFAULT,  			  "get-prog-fd-bad-nr-map-ids", "err %d errno %d(%d)",  			  err, errno, EFAULT)) @@ -228,7 +228,7 @@ void serial_test_bpf_obj_id(void)  		saved_map_id = *(int *)((long)prog_infos[i].map_ids);  		prog_info.map_ids = prog_infos[i].map_ids;  		prog_info.nr_map_ids = 2; -		err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len); +		err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &info_len);  		prog_infos[i].jited_prog_insns = 0;  		prog_infos[i].xlated_prog_insns = 0;  		CHECK(err || info_len != sizeof(struct bpf_prog_info) || @@ -277,7 +277,7 @@ void serial_test_bpf_obj_id(void)  		if (CHECK_FAIL(err))  			goto done; -		err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len); +		err = bpf_map_get_info_by_fd(map_fd, &map_info, &info_len);  		CHECK(err || info_len != sizeof(struct bpf_map_info) ||  		      memcmp(&map_info, &map_infos[i], info_len) ||  		      array_value != array_magic_value, @@ -322,7 +322,7 @@ void serial_test_bpf_obj_id(void)  		nr_id_found++; -		err = bpf_obj_get_info_by_fd(link_fd, &link_info, &info_len); +		err = bpf_link_get_info_by_fd(link_fd, &link_info, &info_len);  		cmp_res = memcmp(&link_info, &link_infos[i],  				offsetof(struct bpf_link_info, raw_tracepoint));  		CHECK(err || info_len != sizeof(link_info) || cmp_res, diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c index de1b5b9eb93a..210d643fda6c 100644 --- a/tools/testing/selftests/bpf/prog_tests/btf.c +++ b/tools/testing/selftests/bpf/prog_tests/btf.c @@ -879,6 +879,34 @@ static struct btf_raw_test raw_tests[] = {  	.btf_load_err = true,  	.err_str = "Invalid elem",  }, +{ +	.descr = "var after datasec, ptr followed by modifier", +	.raw_types = { +		/* .bss section */				/* [1] */ +		BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 2), +			sizeof(void*)+4), +		BTF_VAR_SECINFO_ENC(4, 0, sizeof(void*)), +		BTF_VAR_SECINFO_ENC(6, sizeof(void*), 4), +		/* int */					/* [2] */ +		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), +		/* int* */					/* [3] */ +		BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2), +		BTF_VAR_ENC(NAME_TBD, 3, 0),			/* [4] */ +		/* const int */					/* [5] */ +		BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 2), +		BTF_VAR_ENC(NAME_TBD, 5, 0),			/* [6] */ +		BTF_END_RAW, +	}, +	.str_sec = "\0a\0b\0c\0", +	.str_sec_size = sizeof("\0a\0b\0c\0"), +	.map_type = BPF_MAP_TYPE_ARRAY, +	.map_name = ".bss", +	.key_size = sizeof(int), +	.value_size = sizeof(void*)+4, +	.key_type_id = 0, +	.value_type_id = 1, +	.max_entries = 1, +},  /* Test member exceeds the size of struct.   *   * struct A { @@ -4422,7 +4450,7 @@ static int test_big_btf_info(unsigned int test_num)  	info->btf = ptr_to_u64(user_btf);  	info->btf_size = raw_btf_size; -	err = bpf_obj_get_info_by_fd(btf_fd, info, &info_len); +	err = bpf_btf_get_info_by_fd(btf_fd, info, &info_len);  	if (CHECK(!err, "!err")) {  		err = -1;  		goto done; @@ -4435,7 +4463,7 @@ static int test_big_btf_info(unsigned int test_num)  	 * to userspace.  	 */  	info_garbage.garbage = 0; -	err = bpf_obj_get_info_by_fd(btf_fd, info, &info_len); +	err = bpf_btf_get_info_by_fd(btf_fd, info, &info_len);  	if (CHECK(err || info_len != sizeof(*info),  		  "err:%d errno:%d info_len:%u sizeof(*info):%zu",  		  err, errno, info_len, sizeof(*info))) { @@ -4499,7 +4527,7 @@ static int test_btf_id(unsigned int test_num)  	/* Test BPF_OBJ_GET_INFO_BY_ID on btf_id */  	info_len = sizeof(info[0]); -	err = bpf_obj_get_info_by_fd(btf_fd[0], &info[0], &info_len); +	err = bpf_btf_get_info_by_fd(btf_fd[0], &info[0], &info_len);  	if (CHECK(err, "errno:%d", errno)) {  		err = -1;  		goto done; @@ -4512,7 +4540,7 @@ static int test_btf_id(unsigned int test_num)  	}  	ret = 0; -	err = bpf_obj_get_info_by_fd(btf_fd[1], &info[1], &info_len); +	err = bpf_btf_get_info_by_fd(btf_fd[1], &info[1], &info_len);  	if (CHECK(err || info[0].id != info[1].id ||  		  info[0].btf_size != info[1].btf_size ||  		  (ret = memcmp(user_btf[0], user_btf[1], info[0].btf_size)), @@ -4535,7 +4563,7 @@ static int test_btf_id(unsigned int test_num)  	}  	info_len = sizeof(map_info); -	err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len); +	err = bpf_map_get_info_by_fd(map_fd, &map_info, &info_len);  	if (CHECK(err || map_info.btf_id != info[0].id ||  		  map_info.btf_key_type_id != 1 || map_info.btf_value_type_id != 2,  		  "err:%d errno:%d info.id:%u btf_id:%u btf_key_type_id:%u btf_value_type_id:%u", @@ -4638,7 +4666,7 @@ static void do_test_get_info(unsigned int test_num)  	info.btf_size = user_btf_size;  	ret = 0; -	err = bpf_obj_get_info_by_fd(btf_fd, &info, &info_len); +	err = bpf_btf_get_info_by_fd(btf_fd, &info, &info_len);  	if (CHECK(err || !info.id || info_len != sizeof(info) ||  		  info.btf_size != raw_btf_size ||  		  (ret = memcmp(raw_btf, user_btf, expected_nbytes)), @@ -4755,7 +4783,7 @@ static void do_test_file(unsigned int test_num)  	/* get necessary program info */  	info_len = sizeof(struct bpf_prog_info); -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	if (CHECK(err < 0, "invalid get info (1st) errno:%d", errno)) {  		fprintf(stderr, "%s\n", btf_log_buf); @@ -4787,7 +4815,7 @@ static void do_test_file(unsigned int test_num)  	info.func_info_rec_size = rec_size;  	info.func_info = ptr_to_u64(func_info); -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	if (CHECK(err < 0, "invalid get info (2nd) errno:%d", errno)) {  		fprintf(stderr, "%s\n", btf_log_buf); @@ -6405,7 +6433,7 @@ static int test_get_finfo(const struct prog_info_raw_test *test,  	/* get necessary lens */  	info_len = sizeof(struct bpf_prog_info); -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	if (CHECK(err < 0, "invalid get info (1st) errno:%d", errno)) {  		fprintf(stderr, "%s\n", btf_log_buf);  		return -1; @@ -6435,7 +6463,7 @@ static int test_get_finfo(const struct prog_info_raw_test *test,  	info.nr_func_info = nr_func_info;  	info.func_info_rec_size = rec_size;  	info.func_info = ptr_to_u64(func_info); -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	if (CHECK(err < 0, "invalid get info (2nd) errno:%d", errno)) {  		fprintf(stderr, "%s\n", btf_log_buf);  		err = -1; @@ -6499,7 +6527,7 @@ static int test_get_linfo(const struct prog_info_raw_test *test,  	nr_jited_func_lens = nr_jited_ksyms;  	info_len = sizeof(struct bpf_prog_info); -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	if (CHECK(err < 0, "err:%d errno:%d", err, errno)) {  		err = -1;  		goto done; @@ -6573,7 +6601,7 @@ static int test_get_linfo(const struct prog_info_raw_test *test,  		info.jited_func_lens = ptr_to_u64(jited_func_lens);  	} -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	/*  	 * Only recheck the info.*line_info* fields. diff --git a/tools/testing/selftests/bpf/prog_tests/btf_map_in_map.c b/tools/testing/selftests/bpf/prog_tests/btf_map_in_map.c index eb90a6b8850d..a8b53b8736f0 100644 --- a/tools/testing/selftests/bpf/prog_tests/btf_map_in_map.c +++ b/tools/testing/selftests/bpf/prog_tests/btf_map_in_map.c @@ -14,7 +14,7 @@ static __u32 bpf_map_id(struct bpf_map *map)  	int err;  	memset(&info, 0, info_len); -	err = bpf_obj_get_info_by_fd(bpf_map__fd(map), &info, &info_len); +	err = bpf_map_get_info_by_fd(bpf_map__fd(map), &info, &info_len);  	if (err)  		return 0;  	return info.id; diff --git a/tools/testing/selftests/bpf/prog_tests/cgrp_kfunc.c b/tools/testing/selftests/bpf/prog_tests/cgrp_kfunc.c index 973f0c5af965..b3f7985c8504 100644 --- a/tools/testing/selftests/bpf/prog_tests/cgrp_kfunc.c +++ b/tools/testing/selftests/bpf/prog_tests/cgrp_kfunc.c @@ -8,9 +8,6 @@  #include "cgrp_kfunc_failure.skel.h"  #include "cgrp_kfunc_success.skel.h" -static size_t log_buf_sz = 1 << 20; /* 1 MB */ -static char obj_log_buf[1048576]; -  static struct cgrp_kfunc_success *open_load_cgrp_kfunc_skel(void)  {  	struct cgrp_kfunc_success *skel; @@ -89,65 +86,6 @@ static const char * const success_tests[] = {  	"test_cgrp_get_ancestors",  }; -static struct { -	const char *prog_name; -	const char *expected_err_msg; -} failure_tests[] = { -	{"cgrp_kfunc_acquire_untrusted", "R1 must be referenced or trusted"}, -	{"cgrp_kfunc_acquire_fp", "arg#0 pointer type STRUCT cgroup must point"}, -	{"cgrp_kfunc_acquire_unsafe_kretprobe", "reg type unsupported for arg#0 function"}, -	{"cgrp_kfunc_acquire_trusted_walked", "R1 must be referenced or trusted"}, -	{"cgrp_kfunc_acquire_null", "arg#0 pointer type STRUCT cgroup must point"}, -	{"cgrp_kfunc_acquire_unreleased", "Unreleased reference"}, -	{"cgrp_kfunc_get_non_kptr_param", "arg#0 expected pointer to map value"}, -	{"cgrp_kfunc_get_non_kptr_acquired", "arg#0 expected pointer to map value"}, -	{"cgrp_kfunc_get_null", "arg#0 expected pointer to map value"}, -	{"cgrp_kfunc_xchg_unreleased", "Unreleased reference"}, -	{"cgrp_kfunc_get_unreleased", "Unreleased reference"}, -	{"cgrp_kfunc_release_untrusted", "arg#0 is untrusted_ptr_or_null_ expected ptr_ or socket"}, -	{"cgrp_kfunc_release_fp", "arg#0 pointer type STRUCT cgroup must point"}, -	{"cgrp_kfunc_release_null", "arg#0 is ptr_or_null_ expected ptr_ or socket"}, -	{"cgrp_kfunc_release_unacquired", "release kernel function bpf_cgroup_release expects"}, -}; - -static void verify_fail(const char *prog_name, const char *expected_err_msg) -{ -	LIBBPF_OPTS(bpf_object_open_opts, opts); -	struct cgrp_kfunc_failure *skel; -	int err, i; - -	opts.kernel_log_buf = obj_log_buf; -	opts.kernel_log_size = log_buf_sz; -	opts.kernel_log_level = 1; - -	skel = cgrp_kfunc_failure__open_opts(&opts); -	if (!ASSERT_OK_PTR(skel, "cgrp_kfunc_failure__open_opts")) -		goto cleanup; - -	for (i = 0; i < ARRAY_SIZE(failure_tests); i++) { -		struct bpf_program *prog; -		const char *curr_name = failure_tests[i].prog_name; - -		prog = bpf_object__find_program_by_name(skel->obj, curr_name); -		if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) -			goto cleanup; - -		bpf_program__set_autoload(prog, !strcmp(curr_name, prog_name)); -	} - -	err = cgrp_kfunc_failure__load(skel); -	if (!ASSERT_ERR(err, "unexpected load success")) -		goto cleanup; - -	if (!ASSERT_OK_PTR(strstr(obj_log_buf, expected_err_msg), "expected_err_msg")) { -		fprintf(stderr, "Expected err_msg: %s\n", expected_err_msg); -		fprintf(stderr, "Verifier output: %s\n", obj_log_buf); -	} - -cleanup: -	cgrp_kfunc_failure__destroy(skel); -} -  void test_cgrp_kfunc(void)  {  	int i, err; @@ -163,12 +101,7 @@ void test_cgrp_kfunc(void)  		run_success_test(success_tests[i]);  	} -	for (i = 0; i < ARRAY_SIZE(failure_tests); i++) { -		if (!test__start_subtest(failure_tests[i].prog_name)) -			continue; - -		verify_fail(failure_tests[i].prog_name, failure_tests[i].expected_err_msg); -	} +	RUN_TESTS(cgrp_kfunc_failure);  cleanup:  	cleanup_cgroup_environment(); diff --git a/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c b/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c index 33a2776737e7..2cc759956e3b 100644 --- a/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c +++ b/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c @@ -16,7 +16,7 @@  struct socket_cookie {  	__u64 cookie_key; -	__u32 cookie_value; +	__u64 cookie_value;  };  static void test_tp_btf(int cgroup_fd) diff --git a/tools/testing/selftests/bpf/prog_tests/check_mtu.c b/tools/testing/selftests/bpf/prog_tests/check_mtu.c index 12f4395f18b3..5338d2ea0460 100644 --- a/tools/testing/selftests/bpf/prog_tests/check_mtu.c +++ b/tools/testing/selftests/bpf/prog_tests/check_mtu.c @@ -59,7 +59,7 @@ static void test_check_mtu_xdp_attach(void)  	memset(&link_info, 0, sizeof(link_info));  	fd = bpf_link__fd(link); -	err = bpf_obj_get_info_by_fd(fd, &link_info, &link_info_len); +	err = bpf_link_get_info_by_fd(fd, &link_info, &link_info_len);  	if (CHECK(err, "link_info", "failed: %d\n", err))  		goto out; diff --git a/tools/testing/selftests/bpf/prog_tests/cpumask.c b/tools/testing/selftests/bpf/prog_tests/cpumask.c new file mode 100644 index 000000000000..5fbe457c4ebe --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/cpumask.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include <test_progs.h> +#include "cpumask_failure.skel.h" +#include "cpumask_success.skel.h" + +static const char * const cpumask_success_testcases[] = { +	"test_alloc_free_cpumask", +	"test_set_clear_cpu", +	"test_setall_clear_cpu", +	"test_first_firstzero_cpu", +	"test_test_and_set_clear", +	"test_and_or_xor", +	"test_intersects_subset", +	"test_copy_any_anyand", +	"test_insert_leave", +	"test_insert_remove_release", +	"test_insert_kptr_get_release", +}; + +static void verify_success(const char *prog_name) +{ +	struct cpumask_success *skel; +	struct bpf_program *prog; +	struct bpf_link *link = NULL; +	pid_t child_pid; +	int status; + +	skel = cpumask_success__open(); +	if (!ASSERT_OK_PTR(skel, "cpumask_success__open")) +		return; + +	skel->bss->pid = getpid(); +	skel->bss->nr_cpus = libbpf_num_possible_cpus(); + +	cpumask_success__load(skel); +	if (!ASSERT_OK_PTR(skel, "cpumask_success__load")) +		goto cleanup; + +	prog = bpf_object__find_program_by_name(skel->obj, prog_name); +	if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) +		goto cleanup; + +	link = bpf_program__attach(prog); +	if (!ASSERT_OK_PTR(link, "bpf_program__attach")) +		goto cleanup; + +	child_pid = fork(); +	if (!ASSERT_GT(child_pid, -1, "child_pid")) +		goto cleanup; +	if (child_pid == 0) +		_exit(0); +	waitpid(child_pid, &status, 0); +	ASSERT_OK(skel->bss->err, "post_wait_err"); + +cleanup: +	bpf_link__destroy(link); +	cpumask_success__destroy(skel); +} + +void test_cpumask(void) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(cpumask_success_testcases); i++) { +		if (!test__start_subtest(cpumask_success_testcases[i])) +			continue; + +		verify_success(cpumask_success_testcases[i]); +	} + +	RUN_TESTS(cpumask_failure); +} diff --git a/tools/testing/selftests/bpf/prog_tests/decap_sanity.c b/tools/testing/selftests/bpf/prog_tests/decap_sanity.c index 0b2f73b88c53..2853883b7cbb 100644 --- a/tools/testing/selftests/bpf/prog_tests/decap_sanity.c +++ b/tools/testing/selftests/bpf/prog_tests/decap_sanity.c @@ -80,6 +80,6 @@ fail:  		bpf_tc_hook_destroy(&qdisc_hook);  		close_netns(nstoken);  	} -	system("ip netns del " NS_TEST " >& /dev/null"); +	system("ip netns del " NS_TEST " &> /dev/null");  	decap_sanity__destroy(skel);  } diff --git a/tools/testing/selftests/bpf/prog_tests/dummy_st_ops.c b/tools/testing/selftests/bpf/prog_tests/dummy_st_ops.c index c11832657d2b..f43fcb13d2c4 100644 --- a/tools/testing/selftests/bpf/prog_tests/dummy_st_ops.c +++ b/tools/testing/selftests/bpf/prog_tests/dummy_st_ops.c @@ -1,7 +1,8 @@  // SPDX-License-Identifier: GPL-2.0  /* Copyright (C) 2021. Huawei Technologies Co., Ltd */  #include <test_progs.h> -#include "dummy_st_ops.skel.h" +#include "dummy_st_ops_success.skel.h" +#include "dummy_st_ops_fail.skel.h"  #include "trace_dummy_st_ops.skel.h"  /* Need to keep consistent with definition in include/linux/bpf.h */ @@ -11,17 +12,17 @@ struct bpf_dummy_ops_state {  static void test_dummy_st_ops_attach(void)  { -	struct dummy_st_ops *skel; +	struct dummy_st_ops_success *skel;  	struct bpf_link *link; -	skel = dummy_st_ops__open_and_load(); +	skel = dummy_st_ops_success__open_and_load();  	if (!ASSERT_OK_PTR(skel, "dummy_st_ops_load"))  		return;  	link = bpf_map__attach_struct_ops(skel->maps.dummy_1);  	ASSERT_EQ(libbpf_get_error(link), -EOPNOTSUPP, "dummy_st_ops_attach"); -	dummy_st_ops__destroy(skel); +	dummy_st_ops_success__destroy(skel);  }  static void test_dummy_init_ret_value(void) @@ -31,10 +32,10 @@ static void test_dummy_init_ret_value(void)  		.ctx_in = args,  		.ctx_size_in = sizeof(args),  	); -	struct dummy_st_ops *skel; +	struct dummy_st_ops_success *skel;  	int fd, err; -	skel = dummy_st_ops__open_and_load(); +	skel = dummy_st_ops_success__open_and_load();  	if (!ASSERT_OK_PTR(skel, "dummy_st_ops_load"))  		return; @@ -43,7 +44,7 @@ static void test_dummy_init_ret_value(void)  	ASSERT_OK(err, "test_run");  	ASSERT_EQ(attr.retval, 0xf2f3f4f5, "test_ret"); -	dummy_st_ops__destroy(skel); +	dummy_st_ops_success__destroy(skel);  }  static void test_dummy_init_ptr_arg(void) @@ -58,10 +59,10 @@ static void test_dummy_init_ptr_arg(void)  		.ctx_size_in = sizeof(args),  	);  	struct trace_dummy_st_ops *trace_skel; -	struct dummy_st_ops *skel; +	struct dummy_st_ops_success *skel;  	int fd, err; -	skel = dummy_st_ops__open_and_load(); +	skel = dummy_st_ops_success__open_and_load();  	if (!ASSERT_OK_PTR(skel, "dummy_st_ops_load"))  		return; @@ -91,7 +92,7 @@ static void test_dummy_init_ptr_arg(void)  	ASSERT_EQ(trace_skel->bss->val, exp_retval, "fentry_val");  done: -	dummy_st_ops__destroy(skel); +	dummy_st_ops_success__destroy(skel);  	trace_dummy_st_ops__destroy(trace_skel);  } @@ -102,12 +103,12 @@ static void test_dummy_multiple_args(void)  		.ctx_in = args,  		.ctx_size_in = sizeof(args),  	); -	struct dummy_st_ops *skel; +	struct dummy_st_ops_success *skel;  	int fd, err;  	size_t i;  	char name[8]; -	skel = dummy_st_ops__open_and_load(); +	skel = dummy_st_ops_success__open_and_load();  	if (!ASSERT_OK_PTR(skel, "dummy_st_ops_load"))  		return; @@ -119,7 +120,28 @@ static void test_dummy_multiple_args(void)  		ASSERT_EQ(skel->bss->test_2_args[i], args[i], name);  	} -	dummy_st_ops__destroy(skel); +	dummy_st_ops_success__destroy(skel); +} + +static void test_dummy_sleepable(void) +{ +	__u64 args[1] = {0}; +	LIBBPF_OPTS(bpf_test_run_opts, attr, +		.ctx_in = args, +		.ctx_size_in = sizeof(args), +	); +	struct dummy_st_ops_success *skel; +	int fd, err; + +	skel = dummy_st_ops_success__open_and_load(); +	if (!ASSERT_OK_PTR(skel, "dummy_st_ops_load")) +		return; + +	fd = bpf_program__fd(skel->progs.test_sleepable); +	err = bpf_prog_test_run_opts(fd, &attr); +	ASSERT_OK(err, "test_run"); + +	dummy_st_ops_success__destroy(skel);  }  void test_dummy_st_ops(void) @@ -132,4 +154,8 @@ void test_dummy_st_ops(void)  		test_dummy_init_ptr_arg();  	if (test__start_subtest("dummy_multiple_args"))  		test_dummy_multiple_args(); +	if (test__start_subtest("dummy_sleepable")) +		test_dummy_sleepable(); + +	RUN_TESTS(dummy_st_ops_fail);  } diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c index 7faaf6d9e0d4..b99264ec0d9c 100644 --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c @@ -5,14 +5,10 @@  #include "dynptr_fail.skel.h"  #include "dynptr_success.skel.h" -static struct { -	const char *prog_name; -	const char *expected_err_msg; -} dynptr_tests[] = { -	/* success cases */ -	{"test_read_write", NULL}, -	{"test_data_slice", NULL}, -	{"test_ringbuf", NULL}, +static const char * const success_tests[] = { +	"test_read_write", +	"test_data_slice", +	"test_ringbuf",  };  static void verify_success(const char *prog_name) @@ -53,11 +49,11 @@ void test_dynptr(void)  {  	int i; -	for (i = 0; i < ARRAY_SIZE(dynptr_tests); i++) { -		if (!test__start_subtest(dynptr_tests[i].prog_name)) +	for (i = 0; i < ARRAY_SIZE(success_tests); i++) { +		if (!test__start_subtest(success_tests[i]))  			continue; -		verify_success(dynptr_tests[i].prog_name); +		verify_success(success_tests[i]);  	}  	RUN_TESTS(dynptr_fail); diff --git a/tools/testing/selftests/bpf/prog_tests/enable_stats.c b/tools/testing/selftests/bpf/prog_tests/enable_stats.c index 2cb2085917e7..75f85d0fe74a 100644 --- a/tools/testing/selftests/bpf/prog_tests/enable_stats.c +++ b/tools/testing/selftests/bpf/prog_tests/enable_stats.c @@ -28,7 +28,7 @@ void test_enable_stats(void)  	prog_fd = bpf_program__fd(skel->progs.test_enable_stats);  	memset(&info, 0, info_len); -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	if (CHECK(err, "get_prog_info",  		  "failed to get bpf_prog_info for fd %d\n", prog_fd))  		goto cleanup; diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c b/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c index 20f5fa0fcec9..8ec73fdfcdab 100644 --- a/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c +++ b/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c @@ -79,7 +79,7 @@ static void test_fexit_bpf2bpf_common(const char *obj_file,  		return;  	info_len = sizeof(prog_info); -	err = bpf_obj_get_info_by_fd(tgt_fd, &prog_info, &info_len); +	err = bpf_prog_get_info_by_fd(tgt_fd, &prog_info, &info_len);  	if (!ASSERT_OK(err, "tgt_fd_get_info"))  		goto close_prog; @@ -136,8 +136,8 @@ static void test_fexit_bpf2bpf_common(const char *obj_file,  		info_len = sizeof(link_info);  		memset(&link_info, 0, sizeof(link_info)); -		err = bpf_obj_get_info_by_fd(bpf_link__fd(link[i]), -					     &link_info, &info_len); +		err = bpf_link_get_info_by_fd(bpf_link__fd(link[i]), +					      &link_info, &info_len);  		ASSERT_OK(err, "link_fd_get_info");  		ASSERT_EQ(link_info.tracing.attach_type,  			  bpf_program__expected_attach_type(prog[i]), @@ -417,7 +417,7 @@ static int find_prog_btf_id(const char *name, __u32 attach_prog_fd)  	struct btf *btf;  	int ret; -	ret = bpf_obj_get_info_by_fd(attach_prog_fd, &info, &info_len); +	ret = bpf_prog_get_info_by_fd(attach_prog_fd, &info, &info_len);  	if (ret)  		return ret; @@ -483,12 +483,12 @@ static void test_fentry_to_cgroup_bpf(void)  	if (!ASSERT_GE(fentry_fd, 0, "load_fentry"))  		goto cleanup; -	/* Make sure bpf_obj_get_info_by_fd works correctly when attaching +	/* Make sure bpf_prog_get_info_by_fd works correctly when attaching  	 * to another BPF program.  	 */ -	ASSERT_OK(bpf_obj_get_info_by_fd(fentry_fd, &info, &info_len), -		  "bpf_obj_get_info_by_fd"); +	ASSERT_OK(bpf_prog_get_info_by_fd(fentry_fd, &info, &info_len), +		  "bpf_prog_get_info_by_fd");  	ASSERT_EQ(info.btf_id, 0, "info.btf_id");  	ASSERT_EQ(info.attach_btf_id, btf_id, "info.attach_btf_id"); diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_stress.c b/tools/testing/selftests/bpf/prog_tests/fexit_stress.c index 5a7e6011f6bf..596536def43d 100644 --- a/tools/testing/selftests/bpf/prog_tests/fexit_stress.c +++ b/tools/testing/selftests/bpf/prog_tests/fexit_stress.c @@ -2,14 +2,19 @@  /* Copyright (c) 2019 Facebook */  #include <test_progs.h> -/* that's kernel internal BPF_MAX_TRAMP_PROGS define */ -#define CNT 38 -  void serial_test_fexit_stress(void)  { -	int fexit_fd[CNT] = {}; -	int link_fd[CNT] = {}; -	int err, i; +	int bpf_max_tramp_links, err, i; +	int *fd, *fexit_fd, *link_fd; + +	bpf_max_tramp_links = get_bpf_max_tramp_links(); +	if (!ASSERT_GE(bpf_max_tramp_links, 1, "bpf_max_tramp_links")) +		return; +	fd = calloc(bpf_max_tramp_links * 2, sizeof(*fd)); +	if (!ASSERT_OK_PTR(fd, "fd")) +		return; +	fexit_fd = fd; +	link_fd = fd + bpf_max_tramp_links;  	const struct bpf_insn trace_program[] = {  		BPF_MOV64_IMM(BPF_REG_0, 0), @@ -28,7 +33,7 @@ void serial_test_fexit_stress(void)  		goto out;  	trace_opts.attach_btf_id = err; -	for (i = 0; i < CNT; i++) { +	for (i = 0; i < bpf_max_tramp_links; i++) {  		fexit_fd[i] = bpf_prog_load(BPF_PROG_TYPE_TRACING, NULL, "GPL",  					    trace_program,  					    sizeof(trace_program) / sizeof(struct bpf_insn), @@ -44,10 +49,11 @@ void serial_test_fexit_stress(void)  	ASSERT_OK(err, "bpf_prog_test_run_opts");  out: -	for (i = 0; i < CNT; i++) { +	for (i = 0; i < bpf_max_tramp_links; i++) {  		if (link_fd[i])  			close(link_fd[i]);  		if (fexit_fd[i])  			close(fexit_fd[i]);  	} +	free(fd);  } diff --git a/tools/testing/selftests/bpf/prog_tests/fib_lookup.c b/tools/testing/selftests/bpf/prog_tests/fib_lookup.c new file mode 100644 index 000000000000..61ccddccf485 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/fib_lookup.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include <sys/types.h> +#include <net/if.h> + +#include "test_progs.h" +#include "network_helpers.h" +#include "fib_lookup.skel.h" + +#define SYS(fmt, ...)						\ +	({							\ +		char cmd[1024];					\ +		snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__);	\ +		if (!ASSERT_OK(system(cmd), cmd))		\ +			goto fail;				\ +	}) + +#define NS_TEST			"fib_lookup_ns" +#define IPV6_IFACE_ADDR		"face::face" +#define IPV6_NUD_FAILED_ADDR	"face::1" +#define IPV6_NUD_STALE_ADDR	"face::2" +#define IPV4_IFACE_ADDR		"10.0.0.254" +#define IPV4_NUD_FAILED_ADDR	"10.0.0.1" +#define IPV4_NUD_STALE_ADDR	"10.0.0.2" +#define DMAC			"11:11:11:11:11:11" +#define DMAC_INIT { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, } + +struct fib_lookup_test { +	const char *desc; +	const char *daddr; +	int expected_ret; +	int lookup_flags; +	__u8 dmac[6]; +}; + +static const struct fib_lookup_test tests[] = { +	{ .desc = "IPv6 failed neigh", +	  .daddr = IPV6_NUD_FAILED_ADDR, .expected_ret = BPF_FIB_LKUP_RET_NO_NEIGH, }, +	{ .desc = "IPv6 stale neigh", +	  .daddr = IPV6_NUD_STALE_ADDR, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS, +	  .dmac = DMAC_INIT, }, +	{ .desc = "IPv6 skip neigh", +	  .daddr = IPV6_NUD_FAILED_ADDR, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS, +	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH, }, +	{ .desc = "IPv4 failed neigh", +	  .daddr = IPV4_NUD_FAILED_ADDR, .expected_ret = BPF_FIB_LKUP_RET_NO_NEIGH, }, +	{ .desc = "IPv4 stale neigh", +	  .daddr = IPV4_NUD_STALE_ADDR, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS, +	  .dmac = DMAC_INIT, }, +	{ .desc = "IPv4 skip neigh", +	  .daddr = IPV4_NUD_FAILED_ADDR, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS, +	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH, }, +}; + +static int ifindex; + +static int setup_netns(void) +{ +	int err; + +	SYS("ip link add veth1 type veth peer name veth2"); +	SYS("ip link set dev veth1 up"); + +	SYS("ip addr add %s/64 dev veth1 nodad", IPV6_IFACE_ADDR); +	SYS("ip neigh add %s dev veth1 nud failed", IPV6_NUD_FAILED_ADDR); +	SYS("ip neigh add %s dev veth1 lladdr %s nud stale", IPV6_NUD_STALE_ADDR, DMAC); + +	SYS("ip addr add %s/24 dev veth1 nodad", IPV4_IFACE_ADDR); +	SYS("ip neigh add %s dev veth1 nud failed", IPV4_NUD_FAILED_ADDR); +	SYS("ip neigh add %s dev veth1 lladdr %s nud stale", IPV4_NUD_STALE_ADDR, DMAC); + +	err = write_sysctl("/proc/sys/net/ipv4/conf/veth1/forwarding", "1"); +	if (!ASSERT_OK(err, "write_sysctl(net.ipv4.conf.veth1.forwarding)")) +		goto fail; + +	err = write_sysctl("/proc/sys/net/ipv6/conf/veth1/forwarding", "1"); +	if (!ASSERT_OK(err, "write_sysctl(net.ipv6.conf.veth1.forwarding)")) +		goto fail; + +	return 0; +fail: +	return -1; +} + +static int set_lookup_params(struct bpf_fib_lookup *params, const char *daddr) +{ +	int ret; + +	memset(params, 0, sizeof(*params)); + +	params->l4_protocol = IPPROTO_TCP; +	params->ifindex = ifindex; + +	if (inet_pton(AF_INET6, daddr, params->ipv6_dst) == 1) { +		params->family = AF_INET6; +		ret = inet_pton(AF_INET6, IPV6_IFACE_ADDR, params->ipv6_src); +		if (!ASSERT_EQ(ret, 1, "inet_pton(IPV6_IFACE_ADDR)")) +			return -1; +		return 0; +	} + +	ret = inet_pton(AF_INET, daddr, ¶ms->ipv4_dst); +	if (!ASSERT_EQ(ret, 1, "convert IP[46] address")) +		return -1; +	params->family = AF_INET; +	ret = inet_pton(AF_INET, IPV4_IFACE_ADDR, ¶ms->ipv4_src); +	if (!ASSERT_EQ(ret, 1, "inet_pton(IPV4_IFACE_ADDR)")) +		return -1; + +	return 0; +} + +static void mac_str(char *b, const __u8 *mac) +{ +	sprintf(b, "%02X:%02X:%02X:%02X:%02X:%02X", +		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +void test_fib_lookup(void) +{ +	struct bpf_fib_lookup *fib_params; +	struct nstoken *nstoken = NULL; +	struct __sk_buff skb = { }; +	struct fib_lookup *skel; +	int prog_fd, err, ret, i; + +	/* The test does not use the skb->data, so +	 * use pkt_v6 for both v6 and v4 test. +	 */ +	LIBBPF_OPTS(bpf_test_run_opts, run_opts, +		    .data_in = &pkt_v6, +		    .data_size_in = sizeof(pkt_v6), +		    .ctx_in = &skb, +		    .ctx_size_in = sizeof(skb), +	); + +	skel = fib_lookup__open_and_load(); +	if (!ASSERT_OK_PTR(skel, "skel open_and_load")) +		return; +	prog_fd = bpf_program__fd(skel->progs.fib_lookup); + +	SYS("ip netns add %s", NS_TEST); + +	nstoken = open_netns(NS_TEST); +	if (!ASSERT_OK_PTR(nstoken, "open_netns")) +		goto fail; + +	if (setup_netns()) +		goto fail; + +	ifindex = if_nametoindex("veth1"); +	skb.ifindex = ifindex; +	fib_params = &skel->bss->fib_params; + +	for (i = 0; i < ARRAY_SIZE(tests); i++) { +		printf("Testing %s\n", tests[i].desc); + +		if (set_lookup_params(fib_params, tests[i].daddr)) +			continue; +		skel->bss->fib_lookup_ret = -1; +		skel->bss->lookup_flags = BPF_FIB_LOOKUP_OUTPUT | +			tests[i].lookup_flags; + +		err = bpf_prog_test_run_opts(prog_fd, &run_opts); +		if (!ASSERT_OK(err, "bpf_prog_test_run_opts")) +			continue; + +		ASSERT_EQ(tests[i].expected_ret, skel->bss->fib_lookup_ret, +			  "fib_lookup_ret"); + +		ret = memcmp(tests[i].dmac, fib_params->dmac, sizeof(tests[i].dmac)); +		if (!ASSERT_EQ(ret, 0, "dmac not match")) { +			char expected[18], actual[18]; + +			mac_str(expected, tests[i].dmac); +			mac_str(actual, fib_params->dmac); +			printf("dmac expected %s actual %s\n", expected, actual); +		} +	} + +fail: +	if (nstoken) +		close_netns(nstoken); +	system("ip netns del " NS_TEST " &> /dev/null"); +	fib_lookup__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c b/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c index 7c79462d2702..9333f7346d15 100644 --- a/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c +++ b/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c @@ -60,9 +60,9 @@ static __u32 query_prog_id(int prog)  	__u32 info_len = sizeof(info);  	int err; -	err = bpf_obj_get_info_by_fd(prog, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog, &info, &info_len);  	if (CHECK_FAIL(err || info_len != sizeof(info))) { -		perror("bpf_obj_get_info_by_fd"); +		perror("bpf_prog_get_info_by_fd");  		return 0;  	} @@ -497,7 +497,7 @@ static void test_link_get_info(int netns, int prog1, int prog2)  	}  	info_len = sizeof(info); -	err = bpf_obj_get_info_by_fd(link, &info, &info_len); +	err = bpf_link_get_info_by_fd(link, &info, &info_len);  	if (CHECK_FAIL(err)) {  		perror("bpf_obj_get_info");  		goto out_unlink; @@ -521,7 +521,7 @@ static void test_link_get_info(int netns, int prog1, int prog2)  	link_id = info.id;  	info_len = sizeof(info); -	err = bpf_obj_get_info_by_fd(link, &info, &info_len); +	err = bpf_link_get_info_by_fd(link, &info, &info_len);  	if (CHECK_FAIL(err)) {  		perror("bpf_obj_get_info");  		goto out_unlink; @@ -546,7 +546,7 @@ static void test_link_get_info(int netns, int prog1, int prog2)  	netns = -1;  	info_len = sizeof(info); -	err = bpf_obj_get_info_by_fd(link, &info, &info_len); +	err = bpf_link_get_info_by_fd(link, &info, &info_len);  	if (CHECK_FAIL(err)) {  		perror("bpf_obj_get_info");  		goto out_unlink; diff --git a/tools/testing/selftests/bpf/prog_tests/htab_reuse.c b/tools/testing/selftests/bpf/prog_tests/htab_reuse.c new file mode 100644 index 000000000000..a742dd994d60 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/htab_reuse.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023. Huawei Technologies Co., Ltd */ +#define _GNU_SOURCE +#include <sched.h> +#include <stdbool.h> +#include <test_progs.h> +#include "htab_reuse.skel.h" + +struct htab_op_ctx { +	int fd; +	int loop; +	bool stop; +}; + +struct htab_val { +	unsigned int lock; +	unsigned int data; +}; + +static void *htab_lookup_fn(void *arg) +{ +	struct htab_op_ctx *ctx = arg; +	int i = 0; + +	while (i++ < ctx->loop && !ctx->stop) { +		struct htab_val value; +		unsigned int key; + +		/* Use BPF_F_LOCK to use spin-lock in map value. */ +		key = 7; +		bpf_map_lookup_elem_flags(ctx->fd, &key, &value, BPF_F_LOCK); +	} + +	return NULL; +} + +static void *htab_update_fn(void *arg) +{ +	struct htab_op_ctx *ctx = arg; +	int i = 0; + +	while (i++ < ctx->loop && !ctx->stop) { +		struct htab_val value; +		unsigned int key; + +		key = 7; +		value.lock = 0; +		value.data = key; +		bpf_map_update_elem(ctx->fd, &key, &value, BPF_F_LOCK); +		bpf_map_delete_elem(ctx->fd, &key); + +		key = 24; +		value.lock = 0; +		value.data = key; +		bpf_map_update_elem(ctx->fd, &key, &value, BPF_F_LOCK); +		bpf_map_delete_elem(ctx->fd, &key); +	} + +	return NULL; +} + +void test_htab_reuse(void) +{ +	unsigned int i, wr_nr = 1, rd_nr = 4; +	pthread_t tids[wr_nr + rd_nr]; +	struct htab_reuse *skel; +	struct htab_op_ctx ctx; +	int err; + +	skel = htab_reuse__open_and_load(); +	if (!ASSERT_OK_PTR(skel, "htab_reuse__open_and_load")) +		return; + +	ctx.fd = bpf_map__fd(skel->maps.htab); +	ctx.loop = 500; +	ctx.stop = false; + +	memset(tids, 0, sizeof(tids)); +	for (i = 0; i < wr_nr; i++) { +		err = pthread_create(&tids[i], NULL, htab_update_fn, &ctx); +		if (!ASSERT_OK(err, "pthread_create")) { +			ctx.stop = true; +			goto reap; +		} +	} +	for (i = 0; i < rd_nr; i++) { +		err = pthread_create(&tids[i + wr_nr], NULL, htab_lookup_fn, &ctx); +		if (!ASSERT_OK(err, "pthread_create")) { +			ctx.stop = true; +			goto reap; +		} +	} + +reap: +	for (i = 0; i < wr_nr + rd_nr; i++) { +		if (!tids[i]) +			continue; +		pthread_join(tids[i], NULL); +	} +	htab_reuse__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/prog_tests/jit_probe_mem.c b/tools/testing/selftests/bpf/prog_tests/jit_probe_mem.c new file mode 100644 index 000000000000..5639428607e6 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/jit_probe_mem.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ +#include <test_progs.h> +#include <network_helpers.h> + +#include "jit_probe_mem.skel.h" + +void test_jit_probe_mem(void) +{ +	LIBBPF_OPTS(bpf_test_run_opts, opts, +		.data_in = &pkt_v4, +		.data_size_in = sizeof(pkt_v4), +		.repeat = 1, +	); +	struct jit_probe_mem *skel; +	int ret; + +	skel = jit_probe_mem__open_and_load(); +	if (!ASSERT_OK_PTR(skel, "jit_probe_mem__open_and_load")) +		return; + +	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_jit_probe_mem), &opts); +	ASSERT_OK(ret, "jit_probe_mem ret"); +	ASSERT_OK(opts.retval, "jit_probe_mem opts.retval"); +	ASSERT_EQ(skel->data->total_sum, 192, "jit_probe_mem total_sum"); + +	jit_probe_mem__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/prog_tests/kfree_skb.c b/tools/testing/selftests/bpf/prog_tests/kfree_skb.c index 73579370bfbd..c07991544a78 100644 --- a/tools/testing/selftests/bpf/prog_tests/kfree_skb.c +++ b/tools/testing/selftests/bpf/prog_tests/kfree_skb.c @@ -36,7 +36,7 @@ static void on_sample(void *ctx, int cpu, void *data, __u32 size)  		  "cb32_0 %x != %x\n",  		  meta->cb32_0, cb.cb32[0]))  		return; -	if (CHECK(pkt_v6->eth.h_proto != 0xdd86, "check_eth", +	if (CHECK(pkt_v6->eth.h_proto != htons(ETH_P_IPV6), "check_eth",  		  "h_proto %x\n", pkt_v6->eth.h_proto))  		return;  	if (CHECK(pkt_v6->iph.nexthdr != 6, "check_ip", diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c index 5af1ee8f0e6e..a543742cd7bd 100644 --- a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c +++ b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c @@ -72,10 +72,12 @@ static struct kfunc_test_params kfunc_tests[] = {  	/* success cases */  	TC_TEST(kfunc_call_test1, 12),  	TC_TEST(kfunc_call_test2, 3), +	TC_TEST(kfunc_call_test4, -1234),  	TC_TEST(kfunc_call_test_ref_btf_id, 0),  	TC_TEST(kfunc_call_test_get_mem, 42),  	SYSCALL_TEST(kfunc_syscall_test, 0),  	SYSCALL_NULL_CTX_TEST(kfunc_syscall_test_null, 0), +	TC_TEST(kfunc_call_test_static_unused_arg, 0),  };  struct syscall_test_args { diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_dynptr_param.c b/tools/testing/selftests/bpf/prog_tests/kfunc_dynptr_param.c index a9229260a6ce..8cd298b78e44 100644 --- a/tools/testing/selftests/bpf/prog_tests/kfunc_dynptr_param.c +++ b/tools/testing/selftests/bpf/prog_tests/kfunc_dynptr_param.c @@ -10,17 +10,11 @@  #include <test_progs.h>  #include "test_kfunc_dynptr_param.skel.h" -static size_t log_buf_sz = 1048576; /* 1 MB */ -static char obj_log_buf[1048576]; -  static struct {  	const char *prog_name; -	const char *expected_verifier_err_msg;  	int expected_runtime_err;  } kfunc_dynptr_tests[] = { -	{"not_valid_dynptr", "Expected an initialized dynptr as arg #1", 0}, -	{"not_ptr_to_stack", "arg#0 expected pointer to stack or dynptr_ptr", 0}, -	{"dynptr_data_null", NULL, -EBADMSG}, +	{"dynptr_data_null", -EBADMSG},  };  static bool kfunc_not_supported; @@ -38,29 +32,15 @@ static int libbpf_print_cb(enum libbpf_print_level level, const char *fmt,  	return 0;  } -static void verify_fail(const char *prog_name, const char *expected_err_msg) +static bool has_pkcs7_kfunc_support(void)  {  	struct test_kfunc_dynptr_param *skel; -	LIBBPF_OPTS(bpf_object_open_opts, opts);  	libbpf_print_fn_t old_print_cb; -	struct bpf_program *prog;  	int err; -	opts.kernel_log_buf = obj_log_buf; -	opts.kernel_log_size = log_buf_sz; -	opts.kernel_log_level = 1; - -	skel = test_kfunc_dynptr_param__open_opts(&opts); -	if (!ASSERT_OK_PTR(skel, "test_kfunc_dynptr_param__open_opts")) -		goto cleanup; - -	prog = bpf_object__find_program_by_name(skel->obj, prog_name); -	if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) -		goto cleanup; - -	bpf_program__set_autoload(prog, true); - -	bpf_map__set_max_entries(skel->maps.ringbuf, getpagesize()); +	skel = test_kfunc_dynptr_param__open(); +	if (!ASSERT_OK_PTR(skel, "test_kfunc_dynptr_param__open")) +		return false;  	kfunc_not_supported = false; @@ -72,26 +52,18 @@ static void verify_fail(const char *prog_name, const char *expected_err_msg)  		fprintf(stderr,  		  "%s:SKIP:bpf_verify_pkcs7_signature() kfunc not supported\n",  		  __func__); -		test__skip(); -		goto cleanup; -	} - -	if (!ASSERT_ERR(err, "unexpected load success")) -		goto cleanup; - -	if (!ASSERT_OK_PTR(strstr(obj_log_buf, expected_err_msg), "expected_err_msg")) { -		fprintf(stderr, "Expected err_msg: %s\n", expected_err_msg); -		fprintf(stderr, "Verifier output: %s\n", obj_log_buf); +		test_kfunc_dynptr_param__destroy(skel); +		return false;  	} -cleanup:  	test_kfunc_dynptr_param__destroy(skel); + +	return true;  }  static void verify_success(const char *prog_name, int expected_runtime_err)  {  	struct test_kfunc_dynptr_param *skel; -	libbpf_print_fn_t old_print_cb;  	struct bpf_program *prog;  	struct bpf_link *link;  	__u32 next_id; @@ -103,21 +75,7 @@ static void verify_success(const char *prog_name, int expected_runtime_err)  	skel->bss->pid = getpid(); -	bpf_map__set_max_entries(skel->maps.ringbuf, getpagesize()); - -	kfunc_not_supported = false; - -	old_print_cb = libbpf_set_print(libbpf_print_cb);  	err = test_kfunc_dynptr_param__load(skel); -	libbpf_set_print(old_print_cb); - -	if (err < 0 && kfunc_not_supported) { -		fprintf(stderr, -		  "%s:SKIP:bpf_verify_pkcs7_signature() kfunc not supported\n", -		  __func__); -		test__skip(); -		goto cleanup; -	}  	if (!ASSERT_OK(err, "test_kfunc_dynptr_param__load"))  		goto cleanup; @@ -147,15 +105,15 @@ void test_kfunc_dynptr_param(void)  {  	int i; +	if (!has_pkcs7_kfunc_support()) +		return; +  	for (i = 0; i < ARRAY_SIZE(kfunc_dynptr_tests); i++) {  		if (!test__start_subtest(kfunc_dynptr_tests[i].prog_name))  			continue; -		if (kfunc_dynptr_tests[i].expected_verifier_err_msg) -			verify_fail(kfunc_dynptr_tests[i].prog_name, -			  kfunc_dynptr_tests[i].expected_verifier_err_msg); -		else -			verify_success(kfunc_dynptr_tests[i].prog_name, -				kfunc_dynptr_tests[i].expected_runtime_err); +		verify_success(kfunc_dynptr_tests[i].prog_name, +			kfunc_dynptr_tests[i].expected_runtime_err);  	} +	RUN_TESTS(test_kfunc_dynptr_param);  } diff --git a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c index c6f37e825f11..113dba349a57 100644 --- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c +++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c @@ -322,7 +322,7 @@ static bool symbol_equal(long key1, long key2, void *ctx __maybe_unused)  	return strcmp((const char *) key1, (const char *) key2) == 0;  } -static int get_syms(char ***symsp, size_t *cntp) +static int get_syms(char ***symsp, size_t *cntp, bool kernel)  {  	size_t cap = 0, cnt = 0, i;  	char *name = NULL, **syms = NULL; @@ -349,8 +349,9 @@ static int get_syms(char ***symsp, size_t *cntp)  	}  	while (fgets(buf, sizeof(buf), f)) { -		/* skip modules */ -		if (strchr(buf, '[')) +		if (kernel && strchr(buf, '[')) +			continue; +		if (!kernel && !strchr(buf, '['))  			continue;  		free(name); @@ -404,7 +405,7 @@ error:  	return err;  } -void serial_test_kprobe_multi_bench_attach(void) +static void test_kprobe_multi_bench_attach(bool kernel)  {  	LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);  	struct kprobe_multi_empty *skel = NULL; @@ -415,7 +416,7 @@ void serial_test_kprobe_multi_bench_attach(void)  	char **syms = NULL;  	size_t cnt = 0, i; -	if (!ASSERT_OK(get_syms(&syms, &cnt), "get_syms")) +	if (!ASSERT_OK(get_syms(&syms, &cnt, kernel), "get_syms"))  		return;  	skel = kprobe_multi_empty__open_and_load(); @@ -453,6 +454,14 @@ cleanup:  	}  } +void serial_test_kprobe_multi_bench_attach(void) +{ +	if (test__start_subtest("kernel")) +		test_kprobe_multi_bench_attach(true); +	if (test__start_subtest("modules")) +		test_kprobe_multi_bench_attach(false); +} +  void test_kprobe_multi_test(void)  {  	if (!ASSERT_OK(load_kallsyms(), "load_kallsyms")) diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_get_fd_by_id_opts.c b/tools/testing/selftests/bpf/prog_tests/libbpf_get_fd_by_id_opts.c index 25e5dfa9c315..a3f238f51d05 100644 --- a/tools/testing/selftests/bpf/prog_tests/libbpf_get_fd_by_id_opts.c +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_get_fd_by_id_opts.c @@ -29,9 +29,9 @@ void test_libbpf_get_fd_by_id_opts(void)  	if (!ASSERT_OK(ret, "test_libbpf_get_fd_by_id_opts__attach"))  		goto close_prog; -	ret = bpf_obj_get_info_by_fd(bpf_map__fd(skel->maps.data_input), +	ret = bpf_map_get_info_by_fd(bpf_map__fd(skel->maps.data_input),  				     &info_m, &len); -	if (!ASSERT_OK(ret, "bpf_obj_get_info_by_fd")) +	if (!ASSERT_OK(ret, "bpf_map_get_info_by_fd"))  		goto close_prog;  	fd = bpf_map_get_fd_by_id(info_m.id); diff --git a/tools/testing/selftests/bpf/prog_tests/linked_list.c b/tools/testing/selftests/bpf/prog_tests/linked_list.c index 9a7d4c47af63..0ed8132ce1c3 100644 --- a/tools/testing/selftests/bpf/prog_tests/linked_list.c +++ b/tools/testing/selftests/bpf/prog_tests/linked_list.c @@ -58,12 +58,12 @@ static struct {  	TEST(inner_map, pop_front)  	TEST(inner_map, pop_back)  #undef TEST -	{ "map_compat_kprobe", "tracing progs cannot use bpf_list_head yet" }, -	{ "map_compat_kretprobe", "tracing progs cannot use bpf_list_head yet" }, -	{ "map_compat_tp", "tracing progs cannot use bpf_list_head yet" }, -	{ "map_compat_perf", "tracing progs cannot use bpf_list_head yet" }, -	{ "map_compat_raw_tp", "tracing progs cannot use bpf_list_head yet" }, -	{ "map_compat_raw_tp_w", "tracing progs cannot use bpf_list_head yet" }, +	{ "map_compat_kprobe", "tracing progs cannot use bpf_{list_head,rb_root} yet" }, +	{ "map_compat_kretprobe", "tracing progs cannot use bpf_{list_head,rb_root} yet" }, +	{ "map_compat_tp", "tracing progs cannot use bpf_{list_head,rb_root} yet" }, +	{ "map_compat_perf", "tracing progs cannot use bpf_{list_head,rb_root} yet" }, +	{ "map_compat_raw_tp", "tracing progs cannot use bpf_{list_head,rb_root} yet" }, +	{ "map_compat_raw_tp_w", "tracing progs cannot use bpf_{list_head,rb_root} yet" },  	{ "obj_type_id_oor", "local type ID argument must be in range [0, U32_MAX]" },  	{ "obj_new_no_composite", "bpf_obj_new type ID argument must be of a struct" },  	{ "obj_new_no_struct", "bpf_obj_new type ID argument must be of a struct" }, @@ -78,8 +78,6 @@ static struct {  	{ "direct_write_head", "direct access to bpf_list_head is disallowed" },  	{ "direct_read_node", "direct access to bpf_list_node is disallowed" },  	{ "direct_write_node", "direct access to bpf_list_node is disallowed" }, -	{ "write_after_push_front", "only read is supported" }, -	{ "write_after_push_back", "only read is supported" },  	{ "use_after_unlock_push_front", "invalid mem access 'scalar'" },  	{ "use_after_unlock_push_back", "invalid mem access 'scalar'" },  	{ "double_push_front", "arg#1 expected pointer to allocated object" }, @@ -717,6 +715,43 @@ static void test_btf(void)  		btf__free(btf);  		break;  	} + +	while (test__start_subtest("btf: list_node and rb_node in same struct")) { +		btf = init_btf(); +		if (!ASSERT_OK_PTR(btf, "init_btf")) +			break; + +		id = btf__add_struct(btf, "bpf_rb_node", 24); +		if (!ASSERT_EQ(id, 5, "btf__add_struct bpf_rb_node")) +			break; +		id = btf__add_struct(btf, "bar", 40); +		if (!ASSERT_EQ(id, 6, "btf__add_struct bar")) +			break; +		err = btf__add_field(btf, "a", LIST_NODE, 0, 0); +		if (!ASSERT_OK(err, "btf__add_field bar::a")) +			break; +		err = btf__add_field(btf, "c", 5, 128, 0); +		if (!ASSERT_OK(err, "btf__add_field bar::c")) +			break; + +		id = btf__add_struct(btf, "foo", 20); +		if (!ASSERT_EQ(id, 7, "btf__add_struct foo")) +			break; +		err = btf__add_field(btf, "a", LIST_HEAD, 0, 0); +		if (!ASSERT_OK(err, "btf__add_field foo::a")) +			break; +		err = btf__add_field(btf, "b", SPIN_LOCK, 128, 0); +		if (!ASSERT_OK(err, "btf__add_field foo::b")) +			break; +		id = btf__add_decl_tag(btf, "contains:bar:a", 7, 0); +		if (!ASSERT_EQ(id, 8, "btf__add_decl_tag contains:bar:a")) +			break; + +		err = btf__load_into_kernel(btf); +		ASSERT_EQ(err, -EINVAL, "check btf"); +		btf__free(btf); +		break; +	}  }  void test_linked_list(void) diff --git a/tools/testing/selftests/bpf/prog_tests/lsm_cgroup.c b/tools/testing/selftests/bpf/prog_tests/lsm_cgroup.c index f117bfef68a1..130a3b21e467 100644 --- a/tools/testing/selftests/bpf/prog_tests/lsm_cgroup.c +++ b/tools/testing/selftests/bpf/prog_tests/lsm_cgroup.c @@ -47,7 +47,8 @@ static __u32 query_prog_cnt(int cgroup_fd, const char *attach_func)  		fd = bpf_prog_get_fd_by_id(p.prog_ids[i]);  		ASSERT_GE(fd, 0, "prog_get_fd_by_id"); -		ASSERT_OK(bpf_obj_get_info_by_fd(fd, &info, &info_len), "prog_info_by_fd"); +		ASSERT_OK(bpf_prog_get_info_by_fd(fd, &info, &info_len), +			  "prog_info_by_fd");  		close(fd);  		if (info.attach_btf_id == diff --git a/tools/testing/selftests/bpf/prog_tests/metadata.c b/tools/testing/selftests/bpf/prog_tests/metadata.c index 2c53eade88e3..8b67dfc10f5c 100644 --- a/tools/testing/selftests/bpf/prog_tests/metadata.c +++ b/tools/testing/selftests/bpf/prog_tests/metadata.c @@ -16,7 +16,7 @@ static int duration;  static int prog_holds_map(int prog_fd, int map_fd)  {  	struct bpf_prog_info prog_info = {}; -	struct bpf_prog_info map_info = {}; +	struct bpf_map_info map_info = {};  	__u32 prog_info_len;  	__u32 map_info_len;  	__u32 *map_ids; @@ -25,12 +25,12 @@ static int prog_holds_map(int prog_fd, int map_fd)  	int i;  	map_info_len = sizeof(map_info); -	ret = bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len); +	ret = bpf_map_get_info_by_fd(map_fd, &map_info, &map_info_len);  	if (ret)  		return -errno;  	prog_info_len = sizeof(prog_info); -	ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); +	ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);  	if (ret)  		return -errno; @@ -44,7 +44,7 @@ static int prog_holds_map(int prog_fd, int map_fd)  	prog_info.map_ids = ptr_to_u64(map_ids);  	prog_info_len = sizeof(prog_info); -	ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); +	ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);  	if (ret) {  		ret = -errno;  		goto free_map_ids; diff --git a/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c index eb2feaac81fe..653b0a20fab9 100644 --- a/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c +++ b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c @@ -488,7 +488,7 @@ static void run_test(struct migrate_reuseport_test_case *test_case,  			goto close_servers;  	} -	/* Tie requests to the first four listners */ +	/* Tie requests to the first four listeners */  	err = start_clients(test_case);  	if (!ASSERT_OK(err, "start_clients"))  		goto close_clients; diff --git a/tools/testing/selftests/bpf/prog_tests/mmap.c b/tools/testing/selftests/bpf/prog_tests/mmap.c index 37b002ca1167..a271d5a0f7ab 100644 --- a/tools/testing/selftests/bpf/prog_tests/mmap.c +++ b/tools/testing/selftests/bpf/prog_tests/mmap.c @@ -64,7 +64,7 @@ void test_mmap(void)  	/* get map's ID */  	memset(&map_info, 0, map_info_sz); -	err = bpf_obj_get_info_by_fd(data_map_fd, &map_info, &map_info_sz); +	err = bpf_map_get_info_by_fd(data_map_fd, &map_info, &map_info_sz);  	if (CHECK(err, "map_get_info", "failed %d\n", errno))  		goto cleanup;  	data_map_id = map_info.id; diff --git a/tools/testing/selftests/bpf/prog_tests/nested_trust.c b/tools/testing/selftests/bpf/prog_tests/nested_trust.c new file mode 100644 index 000000000000..39886f58924e --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/nested_trust.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include <test_progs.h> +#include "nested_trust_failure.skel.h" +#include "nested_trust_success.skel.h" + +void test_nested_trust(void) +{ +	RUN_TESTS(nested_trust_success); +	RUN_TESTS(nested_trust_failure); +} diff --git a/tools/testing/selftests/bpf/prog_tests/perf_link.c b/tools/testing/selftests/bpf/prog_tests/perf_link.c index 224eba6fef2e..3a25f1c743a1 100644 --- a/tools/testing/selftests/bpf/prog_tests/perf_link.c +++ b/tools/testing/selftests/bpf/prog_tests/perf_link.c @@ -54,7 +54,7 @@ void serial_test_perf_link(void)  		goto cleanup;  	memset(&info, 0, sizeof(info)); -	err = bpf_obj_get_info_by_fd(link_fd, &info, &info_len); +	err = bpf_link_get_info_by_fd(link_fd, &info, &info_len);  	if (!ASSERT_OK(err, "link_get_info"))  		goto cleanup; diff --git a/tools/testing/selftests/bpf/prog_tests/pinning.c b/tools/testing/selftests/bpf/prog_tests/pinning.c index d95cee5867b7..c799a3c5ad1f 100644 --- a/tools/testing/selftests/bpf/prog_tests/pinning.c +++ b/tools/testing/selftests/bpf/prog_tests/pinning.c @@ -18,7 +18,7 @@ __u32 get_map_id(struct bpf_object *obj, const char *name)  	if (CHECK(!map, "find map", "NULL map"))  		return 0; -	err = bpf_obj_get_info_by_fd(bpf_map__fd(map), +	err = bpf_map_get_info_by_fd(bpf_map__fd(map),  				     &map_info, &map_info_len);  	CHECK(err, "get map info", "err %d errno %d", err, errno);  	return map_info.id; diff --git a/tools/testing/selftests/bpf/prog_tests/prog_run_opts.c b/tools/testing/selftests/bpf/prog_tests/prog_run_opts.c index 1ccd2bdf8fa8..01f1d1b6715a 100644 --- a/tools/testing/selftests/bpf/prog_tests/prog_run_opts.c +++ b/tools/testing/selftests/bpf/prog_tests/prog_run_opts.c @@ -12,7 +12,7 @@ static void check_run_cnt(int prog_fd, __u64 run_cnt)  	__u32 info_len = sizeof(info);  	int err; -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	if (CHECK(err, "get_prog_info", "failed to get bpf_prog_info for fd %d\n", prog_fd))  		return; diff --git a/tools/testing/selftests/bpf/prog_tests/rbtree.c b/tools/testing/selftests/bpf/prog_tests/rbtree.c new file mode 100644 index 000000000000..156fa95c42f6 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/rbtree.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ + +#include <test_progs.h> +#include <network_helpers.h> + +#include "rbtree.skel.h" +#include "rbtree_fail.skel.h" +#include "rbtree_btf_fail__wrong_node_type.skel.h" +#include "rbtree_btf_fail__add_wrong_type.skel.h" + +static void test_rbtree_add_nodes(void) +{ +	LIBBPF_OPTS(bpf_test_run_opts, opts, +		    .data_in = &pkt_v4, +		    .data_size_in = sizeof(pkt_v4), +		    .repeat = 1, +	); +	struct rbtree *skel; +	int ret; + +	skel = rbtree__open_and_load(); +	if (!ASSERT_OK_PTR(skel, "rbtree__open_and_load")) +		return; + +	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.rbtree_add_nodes), &opts); +	ASSERT_OK(ret, "rbtree_add_nodes run"); +	ASSERT_OK(opts.retval, "rbtree_add_nodes retval"); +	ASSERT_EQ(skel->data->less_callback_ran, 1, "rbtree_add_nodes less_callback_ran"); + +	rbtree__destroy(skel); +} + +static void test_rbtree_add_and_remove(void) +{ +	LIBBPF_OPTS(bpf_test_run_opts, opts, +		    .data_in = &pkt_v4, +		    .data_size_in = sizeof(pkt_v4), +		    .repeat = 1, +	); +	struct rbtree *skel; +	int ret; + +	skel = rbtree__open_and_load(); +	if (!ASSERT_OK_PTR(skel, "rbtree__open_and_load")) +		return; + +	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.rbtree_add_and_remove), &opts); +	ASSERT_OK(ret, "rbtree_add_and_remove"); +	ASSERT_OK(opts.retval, "rbtree_add_and_remove retval"); +	ASSERT_EQ(skel->data->removed_key, 5, "rbtree_add_and_remove first removed key"); + +	rbtree__destroy(skel); +} + +static void test_rbtree_first_and_remove(void) +{ +	LIBBPF_OPTS(bpf_test_run_opts, opts, +		    .data_in = &pkt_v4, +		    .data_size_in = sizeof(pkt_v4), +		    .repeat = 1, +	); +	struct rbtree *skel; +	int ret; + +	skel = rbtree__open_and_load(); +	if (!ASSERT_OK_PTR(skel, "rbtree__open_and_load")) +		return; + +	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.rbtree_first_and_remove), &opts); +	ASSERT_OK(ret, "rbtree_first_and_remove"); +	ASSERT_OK(opts.retval, "rbtree_first_and_remove retval"); +	ASSERT_EQ(skel->data->first_data[0], 2, "rbtree_first_and_remove first rbtree_first()"); +	ASSERT_EQ(skel->data->removed_key, 1, "rbtree_first_and_remove first removed key"); +	ASSERT_EQ(skel->data->first_data[1], 4, "rbtree_first_and_remove second rbtree_first()"); + +	rbtree__destroy(skel); +} + +void test_rbtree_success(void) +{ +	if (test__start_subtest("rbtree_add_nodes")) +		test_rbtree_add_nodes(); +	if (test__start_subtest("rbtree_add_and_remove")) +		test_rbtree_add_and_remove(); +	if (test__start_subtest("rbtree_first_and_remove")) +		test_rbtree_first_and_remove(); +} + +#define BTF_FAIL_TEST(suffix)									\ +void test_rbtree_btf_fail__##suffix(void)							\ +{												\ +	struct rbtree_btf_fail__##suffix *skel;							\ +												\ +	skel = rbtree_btf_fail__##suffix##__open_and_load();					\ +	if (!ASSERT_ERR_PTR(skel,								\ +			    "rbtree_btf_fail__" #suffix "__open_and_load unexpected success"))	\ +		rbtree_btf_fail__##suffix##__destroy(skel);					\ +} + +#define RUN_BTF_FAIL_TEST(suffix)				\ +	if (test__start_subtest("rbtree_btf_fail__" #suffix))	\ +		test_rbtree_btf_fail__##suffix(); + +BTF_FAIL_TEST(wrong_node_type); +BTF_FAIL_TEST(add_wrong_type); + +void test_rbtree_btf_fail(void) +{ +	RUN_BTF_FAIL_TEST(wrong_node_type); +	RUN_BTF_FAIL_TEST(add_wrong_type); +} + +void test_rbtree_fail(void) +{ +	RUN_TESTS(rbtree_fail); +} diff --git a/tools/testing/selftests/bpf/prog_tests/recursion.c b/tools/testing/selftests/bpf/prog_tests/recursion.c index f3af2627b599..23552d3e3365 100644 --- a/tools/testing/selftests/bpf/prog_tests/recursion.c +++ b/tools/testing/selftests/bpf/prog_tests/recursion.c @@ -31,8 +31,8 @@ void test_recursion(void)  	bpf_map_delete_elem(bpf_map__fd(skel->maps.hash2), &key);  	ASSERT_EQ(skel->bss->pass2, 2, "pass2 == 2"); -	err = bpf_obj_get_info_by_fd(bpf_program__fd(skel->progs.on_delete), -				     &prog_info, &prog_info_len); +	err = bpf_prog_get_info_by_fd(bpf_program__fd(skel->progs.on_delete), +				      &prog_info, &prog_info_len);  	if (!ASSERT_OK(err, "get_prog_info"))  		goto out;  	ASSERT_EQ(prog_info.recursion_misses, 2, "recursion_misses"); diff --git a/tools/testing/selftests/bpf/prog_tests/setget_sockopt.c b/tools/testing/selftests/bpf/prog_tests/setget_sockopt.c index 018611e6b248..7d4a9b3d3722 100644 --- a/tools/testing/selftests/bpf/prog_tests/setget_sockopt.c +++ b/tools/testing/selftests/bpf/prog_tests/setget_sockopt.c @@ -4,6 +4,7 @@  #define _GNU_SOURCE  #include <sched.h>  #include <linux/socket.h> +#include <linux/tls.h>  #include <net/if.h>  #include "test_progs.h" @@ -83,6 +84,76 @@ static void test_udp(int family)  	ASSERT_EQ(bss->nr_binddev, 1, "nr_bind");  } +static void test_ktls(int family) +{ +	struct tls12_crypto_info_aes_gcm_128 aes128; +	struct setget_sockopt__bss *bss = skel->bss; +	int cfd = -1, sfd = -1, fd = -1, ret; +	char buf; + +	memset(bss, 0, sizeof(*bss)); + +	sfd = start_server(family, SOCK_STREAM, +			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0); +	if (!ASSERT_GE(sfd, 0, "start_server")) +		return; +	fd = connect_to_fd(sfd, 0); +	if (!ASSERT_GE(fd, 0, "connect_to_fd")) +		goto err_out; + +	cfd = accept(sfd, NULL, 0); +	if (!ASSERT_GE(cfd, 0, "accept")) +		goto err_out; + +	close(sfd); +	sfd = -1; + +	/* Setup KTLS */ +	ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); +	if (!ASSERT_OK(ret, "setsockopt")) +		goto err_out; +	ret = setsockopt(cfd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); +	if (!ASSERT_OK(ret, "setsockopt")) +		goto err_out; + +	memset(&aes128, 0, sizeof(aes128)); +	aes128.info.version = TLS_1_2_VERSION; +	aes128.info.cipher_type = TLS_CIPHER_AES_GCM_128; + +	ret = setsockopt(fd, SOL_TLS, TLS_TX, &aes128, sizeof(aes128)); +	if (!ASSERT_OK(ret, "setsockopt")) +		goto err_out; + +	ret = setsockopt(cfd, SOL_TLS, TLS_RX, &aes128, sizeof(aes128)); +	if (!ASSERT_OK(ret, "setsockopt")) +		goto err_out; + +	/* KTLS is enabled */ + +	close(fd); +	/* At this point, the cfd socket is at the CLOSE_WAIT state +	 * and still run TLS protocol.  The test for +	 * BPF_TCP_CLOSE_WAIT should be run at this point. +	 */ +	ret = read(cfd, &buf, sizeof(buf)); +	ASSERT_EQ(ret, 0, "read"); +	close(cfd); + +	ASSERT_EQ(bss->nr_listen, 1, "nr_listen"); +	ASSERT_EQ(bss->nr_connect, 1, "nr_connect"); +	ASSERT_EQ(bss->nr_active, 1, "nr_active"); +	ASSERT_EQ(bss->nr_passive, 1, "nr_passive"); +	ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create"); +	ASSERT_EQ(bss->nr_binddev, 2, "nr_bind"); +	ASSERT_EQ(bss->nr_fin_wait1, 1, "nr_fin_wait1"); +	return; + +err_out: +	close(fd); +	close(cfd); +	close(sfd); +} +  void test_setget_sockopt(void)  {  	cg_fd = test__join_cgroup(CG_NAME); @@ -118,6 +189,8 @@ void test_setget_sockopt(void)  	test_tcp(AF_INET);  	test_udp(AF_INET6);  	test_udp(AF_INET); +	test_ktls(AF_INET6); +	test_ktls(AF_INET);  done:  	setget_sockopt__destroy(skel); diff --git a/tools/testing/selftests/bpf/prog_tests/sk_assign.c b/tools/testing/selftests/bpf/prog_tests/sk_assign.c index 3e190ed63976..1374b626a985 100644 --- a/tools/testing/selftests/bpf/prog_tests/sk_assign.c +++ b/tools/testing/selftests/bpf/prog_tests/sk_assign.c @@ -29,7 +29,23 @@ static int stop, duration;  static bool  configure_stack(void)  { +	char tc_version[128];  	char tc_cmd[BUFSIZ]; +	char *prog; +	FILE *tc; + +	/* Check whether tc is built with libbpf. */ +	tc = popen("tc -V", "r"); +	if (CHECK_FAIL(!tc)) +		return false; +	if (CHECK_FAIL(!fgets(tc_version, sizeof(tc_version), tc))) +		return false; +	if (strstr(tc_version, ", libbpf ")) +		prog = "test_sk_assign_libbpf.bpf.o"; +	else +		prog = "test_sk_assign.bpf.o"; +	if (CHECK_FAIL(pclose(tc))) +		return false;  	/* Move to a new networking namespace */  	if (CHECK_FAIL(unshare(CLONE_NEWNET))) @@ -46,8 +62,8 @@ configure_stack(void)  	/* Load qdisc, BPF program */  	if (CHECK_FAIL(system("tc qdisc add dev lo clsact")))  		return false; -	sprintf(tc_cmd, "%s %s %s %s", "tc filter add dev lo ingress bpf", -		       "direct-action object-file ./test_sk_assign.bpf.o", +	sprintf(tc_cmd, "%s %s %s %s %s", "tc filter add dev lo ingress bpf", +		       "direct-action object-file", prog,  		       "section tc",  		       (env.verbosity < VERBOSE_VERY) ? " 2>/dev/null" : "verbose");  	if (CHECK(system(tc_cmd), "BPF load failed;", @@ -129,15 +145,12 @@ get_port(int fd)  static ssize_t  rcv_msg(int srv_client, int type)  { -	struct sockaddr_storage ss;  	char buf[BUFSIZ]; -	socklen_t slen;  	if (type == SOCK_STREAM)  		return read(srv_client, &buf, sizeof(buf));  	else -		return recvfrom(srv_client, &buf, sizeof(buf), 0, -				(struct sockaddr *)&ss, &slen); +		return recvfrom(srv_client, &buf, sizeof(buf), 0, NULL, NULL);  }  static int diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c index 0aa088900699..0ce25a967481 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c @@ -299,9 +299,9 @@ static __u32 query_prog_id(int prog_fd)  	__u32 info_len = sizeof(info);  	int err; -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); -	if (!ASSERT_OK(err, "bpf_obj_get_info_by_fd") || -	    !ASSERT_EQ(info_len, sizeof(info), "bpf_obj_get_info_by_fd")) +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len); +	if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd") || +	    !ASSERT_EQ(info_len, sizeof(info), "bpf_prog_get_info_by_fd"))  		return 0;  	return info.id; diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c index 2cf0c7a3fe23..567e07c19ecc 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c @@ -30,6 +30,8 @@  #define MAX_STRERR_LEN 256  #define MAX_TEST_NAME 80 +#define __always_unused	__attribute__((__unused__)) +  #define _FAIL(errnum, fmt...)                                                  \  	({                                                                     \  		error_at_line(0, (errnum), __func__, __LINE__, fmt);           \ @@ -321,7 +323,8 @@ static int socket_loopback(int family, int sotype)  	return socket_loopback_reuseport(family, sotype, -1);  } -static void test_insert_invalid(int family, int sotype, int mapfd) +static void test_insert_invalid(struct test_sockmap_listen *skel __always_unused, +				int family, int sotype, int mapfd)  {  	u32 key = 0;  	u64 value; @@ -338,7 +341,8 @@ static void test_insert_invalid(int family, int sotype, int mapfd)  		FAIL_ERRNO("map_update: expected EBADF");  } -static void test_insert_opened(int family, int sotype, int mapfd) +static void test_insert_opened(struct test_sockmap_listen *skel __always_unused, +			       int family, int sotype, int mapfd)  {  	u32 key = 0;  	u64 value; @@ -359,7 +363,8 @@ static void test_insert_opened(int family, int sotype, int mapfd)  	xclose(s);  } -static void test_insert_bound(int family, int sotype, int mapfd) +static void test_insert_bound(struct test_sockmap_listen *skel __always_unused, +			      int family, int sotype, int mapfd)  {  	struct sockaddr_storage addr;  	socklen_t len; @@ -386,7 +391,8 @@ close:  	xclose(s);  } -static void test_insert(int family, int sotype, int mapfd) +static void test_insert(struct test_sockmap_listen *skel __always_unused, +			int family, int sotype, int mapfd)  {  	u64 value;  	u32 key; @@ -402,7 +408,8 @@ static void test_insert(int family, int sotype, int mapfd)  	xclose(s);  } -static void test_delete_after_insert(int family, int sotype, int mapfd) +static void test_delete_after_insert(struct test_sockmap_listen *skel __always_unused, +				     int family, int sotype, int mapfd)  {  	u64 value;  	u32 key; @@ -419,7 +426,8 @@ static void test_delete_after_insert(int family, int sotype, int mapfd)  	xclose(s);  } -static void test_delete_after_close(int family, int sotype, int mapfd) +static void test_delete_after_close(struct test_sockmap_listen *skel __always_unused, +				    int family, int sotype, int mapfd)  {  	int err, s;  	u64 value; @@ -442,7 +450,8 @@ static void test_delete_after_close(int family, int sotype, int mapfd)  		FAIL_ERRNO("map_delete: expected EINVAL/EINVAL");  } -static void test_lookup_after_insert(int family, int sotype, int mapfd) +static void test_lookup_after_insert(struct test_sockmap_listen *skel __always_unused, +				     int family, int sotype, int mapfd)  {  	u64 cookie, value;  	socklen_t len; @@ -470,7 +479,8 @@ static void test_lookup_after_insert(int family, int sotype, int mapfd)  	xclose(s);  } -static void test_lookup_after_delete(int family, int sotype, int mapfd) +static void test_lookup_after_delete(struct test_sockmap_listen *skel __always_unused, +				     int family, int sotype, int mapfd)  {  	int err, s;  	u64 value; @@ -493,7 +503,8 @@ static void test_lookup_after_delete(int family, int sotype, int mapfd)  	xclose(s);  } -static void test_lookup_32_bit_value(int family, int sotype, int mapfd) +static void test_lookup_32_bit_value(struct test_sockmap_listen *skel __always_unused, +				     int family, int sotype, int mapfd)  {  	u32 key, value32;  	int err, s; @@ -523,7 +534,8 @@ close:  	xclose(s);  } -static void test_update_existing(int family, int sotype, int mapfd) +static void test_update_existing(struct test_sockmap_listen *skel __always_unused, +				 int family, int sotype, int mapfd)  {  	int s1, s2;  	u64 value; @@ -551,7 +563,7 @@ close_s1:  /* Exercise the code path where we destroy child sockets that never   * got accept()'ed, aka orphans, when parent socket gets closed.   */ -static void test_destroy_orphan_child(int family, int sotype, int mapfd) +static void do_destroy_orphan_child(int family, int sotype, int mapfd)  {  	struct sockaddr_storage addr;  	socklen_t len; @@ -582,10 +594,38 @@ close_srv:  	xclose(s);  } +static void test_destroy_orphan_child(struct test_sockmap_listen *skel, +				      int family, int sotype, int mapfd) +{ +	int msg_verdict = bpf_program__fd(skel->progs.prog_msg_verdict); +	int skb_verdict = bpf_program__fd(skel->progs.prog_skb_verdict); +	const struct test { +		int progfd; +		enum bpf_attach_type atype; +	} tests[] = { +		{ -1, -1 }, +		{ msg_verdict, BPF_SK_MSG_VERDICT }, +		{ skb_verdict, BPF_SK_SKB_VERDICT }, +	}; +	const struct test *t; + +	for (t = tests; t < tests + ARRAY_SIZE(tests); t++) { +		if (t->progfd != -1 && +		    xbpf_prog_attach(t->progfd, mapfd, t->atype, 0) != 0) +			return; + +		do_destroy_orphan_child(family, sotype, mapfd); + +		if (t->progfd != -1) +			xbpf_prog_detach2(t->progfd, mapfd, t->atype); +	} +} +  /* Perform a passive open after removing listening socket from SOCKMAP   * to ensure that callbacks get restored properly.   */ -static void test_clone_after_delete(int family, int sotype, int mapfd) +static void test_clone_after_delete(struct test_sockmap_listen *skel __always_unused, +				    int family, int sotype, int mapfd)  {  	struct sockaddr_storage addr;  	socklen_t len; @@ -621,7 +661,8 @@ close_srv:   * SOCKMAP, but got accept()'ed only after the parent has been removed   * from SOCKMAP, gets cloned without parent psock state or callbacks.   */ -static void test_accept_after_delete(int family, int sotype, int mapfd) +static void test_accept_after_delete(struct test_sockmap_listen *skel __always_unused, +				     int family, int sotype, int mapfd)  {  	struct sockaddr_storage addr;  	const u32 zero = 0; @@ -675,7 +716,8 @@ close_srv:  /* Check that child socket that got created and accepted while parent   * was in a SOCKMAP is cloned without parent psock state or callbacks.   */ -static void test_accept_before_delete(int family, int sotype, int mapfd) +static void test_accept_before_delete(struct test_sockmap_listen *skel __always_unused, +				      int family, int sotype, int mapfd)  {  	struct sockaddr_storage addr;  	const u32 zero = 0, one = 1; @@ -784,7 +826,8 @@ done:  	return NULL;  } -static void test_syn_recv_insert_delete(int family, int sotype, int mapfd) +static void test_syn_recv_insert_delete(struct test_sockmap_listen *skel __always_unused, +					int family, int sotype, int mapfd)  {  	struct connect_accept_ctx ctx = { 0 };  	struct sockaddr_storage addr; @@ -847,7 +890,8 @@ static void *listen_thread(void *arg)  	return NULL;  } -static void test_race_insert_listen(int family, int socktype, int mapfd) +static void test_race_insert_listen(struct test_sockmap_listen *skel __always_unused, +				    int family, int socktype, int mapfd)  {  	struct connect_accept_ctx ctx = { 0 };  	const u32 zero = 0; @@ -1473,7 +1517,8 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,  		     int family, int sotype)  {  	const struct op_test { -		void (*fn)(int family, int sotype, int mapfd); +		void (*fn)(struct test_sockmap_listen *skel, +			   int family, int sotype, int mapfd);  		const char *name;  		int sotype;  	} tests[] = { @@ -1520,7 +1565,7 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,  		if (!test__start_subtest(s))  			continue; -		t->fn(family, sotype, map_fd); +		t->fn(skel, family, sotype, map_fd);  		test_ops_cleanup(map);  	}  } diff --git a/tools/testing/selftests/bpf/prog_tests/task_kfunc.c b/tools/testing/selftests/bpf/prog_tests/task_kfunc.c index 18848c31e36f..f79fa5bc9a8d 100644 --- a/tools/testing/selftests/bpf/prog_tests/task_kfunc.c +++ b/tools/testing/selftests/bpf/prog_tests/task_kfunc.c @@ -9,9 +9,6 @@  #include "task_kfunc_failure.skel.h"  #include "task_kfunc_success.skel.h" -static size_t log_buf_sz = 1 << 20; /* 1 MB */ -static char obj_log_buf[1048576]; -  static struct task_kfunc_success *open_load_task_kfunc_skel(void)  {  	struct task_kfunc_success *skel; @@ -83,67 +80,6 @@ static const char * const success_tests[] = {  	"test_task_from_pid_invalid",  }; -static struct { -	const char *prog_name; -	const char *expected_err_msg; -} failure_tests[] = { -	{"task_kfunc_acquire_untrusted", "R1 must be referenced or trusted"}, -	{"task_kfunc_acquire_fp", "arg#0 pointer type STRUCT task_struct must point"}, -	{"task_kfunc_acquire_unsafe_kretprobe", "reg type unsupported for arg#0 function"}, -	{"task_kfunc_acquire_trusted_walked", "R1 must be referenced or trusted"}, -	{"task_kfunc_acquire_null", "arg#0 pointer type STRUCT task_struct must point"}, -	{"task_kfunc_acquire_unreleased", "Unreleased reference"}, -	{"task_kfunc_get_non_kptr_param", "arg#0 expected pointer to map value"}, -	{"task_kfunc_get_non_kptr_acquired", "arg#0 expected pointer to map value"}, -	{"task_kfunc_get_null", "arg#0 expected pointer to map value"}, -	{"task_kfunc_xchg_unreleased", "Unreleased reference"}, -	{"task_kfunc_get_unreleased", "Unreleased reference"}, -	{"task_kfunc_release_untrusted", "arg#0 is untrusted_ptr_or_null_ expected ptr_ or socket"}, -	{"task_kfunc_release_fp", "arg#0 pointer type STRUCT task_struct must point"}, -	{"task_kfunc_release_null", "arg#0 is ptr_or_null_ expected ptr_ or socket"}, -	{"task_kfunc_release_unacquired", "release kernel function bpf_task_release expects"}, -	{"task_kfunc_from_pid_no_null_check", "arg#0 is ptr_or_null_ expected ptr_ or socket"}, -	{"task_kfunc_from_lsm_task_free", "reg type unsupported for arg#0 function"}, -}; - -static void verify_fail(const char *prog_name, const char *expected_err_msg) -{ -	LIBBPF_OPTS(bpf_object_open_opts, opts); -	struct task_kfunc_failure *skel; -	int err, i; - -	opts.kernel_log_buf = obj_log_buf; -	opts.kernel_log_size = log_buf_sz; -	opts.kernel_log_level = 1; - -	skel = task_kfunc_failure__open_opts(&opts); -	if (!ASSERT_OK_PTR(skel, "task_kfunc_failure__open_opts")) -		goto cleanup; - -	for (i = 0; i < ARRAY_SIZE(failure_tests); i++) { -		struct bpf_program *prog; -		const char *curr_name = failure_tests[i].prog_name; - -		prog = bpf_object__find_program_by_name(skel->obj, curr_name); -		if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) -			goto cleanup; - -		bpf_program__set_autoload(prog, !strcmp(curr_name, prog_name)); -	} - -	err = task_kfunc_failure__load(skel); -	if (!ASSERT_ERR(err, "unexpected load success")) -		goto cleanup; - -	if (!ASSERT_OK_PTR(strstr(obj_log_buf, expected_err_msg), "expected_err_msg")) { -		fprintf(stderr, "Expected err_msg: %s\n", expected_err_msg); -		fprintf(stderr, "Verifier output: %s\n", obj_log_buf); -	} - -cleanup: -	task_kfunc_failure__destroy(skel); -} -  void test_task_kfunc(void)  {  	int i; @@ -155,10 +91,5 @@ void test_task_kfunc(void)  		run_success_test(success_tests[i]);  	} -	for (i = 0; i < ARRAY_SIZE(failure_tests); i++) { -		if (!test__start_subtest(failure_tests[i].prog_name)) -			continue; - -		verify_fail(failure_tests[i].prog_name, failure_tests[i].expected_err_msg); -	} +	RUN_TESTS(task_kfunc_failure);  } diff --git a/tools/testing/selftests/bpf/prog_tests/task_local_storage.c b/tools/testing/selftests/bpf/prog_tests/task_local_storage.c index a176bd75a748..ea8537c54413 100644 --- a/tools/testing/selftests/bpf/prog_tests/task_local_storage.c +++ b/tools/testing/selftests/bpf/prog_tests/task_local_storage.c @@ -119,19 +119,19 @@ static void test_recursion(void)  	prog_fd = bpf_program__fd(skel->progs.on_lookup);  	memset(&info, 0, sizeof(info)); -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	ASSERT_OK(err, "get prog info");  	ASSERT_GT(info.recursion_misses, 0, "on_lookup prog recursion");  	prog_fd = bpf_program__fd(skel->progs.on_update);  	memset(&info, 0, sizeof(info)); -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	ASSERT_OK(err, "get prog info");  	ASSERT_EQ(info.recursion_misses, 0, "on_update prog recursion");  	prog_fd = bpf_program__fd(skel->progs.on_enter);  	memset(&info, 0, sizeof(info)); -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	ASSERT_OK(err, "get prog info");  	ASSERT_EQ(info.recursion_misses, 0, "on_enter prog recursion"); @@ -221,7 +221,7 @@ static void test_nodeadlock(void)  	info_len = sizeof(info);  	prog_fd = bpf_program__fd(skel->progs.socket_post_create); -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);  	ASSERT_OK(err, "get prog info");  	ASSERT_EQ(info.recursion_misses, 0, "prog recursion"); diff --git a/tools/testing/selftests/bpf/prog_tests/tc_bpf.c b/tools/testing/selftests/bpf/prog_tests/tc_bpf.c index 4a505a5adf4d..e873766276d1 100644 --- a/tools/testing/selftests/bpf/prog_tests/tc_bpf.c +++ b/tools/testing/selftests/bpf/prog_tests/tc_bpf.c @@ -29,8 +29,8 @@ static int test_tc_bpf_basic(const struct bpf_tc_hook *hook, int fd)  	__u32 info_len = sizeof(info);  	int ret; -	ret = bpf_obj_get_info_by_fd(fd, &info, &info_len); -	if (!ASSERT_OK(ret, "bpf_obj_get_info_by_fd")) +	ret = bpf_prog_get_info_by_fd(fd, &info, &info_len); +	if (!ASSERT_OK(ret, "bpf_prog_get_info_by_fd"))  		return ret;  	ret = bpf_tc_attach(hook, &opts); diff --git a/tools/testing/selftests/bpf/prog_tests/test_bpf_syscall_macro.c b/tools/testing/selftests/bpf/prog_tests/test_bpf_syscall_macro.c index c381faaae741..2900c5e9a016 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_bpf_syscall_macro.c +++ b/tools/testing/selftests/bpf/prog_tests/test_bpf_syscall_macro.c @@ -1,5 +1,7 @@  // SPDX-License-Identifier: GPL-2.0  /* Copyright 2022 Sony Group Corporation */ +#define _GNU_SOURCE +#include <fcntl.h>  #include <sys/prctl.h>  #include <test_progs.h>  #include "bpf_syscall_macro.skel.h" @@ -13,6 +15,8 @@ void test_bpf_syscall_macro(void)  	unsigned long exp_arg3 = 13;  	unsigned long exp_arg4 = 14;  	unsigned long exp_arg5 = 15; +	loff_t off_in, off_out; +	ssize_t r;  	/* check whether it can open program */  	skel = bpf_syscall_macro__open(); @@ -33,6 +37,7 @@ void test_bpf_syscall_macro(void)  	/* check whether args of syscall are copied correctly */  	prctl(exp_arg1, exp_arg2, exp_arg3, exp_arg4, exp_arg5); +  #if defined(__aarch64__) || defined(__s390__)  	ASSERT_NEQ(skel->bss->arg1, exp_arg1, "syscall_arg1");  #else @@ -68,6 +73,18 @@ void test_bpf_syscall_macro(void)  	ASSERT_EQ(skel->bss->arg4_syscall, exp_arg4, "BPF_KPROBE_SYSCALL_arg4");  	ASSERT_EQ(skel->bss->arg5_syscall, exp_arg5, "BPF_KPROBE_SYSCALL_arg5"); +	r = splice(-42, &off_in, 42, &off_out, 0x12340000, SPLICE_F_NONBLOCK); +	err = -errno; +	ASSERT_EQ(r, -1, "splice_res"); +	ASSERT_EQ(err, -EBADF, "splice_err"); + +	ASSERT_EQ(skel->bss->splice_fd_in, -42, "splice_arg1"); +	ASSERT_EQ(skel->bss->splice_off_in, (__u64)&off_in, "splice_arg2"); +	ASSERT_EQ(skel->bss->splice_fd_out, 42, "splice_arg3"); +	ASSERT_EQ(skel->bss->splice_off_out, (__u64)&off_out, "splice_arg4"); +	ASSERT_EQ(skel->bss->splice_len, 0x12340000, "splice_arg5"); +	ASSERT_EQ(skel->bss->splice_flags, SPLICE_F_NONBLOCK, "splice_arg6"); +  cleanup:  	bpf_syscall_macro__destroy(skel);  } diff --git a/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c b/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c index 7295cc60f724..e0879df38639 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c +++ b/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c @@ -1,104 +1,43 @@  // SPDX-License-Identifier: GPL-2.0  /* Copyright (c) 2020 Facebook */  #include <test_progs.h> - -const char *err_str; -bool found; - -static int libbpf_debug_print(enum libbpf_print_level level, -			      const char *format, va_list args) -{ -	char *log_buf; - -	if (level != LIBBPF_WARN || -	    strcmp(format, "libbpf: \n%s\n")) { -		vprintf(format, args); -		return 0; -	} - -	log_buf = va_arg(args, char *); -	if (!log_buf) -		goto out; -	if (err_str && strstr(log_buf, err_str) == 0) -		found = true; -out: -	printf(format, log_buf); -	return 0; -} - -extern int extra_prog_load_log_flags; - -static int check_load(const char *file) -{ -	struct bpf_object *obj = NULL; -	struct bpf_program *prog; -	int err; - -	found = false; - -	obj = bpf_object__open_file(file, NULL); -	err = libbpf_get_error(obj); -	if (err) -		return err; - -	prog = bpf_object__next_program(obj, NULL); -	if (!prog) { -		err = -ENOENT; -		goto err_out; -	} - -	bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32); -	bpf_program__set_log_level(prog, extra_prog_load_log_flags); - -	err = bpf_object__load(obj); - -err_out: -	bpf_object__close(obj); -	return err; -} - -struct test_def { -	const char *file; -	const char *err_str; -}; +#include "test_global_func1.skel.h" +#include "test_global_func2.skel.h" +#include "test_global_func3.skel.h" +#include "test_global_func4.skel.h" +#include "test_global_func5.skel.h" +#include "test_global_func6.skel.h" +#include "test_global_func7.skel.h" +#include "test_global_func8.skel.h" +#include "test_global_func9.skel.h" +#include "test_global_func10.skel.h" +#include "test_global_func11.skel.h" +#include "test_global_func12.skel.h" +#include "test_global_func13.skel.h" +#include "test_global_func14.skel.h" +#include "test_global_func15.skel.h" +#include "test_global_func16.skel.h" +#include "test_global_func17.skel.h" +#include "test_global_func_ctx_args.skel.h"  void test_test_global_funcs(void)  { -	struct test_def tests[] = { -		{ "test_global_func1.bpf.o", "combined stack size of 4 calls is 544" }, -		{ "test_global_func2.bpf.o" }, -		{ "test_global_func3.bpf.o", "the call stack of 8 frames" }, -		{ "test_global_func4.bpf.o" }, -		{ "test_global_func5.bpf.o", "expected pointer to ctx, but got PTR" }, -		{ "test_global_func6.bpf.o", "modified ctx ptr R2" }, -		{ "test_global_func7.bpf.o", "foo() doesn't return scalar" }, -		{ "test_global_func8.bpf.o" }, -		{ "test_global_func9.bpf.o" }, -		{ "test_global_func10.bpf.o", "invalid indirect read from stack" }, -		{ "test_global_func11.bpf.o", "Caller passes invalid args into func#1" }, -		{ "test_global_func12.bpf.o", "invalid mem access 'mem_or_null'" }, -		{ "test_global_func13.bpf.o", "Caller passes invalid args into func#1" }, -		{ "test_global_func14.bpf.o", "reference type('FWD S') size cannot be determined" }, -		{ "test_global_func15.bpf.o", "At program exit the register R0 has value" }, -		{ "test_global_func16.bpf.o", "invalid indirect read from stack" }, -		{ "test_global_func17.bpf.o", "Caller passes invalid args into func#1" }, -	}; -	libbpf_print_fn_t old_print_fn = NULL; -	int err, i, duration = 0; - -	old_print_fn = libbpf_set_print(libbpf_debug_print); - -	for (i = 0; i < ARRAY_SIZE(tests); i++) { -		const struct test_def *test = &tests[i]; - -		if (!test__start_subtest(test->file)) -			continue; - -		err_str = test->err_str; -		err = check_load(test->file); -		CHECK_FAIL(!!err ^ !!err_str); -		if (err_str) -			CHECK(found, "", "expected string '%s'", err_str); -	} -	libbpf_set_print(old_print_fn); +	RUN_TESTS(test_global_func1); +	RUN_TESTS(test_global_func2); +	RUN_TESTS(test_global_func3); +	RUN_TESTS(test_global_func4); +	RUN_TESTS(test_global_func5); +	RUN_TESTS(test_global_func6); +	RUN_TESTS(test_global_func7); +	RUN_TESTS(test_global_func8); +	RUN_TESTS(test_global_func9); +	RUN_TESTS(test_global_func10); +	RUN_TESTS(test_global_func11); +	RUN_TESTS(test_global_func12); +	RUN_TESTS(test_global_func13); +	RUN_TESTS(test_global_func14); +	RUN_TESTS(test_global_func15); +	RUN_TESTS(test_global_func16); +	RUN_TESTS(test_global_func17); +	RUN_TESTS(test_global_func_ctx_args);  } diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c b/tools/testing/selftests/bpf/prog_tests/test_lsm.c index 244c01125126..16175d579bc7 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c @@ -75,7 +75,8 @@ static int test_lsm(struct lsm *skel)  	skel->bss->monitored_pid = getpid();  	err = stack_mprotect(); -	if (!ASSERT_EQ(errno, EPERM, "stack_mprotect")) +	if (!ASSERT_EQ(err, -1, "stack_mprotect") || +	    !ASSERT_EQ(errno, EPERM, "stack_mprotect"))  		return err;  	ASSERT_EQ(skel->bss->mprotect_count, 1, "mprotect_count"); diff --git a/tools/testing/selftests/bpf/prog_tests/tp_attach_query.c b/tools/testing/selftests/bpf/prog_tests/tp_attach_query.c index a479080533db..770fcc3bb1ba 100644 --- a/tools/testing/selftests/bpf/prog_tests/tp_attach_query.c +++ b/tools/testing/selftests/bpf/prog_tests/tp_attach_query.c @@ -45,8 +45,9 @@ void serial_test_tp_attach_query(void)  		prog_info.xlated_prog_len = 0;  		prog_info.nr_map_ids = 0;  		info_len = sizeof(prog_info); -		err = bpf_obj_get_info_by_fd(prog_fd[i], &prog_info, &info_len); -		if (CHECK(err, "bpf_obj_get_info_by_fd", "err %d errno %d\n", +		err = bpf_prog_get_info_by_fd(prog_fd[i], &prog_info, +					      &info_len); +		if (CHECK(err, "bpf_prog_get_info_by_fd", "err %d errno %d\n",  			  err, errno))  			goto cleanup1;  		saved_prog_ids[i] = prog_info.id; diff --git a/tools/testing/selftests/bpf/prog_tests/trampoline_count.c b/tools/testing/selftests/bpf/prog_tests/trampoline_count.c index 564b75bc087f..e91d0d1769f1 100644 --- a/tools/testing/selftests/bpf/prog_tests/trampoline_count.c +++ b/tools/testing/selftests/bpf/prog_tests/trampoline_count.c @@ -2,8 +2,6 @@  #define _GNU_SOURCE  #include <test_progs.h> -#define MAX_TRAMP_PROGS 38 -  struct inst {  	struct bpf_object *obj;  	struct bpf_link   *link; @@ -37,14 +35,21 @@ void serial_test_trampoline_count(void)  {  	char *file = "test_trampoline_count.bpf.o";  	char *const progs[] = { "fentry_test", "fmod_ret_test", "fexit_test" }; -	struct inst inst[MAX_TRAMP_PROGS + 1] = {}; +	int bpf_max_tramp_links, err, i, prog_fd;  	struct bpf_program *prog;  	struct bpf_link *link; -	int prog_fd, err, i; +	struct inst *inst;  	LIBBPF_OPTS(bpf_test_run_opts, opts); +	bpf_max_tramp_links = get_bpf_max_tramp_links(); +	if (!ASSERT_GE(bpf_max_tramp_links, 1, "bpf_max_tramp_links")) +		return; +	inst = calloc(bpf_max_tramp_links + 1, sizeof(*inst)); +	if (!ASSERT_OK_PTR(inst, "inst")) +		return; +  	/* attach 'allowed' trampoline programs */ -	for (i = 0; i < MAX_TRAMP_PROGS; i++) { +	for (i = 0; i < bpf_max_tramp_links; i++) {  		prog = load_prog(file, progs[i % ARRAY_SIZE(progs)], &inst[i]);  		if (!prog)  			goto cleanup; @@ -74,7 +79,7 @@ void serial_test_trampoline_count(void)  	if (!ASSERT_EQ(link, NULL, "ptr_is_null"))  		goto cleanup; -	/* and finaly execute the probe */ +	/* and finally execute the probe */  	prog_fd = bpf_program__fd(prog);  	if (!ASSERT_GE(prog_fd, 0, "bpf_program__fd"))  		goto cleanup; @@ -91,4 +96,5 @@ cleanup:  		bpf_link__destroy(inst[i].link);  		bpf_object__close(inst[i].obj);  	} +	free(inst);  } diff --git a/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c b/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c index 1ed3cc2092db..8383a99f610f 100644 --- a/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c +++ b/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c @@ -179,7 +179,7 @@ static void test_unpriv_bpf_disabled_negative(struct test_unpriv_bpf_disabled *s  	ASSERT_EQ(bpf_prog_get_next_id(prog_id, &next), -EPERM, "prog_get_next_id_fails");  	ASSERT_EQ(bpf_prog_get_next_id(0, &next), -EPERM, "prog_get_next_id_fails"); -	if (ASSERT_OK(bpf_obj_get_info_by_fd(map_fds[0], &map_info, &map_info_len), +	if (ASSERT_OK(bpf_map_get_info_by_fd(map_fds[0], &map_info, &map_info_len),  		      "obj_get_info_by_fd")) {  		ASSERT_EQ(bpf_map_get_fd_by_id(map_info.id), -EPERM, "map_get_fd_by_id_fails");  		ASSERT_EQ(bpf_map_get_next_id(map_info.id, &next), -EPERM, @@ -187,8 +187,8 @@ static void test_unpriv_bpf_disabled_negative(struct test_unpriv_bpf_disabled *s  	}  	ASSERT_EQ(bpf_map_get_next_id(0, &next), -EPERM, "map_get_next_id_fails"); -	if (ASSERT_OK(bpf_obj_get_info_by_fd(bpf_link__fd(skel->links.sys_nanosleep_enter), -					     &link_info, &link_info_len), +	if (ASSERT_OK(bpf_link_get_info_by_fd(bpf_link__fd(skel->links.sys_nanosleep_enter), +					      &link_info, &link_info_len),  		      "obj_get_info_by_fd")) {  		ASSERT_EQ(bpf_link_get_fd_by_id(link_info.id), -EPERM, "link_get_fd_by_id_fails");  		ASSERT_EQ(bpf_link_get_next_id(link_info.id, &next), -EPERM, @@ -269,7 +269,7 @@ void test_unpriv_bpf_disabled(void)  	}  	prog_fd = bpf_program__fd(skel->progs.sys_nanosleep_enter); -	ASSERT_OK(bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len), +	ASSERT_OK(bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len),  		  "obj_get_info_by_fd");  	prog_id = prog_info.id;  	ASSERT_GT(prog_id, 0, "valid_prog_id"); diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c b/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c index 35b87c7ba5be..6558c857e620 100644 --- a/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c @@ -3,20 +3,23 @@  #include <test_progs.h>  #include "test_uprobe_autoattach.skel.h" +#include "progs/bpf_misc.h"  /* uprobe attach point */ -static noinline int autoattach_trigger_func(int arg) +static noinline int autoattach_trigger_func(int arg1, int arg2, int arg3, +					    int arg4, int arg5, int arg6, +					    int arg7, int arg8)  {  	asm volatile (""); -	return arg + 1; +	return arg1 + arg2 + arg3 + arg4 + arg5 + arg6 + arg7 + arg8 + 1;  }  void test_uprobe_autoattach(void)  { +	const char *devnull_str = "/dev/null";  	struct test_uprobe_autoattach *skel; -	int trigger_val = 100, trigger_ret; -	size_t malloc_sz = 1; -	char *mem; +	int trigger_ret; +	FILE *devnull;  	skel = test_uprobe_autoattach__open_and_load();  	if (!ASSERT_OK_PTR(skel, "skel_open")) @@ -28,23 +31,45 @@ void test_uprobe_autoattach(void)  	skel->bss->test_pid = getpid();  	/* trigger & validate uprobe & uretprobe */ -	trigger_ret = autoattach_trigger_func(trigger_val); +	trigger_ret = autoattach_trigger_func(1, 2, 3, 4, 5, 6, 7, 8);  	skel->bss->test_pid = getpid();  	/* trigger & validate shared library u[ret]probes attached by name */ -	mem = malloc(malloc_sz); +	devnull = fopen(devnull_str, "r"); -	ASSERT_EQ(skel->bss->uprobe_byname_parm1, trigger_val, "check_uprobe_byname_parm1"); +	ASSERT_EQ(skel->bss->uprobe_byname_parm1, 1, "check_uprobe_byname_parm1");  	ASSERT_EQ(skel->bss->uprobe_byname_ran, 1, "check_uprobe_byname_ran");  	ASSERT_EQ(skel->bss->uretprobe_byname_rc, trigger_ret, "check_uretprobe_byname_rc"); +	ASSERT_EQ(skel->bss->uretprobe_byname_ret, trigger_ret, "check_uretprobe_byname_ret");  	ASSERT_EQ(skel->bss->uretprobe_byname_ran, 2, "check_uretprobe_byname_ran"); -	ASSERT_EQ(skel->bss->uprobe_byname2_parm1, malloc_sz, "check_uprobe_byname2_parm1"); +	ASSERT_EQ(skel->bss->uprobe_byname2_parm1, (__u64)(long)devnull_str, +		  "check_uprobe_byname2_parm1");  	ASSERT_EQ(skel->bss->uprobe_byname2_ran, 3, "check_uprobe_byname2_ran"); -	ASSERT_EQ(skel->bss->uretprobe_byname2_rc, mem, "check_uretprobe_byname2_rc"); +	ASSERT_EQ(skel->bss->uretprobe_byname2_rc, (__u64)(long)devnull, +		  "check_uretprobe_byname2_rc");  	ASSERT_EQ(skel->bss->uretprobe_byname2_ran, 4, "check_uretprobe_byname2_ran"); -	free(mem); +	ASSERT_EQ(skel->bss->a[0], 1, "arg1"); +	ASSERT_EQ(skel->bss->a[1], 2, "arg2"); +	ASSERT_EQ(skel->bss->a[2], 3, "arg3"); +#if FUNC_REG_ARG_CNT > 3 +	ASSERT_EQ(skel->bss->a[3], 4, "arg4"); +#endif +#if FUNC_REG_ARG_CNT > 4 +	ASSERT_EQ(skel->bss->a[4], 5, "arg5"); +#endif +#if FUNC_REG_ARG_CNT > 5 +	ASSERT_EQ(skel->bss->a[5], 6, "arg6"); +#endif +#if FUNC_REG_ARG_CNT > 6 +	ASSERT_EQ(skel->bss->a[6], 7, "arg7"); +#endif +#if FUNC_REG_ARG_CNT > 7 +	ASSERT_EQ(skel->bss->a[7], 8, "arg8"); +#endif + +	fclose(devnull);  cleanup:  	test_uprobe_autoattach__destroy(skel);  } diff --git a/tools/testing/selftests/bpf/prog_tests/usdt.c b/tools/testing/selftests/bpf/prog_tests/usdt.c index 9ad9da0f215e..56ed1eb9b527 100644 --- a/tools/testing/selftests/bpf/prog_tests/usdt.c +++ b/tools/testing/selftests/bpf/prog_tests/usdt.c @@ -314,6 +314,7 @@ static FILE *urand_spawn(int *pid)  	if (fscanf(f, "%d", pid) != 1) {  		pclose(f); +		errno = EINVAL;  		return NULL;  	} diff --git a/tools/testing/selftests/bpf/prog_tests/user_ringbuf.c b/tools/testing/selftests/bpf/prog_tests/user_ringbuf.c index dae68de285b9..3a13e102c149 100644 --- a/tools/testing/selftests/bpf/prog_tests/user_ringbuf.c +++ b/tools/testing/selftests/bpf/prog_tests/user_ringbuf.c @@ -19,8 +19,6 @@  #include "../progs/test_user_ringbuf.h" -static size_t log_buf_sz = 1 << 20; /* 1 MB */ -static char obj_log_buf[1048576];  static const long c_sample_size = sizeof(struct sample) + BPF_RINGBUF_HDR_SZ;  static const long c_ringbuf_size = 1 << 12; /* 1 small page */  static const long c_max_entries = c_ringbuf_size / c_sample_size; @@ -663,23 +661,6 @@ cleanup:  	user_ringbuf_success__destroy(skel);  } -static struct { -	const char *prog_name; -	const char *expected_err_msg; -} failure_tests[] = { -	/* failure cases */ -	{"user_ringbuf_callback_bad_access1", "negative offset dynptr_ptr ptr"}, -	{"user_ringbuf_callback_bad_access2", "dereference of modified dynptr_ptr ptr"}, -	{"user_ringbuf_callback_write_forbidden", "invalid mem access 'dynptr_ptr'"}, -	{"user_ringbuf_callback_null_context_write", "invalid mem access 'scalar'"}, -	{"user_ringbuf_callback_null_context_read", "invalid mem access 'scalar'"}, -	{"user_ringbuf_callback_discard_dynptr", "cannot release unowned const bpf_dynptr"}, -	{"user_ringbuf_callback_submit_dynptr", "cannot release unowned const bpf_dynptr"}, -	{"user_ringbuf_callback_invalid_return", "At callback return the register R0 has value"}, -	{"user_ringbuf_callback_reinit_dynptr_mem", "Dynptr has to be an uninitialized dynptr"}, -	{"user_ringbuf_callback_reinit_dynptr_ringbuf", "Dynptr has to be an uninitialized dynptr"}, -}; -  #define SUCCESS_TEST(_func) { _func, #_func }  static struct { @@ -700,42 +681,6 @@ static struct {  	SUCCESS_TEST(test_user_ringbuf_blocking_reserve),  }; -static void verify_fail(const char *prog_name, const char *expected_err_msg) -{ -	LIBBPF_OPTS(bpf_object_open_opts, opts); -	struct bpf_program *prog; -	struct user_ringbuf_fail *skel; -	int err; - -	opts.kernel_log_buf = obj_log_buf; -	opts.kernel_log_size = log_buf_sz; -	opts.kernel_log_level = 1; - -	skel = user_ringbuf_fail__open_opts(&opts); -	if (!ASSERT_OK_PTR(skel, "dynptr_fail__open_opts")) -		goto cleanup; - -	prog = bpf_object__find_program_by_name(skel->obj, prog_name); -	if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) -		goto cleanup; - -	bpf_program__set_autoload(prog, true); - -	bpf_map__set_max_entries(skel->maps.user_ringbuf, getpagesize()); - -	err = user_ringbuf_fail__load(skel); -	if (!ASSERT_ERR(err, "unexpected load success")) -		goto cleanup; - -	if (!ASSERT_OK_PTR(strstr(obj_log_buf, expected_err_msg), "expected_err_msg")) { -		fprintf(stderr, "Expected err_msg: %s\n", expected_err_msg); -		fprintf(stderr, "Verifier output: %s\n", obj_log_buf); -	} - -cleanup: -	user_ringbuf_fail__destroy(skel); -} -  void test_user_ringbuf(void)  {  	int i; @@ -747,10 +692,5 @@ void test_user_ringbuf(void)  		success_tests[i].test_callback();  	} -	for (i = 0; i < ARRAY_SIZE(failure_tests); i++) { -		if (!test__start_subtest(failure_tests[i].prog_name)) -			continue; - -		verify_fail(failure_tests[i].prog_name, failure_tests[i].expected_err_msg); -	} +	RUN_TESTS(user_ringbuf_fail);  } diff --git a/tools/testing/selftests/bpf/prog_tests/verif_stats.c b/tools/testing/selftests/bpf/prog_tests/verif_stats.c index a47e7c0e1ffd..af4b95f57ac1 100644 --- a/tools/testing/selftests/bpf/prog_tests/verif_stats.c +++ b/tools/testing/selftests/bpf/prog_tests/verif_stats.c @@ -16,8 +16,9 @@ void test_verif_stats(void)  	if (!ASSERT_OK_PTR(skel, "trace_vprintk__open_and_load"))  		goto cleanup; -	err = bpf_obj_get_info_by_fd(skel->progs.sys_enter.prog_fd, &info, &len); -	if (!ASSERT_OK(err, "bpf_obj_get_info_by_fd")) +	err = bpf_prog_get_info_by_fd(skel->progs.sys_enter.prog_fd, +				      &info, &len); +	if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd"))  		goto cleanup;  	if (!ASSERT_GT(info.verified_insns, 0, "verified_insns")) diff --git a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c index 579d6ee83ce0..dd7f2bc70048 100644 --- a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c +++ b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c @@ -61,6 +61,9 @@ static bool kfunc_not_supported;  static int libbpf_print_cb(enum libbpf_print_level level, const char *fmt,  			   va_list args)  { +	if (level == LIBBPF_WARN) +		vprintf(fmt, args); +  	if (strcmp(fmt, "libbpf: extern (func ksym) '%s': not found in kernel or module BTFs\n"))  		return 0; diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c b/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c index 39973ea1ce43..f09505f8b038 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c @@ -76,10 +76,15 @@ static void test_xdp_adjust_tail_grow2(void)  {  	const char *file = "./test_xdp_adjust_tail_grow.bpf.o";  	char buf[4096]; /* avoid segfault: large buf to hold grow results */ -	int tailroom = 320; /* SKB_DATA_ALIGN(sizeof(struct skb_shared_info))*/;  	struct bpf_object *obj;  	int err, cnt, i;  	int max_grow, prog_fd; +	/* SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) */ +#if defined(__s390x__) +	int tailroom = 512; +#else +	int tailroom = 320; +#endif  	LIBBPF_OPTS(bpf_test_run_opts, tattr,  		.repeat		= 1, diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_attach.c b/tools/testing/selftests/bpf/prog_tests/xdp_attach.c index 062fbc8c8e5e..d4cd9f873c14 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_attach.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_attach.c @@ -18,7 +18,7 @@ void serial_test_xdp_attach(void)  	err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj1, &fd1);  	if (CHECK_FAIL(err))  		return; -	err = bpf_obj_get_info_by_fd(fd1, &info, &len); +	err = bpf_prog_get_info_by_fd(fd1, &info, &len);  	if (CHECK_FAIL(err))  		goto out_1;  	id1 = info.id; @@ -28,7 +28,7 @@ void serial_test_xdp_attach(void)  		goto out_1;  	memset(&info, 0, sizeof(info)); -	err = bpf_obj_get_info_by_fd(fd2, &info, &len); +	err = bpf_prog_get_info_by_fd(fd2, &info, &len);  	if (CHECK_FAIL(err))  		goto out_2;  	id2 = info.id; diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_cpumap_attach.c b/tools/testing/selftests/bpf/prog_tests/xdp_cpumap_attach.c index f775a1613833..481626a875d1 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_cpumap_attach.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_cpumap_attach.c @@ -33,8 +33,8 @@ static void test_xdp_with_cpumap_helpers(void)  	prog_fd = bpf_program__fd(skel->progs.xdp_dummy_cm);  	map_fd = bpf_map__fd(skel->maps.cpu_map); -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &len); -	if (!ASSERT_OK(err, "bpf_obj_get_info_by_fd")) +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &len); +	if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd"))  		goto out_close;  	val.bpf_prog.fd = prog_fd; @@ -85,8 +85,8 @@ static void test_xdp_with_cpumap_frags_helpers(void)  	frags_prog_fd = bpf_program__fd(skel->progs.xdp_dummy_cm_frags);  	map_fd = bpf_map__fd(skel->maps.cpu_map); -	err = bpf_obj_get_info_by_fd(frags_prog_fd, &info, &len); -	if (!ASSERT_OK(err, "bpf_obj_get_info_by_fd")) +	err = bpf_prog_get_info_by_fd(frags_prog_fd, &info, &len); +	if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd"))  		goto out_close;  	val.bpf_prog.fd = frags_prog_fd; diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_devmap_attach.c b/tools/testing/selftests/bpf/prog_tests/xdp_devmap_attach.c index ead40016c324..ce6812558287 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_devmap_attach.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_devmap_attach.c @@ -35,8 +35,8 @@ static void test_xdp_with_devmap_helpers(void)  	dm_fd = bpf_program__fd(skel->progs.xdp_dummy_dm);  	map_fd = bpf_map__fd(skel->maps.dm_ports); -	err = bpf_obj_get_info_by_fd(dm_fd, &info, &len); -	if (!ASSERT_OK(err, "bpf_obj_get_info_by_fd")) +	err = bpf_prog_get_info_by_fd(dm_fd, &info, &len); +	if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd"))  		goto out_close;  	val.bpf_prog.fd = dm_fd; @@ -98,8 +98,8 @@ static void test_xdp_with_devmap_frags_helpers(void)  	dm_fd_frags = bpf_program__fd(skel->progs.xdp_dummy_dm_frags);  	map_fd = bpf_map__fd(skel->maps.dm_ports); -	err = bpf_obj_get_info_by_fd(dm_fd_frags, &info, &len); -	if (!ASSERT_OK(err, "bpf_obj_get_info_by_fd")) +	err = bpf_prog_get_info_by_fd(dm_fd_frags, &info, &len); +	if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd"))  		goto out_close;  	val.bpf_prog.fd = dm_fd_frags; diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c b/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c index a50971c6cf4a..7271a18ab3e2 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c @@ -4,10 +4,12 @@  #include <net/if.h>  #include <linux/if_ether.h>  #include <linux/if_packet.h> +#include <linux/if_link.h>  #include <linux/ipv6.h>  #include <linux/in6.h>  #include <linux/udp.h>  #include <bpf/bpf_endian.h> +#include <uapi/linux/netdev.h>  #include "test_xdp_do_redirect.skel.h"  #define SYS(fmt, ...)						\ @@ -63,9 +65,14 @@ static int attach_tc_prog(struct bpf_tc_hook *hook, int fd)  }  /* The maximum permissible size is: PAGE_SIZE - sizeof(struct xdp_page_head) - - * sizeof(struct skb_shared_info) - XDP_PACKET_HEADROOM = 3368 bytes + * SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) - XDP_PACKET_HEADROOM = + * 3408 bytes for 64-byte cacheline and 3216 for 256-byte one.   */ -#define MAX_PKT_SIZE 3368 +#if defined(__s390x__) +#define MAX_PKT_SIZE 3216 +#else +#define MAX_PKT_SIZE 3408 +#endif  static void test_max_pkt_size(int fd)  {  	char data[MAX_PKT_SIZE + 1] = {}; @@ -92,7 +99,7 @@ void test_xdp_do_redirect(void)  	struct test_xdp_do_redirect *skel = NULL;  	struct nstoken *nstoken = NULL;  	struct bpf_link *link; - +	LIBBPF_OPTS(bpf_xdp_query_opts, query_opts);  	struct xdp_md ctx_in = { .data = sizeof(__u32),  				 .data_end = sizeof(data) };  	DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts, @@ -153,6 +160,29 @@ void test_xdp_do_redirect(void)  	    !ASSERT_NEQ(ifindex_dst, 0, "ifindex_dst"))  		goto out; +	/* Check xdp features supported by veth driver */ +	err = bpf_xdp_query(ifindex_src, XDP_FLAGS_DRV_MODE, &query_opts); +	if (!ASSERT_OK(err, "veth_src bpf_xdp_query")) +		goto out; + +	if (!ASSERT_EQ(query_opts.feature_flags, +		       NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | +		       NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG | +		       NETDEV_XDP_ACT_NDO_XMIT_SG, +		       "veth_src query_opts.feature_flags")) +		goto out; + +	err = bpf_xdp_query(ifindex_dst, XDP_FLAGS_DRV_MODE, &query_opts); +	if (!ASSERT_OK(err, "veth_dst bpf_xdp_query")) +		goto out; + +	if (!ASSERT_EQ(query_opts.feature_flags, +		       NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | +		       NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG | +		       NETDEV_XDP_ACT_NDO_XMIT_SG, +		       "veth_dst query_opts.feature_flags")) +		goto out; +  	memcpy(skel->rodata->expect_dst, &pkt_udp.eth.h_dest, ETH_ALEN);  	skel->rodata->ifindex_out = ifindex_src; /* redirect back to the same iface */  	skel->rodata->ifindex_in = ifindex_src; diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_info.c b/tools/testing/selftests/bpf/prog_tests/xdp_info.c index cd3aa340e65e..1dbddcab87a8 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_info.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_info.c @@ -8,6 +8,7 @@ void serial_test_xdp_info(void)  {  	__u32 len = sizeof(struct bpf_prog_info), duration = 0, prog_id;  	const char *file = "./xdp_dummy.bpf.o"; +	LIBBPF_OPTS(bpf_xdp_query_opts, opts);  	struct bpf_prog_info info = {};  	struct bpf_object *obj;  	int err, prog_fd; @@ -33,7 +34,7 @@ void serial_test_xdp_info(void)  	if (CHECK_FAIL(err))  		return; -	err = bpf_obj_get_info_by_fd(prog_fd, &info, &len); +	err = bpf_prog_get_info_by_fd(prog_fd, &info, &len);  	if (CHECK(err, "get_prog_info", "errno=%d\n", errno))  		goto out_close; @@ -61,6 +62,13 @@ void serial_test_xdp_info(void)  	if (CHECK(prog_id, "prog_id_drv", "unexpected prog_id=%u\n", prog_id))  		goto out; +	/* Check xdp features supported by lo device */ +	opts.feature_flags = ~0; +	err = bpf_xdp_query(IFINDEX_LO, XDP_FLAGS_DRV_MODE, &opts); +	if (!ASSERT_OK(err, "bpf_xdp_query")) +		goto out; + +	ASSERT_EQ(opts.feature_flags, 0, "opts.feature_flags");  out:  	bpf_xdp_detach(IFINDEX_LO, 0, NULL);  out_close: diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_link.c b/tools/testing/selftests/bpf/prog_tests/xdp_link.c index 3e9d5c5521f0..e7e9f3c22edf 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_link.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_link.c @@ -29,13 +29,13 @@ void serial_test_xdp_link(void)  	prog_fd2 = bpf_program__fd(skel2->progs.xdp_handler);  	memset(&prog_info, 0, sizeof(prog_info)); -	err = bpf_obj_get_info_by_fd(prog_fd1, &prog_info, &prog_info_len); +	err = bpf_prog_get_info_by_fd(prog_fd1, &prog_info, &prog_info_len);  	if (!ASSERT_OK(err, "fd_info1"))  		goto cleanup;  	id1 = prog_info.id;  	memset(&prog_info, 0, sizeof(prog_info)); -	err = bpf_obj_get_info_by_fd(prog_fd2, &prog_info, &prog_info_len); +	err = bpf_prog_get_info_by_fd(prog_fd2, &prog_info, &prog_info_len);  	if (!ASSERT_OK(err, "fd_info2"))  		goto cleanup;  	id2 = prog_info.id; @@ -119,7 +119,8 @@ void serial_test_xdp_link(void)  		goto cleanup;  	memset(&link_info, 0, sizeof(link_info)); -	err = bpf_obj_get_info_by_fd(bpf_link__fd(link), &link_info, &link_info_len); +	err = bpf_link_get_info_by_fd(bpf_link__fd(link), +				      &link_info, &link_info_len);  	if (!ASSERT_OK(err, "link_info"))  		goto cleanup; @@ -137,7 +138,8 @@ void serial_test_xdp_link(void)  		goto cleanup;  	memset(&link_info, 0, sizeof(link_info)); -	err = bpf_obj_get_info_by_fd(bpf_link__fd(link), &link_info, &link_info_len); +	err = bpf_link_get_info_by_fd(bpf_link__fd(link), +				      &link_info, &link_info_len);  	ASSERT_OK(err, "link_info");  	ASSERT_EQ(link_info.prog_id, id1, "link_prog_id"); diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c new file mode 100644 index 000000000000..aa4beae99f4f --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <test_progs.h> +#include <network_helpers.h> +#include "xdp_metadata.skel.h" +#include "xdp_metadata2.skel.h" +#include "xdp_metadata.h" +#include "xsk.h" + +#include <bpf/btf.h> +#include <linux/errqueue.h> +#include <linux/if_link.h> +#include <linux/net_tstamp.h> +#include <linux/udp.h> +#include <sys/mman.h> +#include <net/if.h> +#include <poll.h> + +#define TX_NAME "veTX" +#define RX_NAME "veRX" + +#define UDP_PAYLOAD_BYTES 4 + +#define AF_XDP_SOURCE_PORT 1234 +#define AF_XDP_CONSUMER_PORT 8080 + +#define UMEM_NUM 16 +#define UMEM_FRAME_SIZE XSK_UMEM__DEFAULT_FRAME_SIZE +#define UMEM_SIZE (UMEM_FRAME_SIZE * UMEM_NUM) +#define XDP_FLAGS XDP_FLAGS_DRV_MODE +#define QUEUE_ID 0 + +#define TX_ADDR "10.0.0.1" +#define RX_ADDR "10.0.0.2" +#define PREFIX_LEN "8" +#define FAMILY AF_INET + +#define SYS(cmd) ({ \ +	if (!ASSERT_OK(system(cmd), (cmd))) \ +		goto out; \ +}) + +struct xsk { +	void *umem_area; +	struct xsk_umem *umem; +	struct xsk_ring_prod fill; +	struct xsk_ring_cons comp; +	struct xsk_ring_prod tx; +	struct xsk_ring_cons rx; +	struct xsk_socket *socket; +}; + +static int open_xsk(int ifindex, struct xsk *xsk) +{ +	int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; +	const struct xsk_socket_config socket_config = { +		.rx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, +		.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, +		.bind_flags = XDP_COPY, +	}; +	const struct xsk_umem_config umem_config = { +		.fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, +		.comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS, +		.frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE, +		.flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG, +	}; +	__u32 idx; +	u64 addr; +	int ret; +	int i; + +	xsk->umem_area = mmap(NULL, UMEM_SIZE, PROT_READ | PROT_WRITE, mmap_flags, -1, 0); +	if (!ASSERT_NEQ(xsk->umem_area, MAP_FAILED, "mmap")) +		return -1; + +	ret = xsk_umem__create(&xsk->umem, +			       xsk->umem_area, UMEM_SIZE, +			       &xsk->fill, +			       &xsk->comp, +			       &umem_config); +	if (!ASSERT_OK(ret, "xsk_umem__create")) +		return ret; + +	ret = xsk_socket__create(&xsk->socket, ifindex, QUEUE_ID, +				 xsk->umem, +				 &xsk->rx, +				 &xsk->tx, +				 &socket_config); +	if (!ASSERT_OK(ret, "xsk_socket__create")) +		return ret; + +	/* First half of umem is for TX. This way address matches 1-to-1 +	 * to the completion queue index. +	 */ + +	for (i = 0; i < UMEM_NUM / 2; i++) { +		addr = i * UMEM_FRAME_SIZE; +		printf("%p: tx_desc[%d] -> %lx\n", xsk, i, addr); +	} + +	/* Second half of umem is for RX. */ + +	ret = xsk_ring_prod__reserve(&xsk->fill, UMEM_NUM / 2, &idx); +	if (!ASSERT_EQ(UMEM_NUM / 2, ret, "xsk_ring_prod__reserve")) +		return ret; +	if (!ASSERT_EQ(idx, 0, "fill idx != 0")) +		return -1; + +	for (i = 0; i < UMEM_NUM / 2; i++) { +		addr = (UMEM_NUM / 2 + i) * UMEM_FRAME_SIZE; +		printf("%p: rx_desc[%d] -> %lx\n", xsk, i, addr); +		*xsk_ring_prod__fill_addr(&xsk->fill, i) = addr; +	} +	xsk_ring_prod__submit(&xsk->fill, ret); + +	return 0; +} + +static void close_xsk(struct xsk *xsk) +{ +	if (xsk->umem) +		xsk_umem__delete(xsk->umem); +	if (xsk->socket) +		xsk_socket__delete(xsk->socket); +	munmap(xsk->umem_area, UMEM_SIZE); +} + +static void ip_csum(struct iphdr *iph) +{ +	__u32 sum = 0; +	__u16 *p; +	int i; + +	iph->check = 0; +	p = (void *)iph; +	for (i = 0; i < sizeof(*iph) / sizeof(*p); i++) +		sum += p[i]; + +	while (sum >> 16) +		sum = (sum & 0xffff) + (sum >> 16); + +	iph->check = ~sum; +} + +static int generate_packet(struct xsk *xsk, __u16 dst_port) +{ +	struct xdp_desc *tx_desc; +	struct udphdr *udph; +	struct ethhdr *eth; +	struct iphdr *iph; +	void *data; +	__u32 idx; +	int ret; + +	ret = xsk_ring_prod__reserve(&xsk->tx, 1, &idx); +	if (!ASSERT_EQ(ret, 1, "xsk_ring_prod__reserve")) +		return -1; + +	tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx); +	tx_desc->addr = idx % (UMEM_NUM / 2) * UMEM_FRAME_SIZE; +	printf("%p: tx_desc[%u]->addr=%llx\n", xsk, idx, tx_desc->addr); +	data = xsk_umem__get_data(xsk->umem_area, tx_desc->addr); + +	eth = data; +	iph = (void *)(eth + 1); +	udph = (void *)(iph + 1); + +	memcpy(eth->h_dest, "\x00\x00\x00\x00\x00\x02", ETH_ALEN); +	memcpy(eth->h_source, "\x00\x00\x00\x00\x00\x01", ETH_ALEN); +	eth->h_proto = htons(ETH_P_IP); + +	iph->version = 0x4; +	iph->ihl = 0x5; +	iph->tos = 0x9; +	iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + UDP_PAYLOAD_BYTES); +	iph->id = 0; +	iph->frag_off = 0; +	iph->ttl = 0; +	iph->protocol = IPPROTO_UDP; +	ASSERT_EQ(inet_pton(FAMILY, TX_ADDR, &iph->saddr), 1, "inet_pton(TX_ADDR)"); +	ASSERT_EQ(inet_pton(FAMILY, RX_ADDR, &iph->daddr), 1, "inet_pton(RX_ADDR)"); +	ip_csum(iph); + +	udph->source = htons(AF_XDP_SOURCE_PORT); +	udph->dest = htons(dst_port); +	udph->len = htons(sizeof(*udph) + UDP_PAYLOAD_BYTES); +	udph->check = 0; + +	memset(udph + 1, 0xAA, UDP_PAYLOAD_BYTES); + +	tx_desc->len = sizeof(*eth) + sizeof(*iph) + sizeof(*udph) + UDP_PAYLOAD_BYTES; +	xsk_ring_prod__submit(&xsk->tx, 1); + +	ret = sendto(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, 0); +	if (!ASSERT_GE(ret, 0, "sendto")) +		return ret; + +	return 0; +} + +static void complete_tx(struct xsk *xsk) +{ +	__u32 idx; +	__u64 addr; + +	if (ASSERT_EQ(xsk_ring_cons__peek(&xsk->comp, 1, &idx), 1, "xsk_ring_cons__peek")) { +		addr = *xsk_ring_cons__comp_addr(&xsk->comp, idx); + +		printf("%p: complete tx idx=%u addr=%llx\n", xsk, idx, addr); +		xsk_ring_cons__release(&xsk->comp, 1); +	} +} + +static void refill_rx(struct xsk *xsk, __u64 addr) +{ +	__u32 idx; + +	if (ASSERT_EQ(xsk_ring_prod__reserve(&xsk->fill, 1, &idx), 1, "xsk_ring_prod__reserve")) { +		printf("%p: complete idx=%u addr=%llx\n", xsk, idx, addr); +		*xsk_ring_prod__fill_addr(&xsk->fill, idx) = addr; +		xsk_ring_prod__submit(&xsk->fill, 1); +	} +} + +static int verify_xsk_metadata(struct xsk *xsk) +{ +	const struct xdp_desc *rx_desc; +	struct pollfd fds = {}; +	struct xdp_meta *meta; +	struct ethhdr *eth; +	struct iphdr *iph; +	__u64 comp_addr; +	void *data; +	__u64 addr; +	__u32 idx; +	int ret; + +	ret = recvfrom(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, NULL); +	if (!ASSERT_EQ(ret, 0, "recvfrom")) +		return -1; + +	fds.fd = xsk_socket__fd(xsk->socket); +	fds.events = POLLIN; + +	ret = poll(&fds, 1, 1000); +	if (!ASSERT_GT(ret, 0, "poll")) +		return -1; + +	ret = xsk_ring_cons__peek(&xsk->rx, 1, &idx); +	if (!ASSERT_EQ(ret, 1, "xsk_ring_cons__peek")) +		return -2; + +	rx_desc = xsk_ring_cons__rx_desc(&xsk->rx, idx); +	comp_addr = xsk_umem__extract_addr(rx_desc->addr); +	addr = xsk_umem__add_offset_to_addr(rx_desc->addr); +	printf("%p: rx_desc[%u]->addr=%llx addr=%llx comp_addr=%llx\n", +	       xsk, idx, rx_desc->addr, addr, comp_addr); +	data = xsk_umem__get_data(xsk->umem_area, addr); + +	/* Make sure we got the packet offset correctly. */ + +	eth = data; +	ASSERT_EQ(eth->h_proto, htons(ETH_P_IP), "eth->h_proto"); +	iph = (void *)(eth + 1); +	ASSERT_EQ((int)iph->version, 4, "iph->version"); + +	/* custom metadata */ + +	meta = data - sizeof(struct xdp_meta); + +	if (!ASSERT_NEQ(meta->rx_timestamp, 0, "rx_timestamp")) +		return -1; + +	if (!ASSERT_NEQ(meta->rx_hash, 0, "rx_hash")) +		return -1; + +	xsk_ring_cons__release(&xsk->rx, 1); +	refill_rx(xsk, comp_addr); + +	return 0; +} + +void test_xdp_metadata(void) +{ +	struct xdp_metadata2 *bpf_obj2 = NULL; +	struct xdp_metadata *bpf_obj = NULL; +	struct bpf_program *new_prog, *prog; +	struct nstoken *tok = NULL; +	__u32 queue_id = QUEUE_ID; +	struct bpf_map *prog_arr; +	struct xsk tx_xsk = {}; +	struct xsk rx_xsk = {}; +	__u32 val, key = 0; +	int retries = 10; +	int rx_ifindex; +	int tx_ifindex; +	int sock_fd; +	int ret; + +	/* Setup new networking namespace, with a veth pair. */ + +	SYS("ip netns add xdp_metadata"); +	tok = open_netns("xdp_metadata"); +	SYS("ip link add numtxqueues 1 numrxqueues 1 " TX_NAME +	    " type veth peer " RX_NAME " numtxqueues 1 numrxqueues 1"); +	SYS("ip link set dev " TX_NAME " address 00:00:00:00:00:01"); +	SYS("ip link set dev " RX_NAME " address 00:00:00:00:00:02"); +	SYS("ip link set dev " TX_NAME " up"); +	SYS("ip link set dev " RX_NAME " up"); +	SYS("ip addr add " TX_ADDR "/" PREFIX_LEN " dev " TX_NAME); +	SYS("ip addr add " RX_ADDR "/" PREFIX_LEN " dev " RX_NAME); + +	rx_ifindex = if_nametoindex(RX_NAME); +	tx_ifindex = if_nametoindex(TX_NAME); + +	/* Setup separate AF_XDP for TX and RX interfaces. */ + +	ret = open_xsk(tx_ifindex, &tx_xsk); +	if (!ASSERT_OK(ret, "open_xsk(TX_NAME)")) +		goto out; + +	ret = open_xsk(rx_ifindex, &rx_xsk); +	if (!ASSERT_OK(ret, "open_xsk(RX_NAME)")) +		goto out; + +	bpf_obj = xdp_metadata__open(); +	if (!ASSERT_OK_PTR(bpf_obj, "open skeleton")) +		goto out; + +	prog = bpf_object__find_program_by_name(bpf_obj->obj, "rx"); +	bpf_program__set_ifindex(prog, rx_ifindex); +	bpf_program__set_flags(prog, BPF_F_XDP_DEV_BOUND_ONLY); + +	if (!ASSERT_OK(xdp_metadata__load(bpf_obj), "load skeleton")) +		goto out; + +	/* Make sure we can't add dev-bound programs to prog maps. */ +	prog_arr = bpf_object__find_map_by_name(bpf_obj->obj, "prog_arr"); +	if (!ASSERT_OK_PTR(prog_arr, "no prog_arr map")) +		goto out; + +	val = bpf_program__fd(prog); +	if (!ASSERT_ERR(bpf_map__update_elem(prog_arr, &key, sizeof(key), +					     &val, sizeof(val), BPF_ANY), +			"update prog_arr")) +		goto out; + +	/* Attach BPF program to RX interface. */ + +	ret = bpf_xdp_attach(rx_ifindex, +			     bpf_program__fd(bpf_obj->progs.rx), +			     XDP_FLAGS, NULL); +	if (!ASSERT_GE(ret, 0, "bpf_xdp_attach")) +		goto out; + +	sock_fd = xsk_socket__fd(rx_xsk.socket); +	ret = bpf_map_update_elem(bpf_map__fd(bpf_obj->maps.xsk), &queue_id, &sock_fd, 0); +	if (!ASSERT_GE(ret, 0, "bpf_map_update_elem")) +		goto out; + +	/* Send packet destined to RX AF_XDP socket. */ +	if (!ASSERT_GE(generate_packet(&tx_xsk, AF_XDP_CONSUMER_PORT), 0, +		       "generate AF_XDP_CONSUMER_PORT")) +		goto out; + +	/* Verify AF_XDP RX packet has proper metadata. */ +	if (!ASSERT_GE(verify_xsk_metadata(&rx_xsk), 0, +		       "verify_xsk_metadata")) +		goto out; + +	complete_tx(&tx_xsk); + +	/* Make sure freplace correctly picks up original bound device +	 * and doesn't crash. +	 */ + +	bpf_obj2 = xdp_metadata2__open(); +	if (!ASSERT_OK_PTR(bpf_obj2, "open skeleton")) +		goto out; + +	new_prog = bpf_object__find_program_by_name(bpf_obj2->obj, "freplace_rx"); +	bpf_program__set_attach_target(new_prog, bpf_program__fd(prog), "rx"); + +	if (!ASSERT_OK(xdp_metadata2__load(bpf_obj2), "load freplace skeleton")) +		goto out; + +	if (!ASSERT_OK(xdp_metadata2__attach(bpf_obj2), "attach freplace")) +		goto out; + +	/* Send packet to trigger . */ +	if (!ASSERT_GE(generate_packet(&tx_xsk, AF_XDP_CONSUMER_PORT), 0, +		       "generate freplace packet")) +		goto out; + +	while (!retries--) { +		if (bpf_obj2->bss->called) +			break; +		usleep(10); +	} +	ASSERT_GT(bpf_obj2->bss->called, 0, "not called"); + +out: +	close_xsk(&rx_xsk); +	close_xsk(&tx_xsk); +	xdp_metadata2__destroy(bpf_obj2); +	xdp_metadata__destroy(bpf_obj); +	if (tok) +		close_netns(tok); +	system("ip netns del xdp_metadata"); +} |