diff --git a/tools/testing/selftests/bpf/prog_tests/check_mtu.c b/tools/testing/selftests/bpf/prog_tests/check_mtu.c
index f73e6e36b74d..b5ab3ef7e9d3 100644
--- a/tools/testing/selftests/bpf/prog_tests/check_mtu.c
+++ b/tools/testing/selftests/bpf/prog_tests/check_mtu.c
@@ -83,24 +83,22 @@ static void test_check_mtu_run_xdp(struct test_check_mtu *skel,
 	int retval_expect = XDP_PASS;
 	__u32 mtu_result = 0;
 	char buf[256] = {};
-	int err;
-	struct bpf_prog_test_run_attr tattr = {
-		.repeat = 1,
-		.data_in = &pkt_v4,
+	int err, prog_fd = bpf_program__fd(prog);
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
+		.repeat = 1, .data_in = &pkt_v4,
 		.data_size_in = sizeof(pkt_v4),
 		.data_out = buf,
 		.data_size_out = sizeof(buf),
-		.prog_fd = bpf_program__fd(prog),
-	};
+	);

-	err = bpf_prog_test_run_xattr(&tattr);
-	CHECK_ATTR(err != 0, "bpf_prog_test_run",
-		   "prog_name:%s (err %d errno %d retval %d)\n",
-		   prog_name, err, errno, tattr.retval);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err != 0, "bpf_prog_test_run",
+		   "prog_name:%s (err %d errno %d retval %d)\n", prog_name, err,
+		   errno, topts.retval);

-	CHECK(tattr.retval != retval_expect, "retval",
-	      "progname:%s unexpected retval=%d expected=%d\n",
-	      prog_name, tattr.retval, retval_expect);
+	CHECK(topts.retval != retval_expect, "retval",
+	      "progname:%s unexpected retval=%d expected=%d\n", prog_name,
+	      topts.retval, retval_expect);

 	/* Extract MTU that BPF-prog got */
 	mtu_result = skel->bss->global_bpf_mtu_xdp;
@@ -143,24 +141,23 @@ static void test_check_mtu_run_tc(struct test_check_mtu *skel,
 	int retval_expect = BPF_OK;
 	__u32 mtu_result = 0;
 	char buf[256] = {};
-	int err;
-	struct bpf_prog_test_run_attr tattr = {
-		.repeat = 1,
+	int err, prog_fd = bpf_program__fd(prog);
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
 		.data_in = &pkt_v4,
 		.data_size_in = sizeof(pkt_v4),
 		.data_out = buf,
 		.data_size_out = sizeof(buf),
-		.prog_fd = bpf_program__fd(prog),
-	};
+		.repeat = 1,
+	);

-	err = bpf_prog_test_run_xattr(&tattr);
-	CHECK_ATTR(err != 0, "bpf_prog_test_run",
-		   "prog_name:%s (err %d errno %d retval %d)\n",
-		   prog_name, err, errno, tattr.retval);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err != 0, "bpf_prog_test_run",
+		   "prog_name:%s (err %d errno %d retval %d)\n", prog_name, err,
+		   errno, topts.retval);

-	CHECK(tattr.retval != retval_expect, "retval",
-	      "progname:%s unexpected retval=%d expected=%d\n",
-	      prog_name, tattr.retval, retval_expect);
+	CHECK(topts.retval != retval_expect, "retval",
+	      "progname:%s unexpected retval=%d expected=%d\n", prog_name,
+	      topts.retval, retval_expect);

 	/* Extract MTU that BPF-prog got */
 	mtu_result = skel->bss->global_bpf_mtu_tc;
diff --git a/tools/testing/selftests/bpf/prog_tests/cls_redirect.c b/tools/testing/selftests/bpf/prog_tests/cls_redirect.c
index e075d03ab630..fec0d3dd00ce 100644
--- a/tools/testing/selftests/bpf/prog_tests/cls_redirect.c
+++ b/tools/testing/selftests/bpf/prog_tests/cls_redirect.c
@@ -161,9 +161,9 @@ static socklen_t prepare_addr(struct sockaddr_storage *addr, int family)
 	}
 }

-static bool was_decapsulated(struct bpf_prog_test_run_attr *tattr)
+static bool was_decapsulated(struct bpf_test_run_opts *topts)
 {
-	return tattr->data_size_out < tattr->data_size_in;
+	return topts->data_size_out < topts->data_size_in;
 }

 enum type {
@@ -367,12 +367,12 @@ static void close_fds(int *fds, int n)

 static void test_cls_redirect_common(struct bpf_program *prog)
 {
-	struct bpf_prog_test_run_attr tattr = {};
+	LIBBPF_OPTS(bpf_test_run_opts, topts);
 	int families[] = { AF_INET, AF_INET6 };
 	struct sockaddr_storage ss;
 	struct sockaddr *addr;
 	socklen_t slen;
-	int i, j, err;
+	int i, j, err, prog_fd;
 	int servers[__NR_KIND][ARRAY_SIZE(families)] = {};
 	int conns[__NR_KIND][ARRAY_SIZE(families)] = {};
 	struct tuple tuples[__NR_KIND][ARRAY_SIZE(families)];
@@ -394,7 +394,7 @@ static void test_cls_redirect_common(struct bpf_program *prog)
 			goto cleanup;
 	}

-	tattr.prog_fd = bpf_program__fd(prog);
+	prog_fd = bpf_program__fd(prog);
 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
 		struct test_cfg *test = &tests[i];

@@ -407,31 +407,31 @@ static void test_cls_redirect_common(struct bpf_program *prog)
 			if (!test__start_subtest(tmp))
 				continue;

-			tattr.data_out = tmp;
-			tattr.data_size_out = sizeof(tmp);
+			topts.data_out = tmp;
+			topts.data_size_out = sizeof(tmp);

-			tattr.data_in = input;
-			tattr.data_size_in = build_input(test, input, tuple);
-			if (CHECK_FAIL(!tattr.data_size_in))
+			topts.data_in = input;
+			topts.data_size_in = build_input(test, input, tuple);
+			if (CHECK_FAIL(!topts.data_size_in))
 				continue;

-			err = bpf_prog_test_run_xattr(&tattr);
+			err = bpf_prog_test_run_opts(prog_fd, &topts);
 			if (CHECK_FAIL(err))
 				continue;

-			if (tattr.retval != TC_ACT_REDIRECT) {
+			if (topts.retval != TC_ACT_REDIRECT) {
 				PRINT_FAIL("expected TC_ACT_REDIRECT, got %d\n",
-					   tattr.retval);
+					   topts.retval);
 				continue;
 			}

 			switch (test->result) {
 			case ACCEPT:
-				if (CHECK_FAIL(!was_decapsulated(&tattr)))
+				if (CHECK_FAIL(!was_decapsulated(&topts)))
 					continue;
 				break;
 			case FORWARD:
-				if (CHECK_FAIL(was_decapsulated(&tattr)))
+				if (CHECK_FAIL(was_decapsulated(&topts)))
 					continue;
 				break;
 			default:
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 cbaa44ffb8c6..81b2f670526a 100644
--- a/tools/testing/selftests/bpf/prog_tests/dummy_st_ops.c
+++ b/tools/testing/selftests/bpf/prog_tests/dummy_st_ops.c
@@ -26,10 +26,10 @@ static void test_dummy_st_ops_attach(void)
 static void test_dummy_init_ret_value(void)
 {
 	__u64 args[1] = {0};
-	struct bpf_prog_test_run_attr attr = {
-		.ctx_size_in = sizeof(args),
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
 		.ctx_in = args,
-	};
+		.ctx_size_in = sizeof(args),
+	);
 	struct dummy_st_ops *skel;
 	int fd, err;

@@ -38,10 +38,9 @@ static void test_dummy_init_ret_value(void)
 		return;

 	fd = bpf_program__fd(skel->progs.test_1);
-	attr.prog_fd = fd;
-	err = bpf_prog_test_run_xattr(&attr);
+	err = bpf_prog_test_run_opts(fd, &topts);
 	ASSERT_OK(err, "test_run");
-	ASSERT_EQ(attr.retval, 0xf2f3f4f5, "test_ret");
+	ASSERT_EQ(topts.retval, 0xf2f3f4f5, "test_ret");

 	dummy_st_ops__destroy(skel);
 }
@@ -53,10 +52,10 @@ static void test_dummy_init_ptr_arg(void)
 		.val = exp_retval,
 	};
 	__u64 args[1] = {(unsigned long)&in_state};
-	struct bpf_prog_test_run_attr attr = {
-		.ctx_size_in = sizeof(args),
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
 		.ctx_in = args,
-	};
+		.ctx_size_in = sizeof(args),
+	);
 	struct dummy_st_ops *skel;
 	int fd, err;

@@ -65,11 +64,10 @@ static void test_dummy_init_ptr_arg(void)
 		return;

 	fd = bpf_program__fd(skel->progs.test_1);
-	attr.prog_fd = fd;
-	err = bpf_prog_test_run_xattr(&attr);
+	err = bpf_prog_test_run_opts(fd, &topts);
 	ASSERT_OK(err, "test_run");
 	ASSERT_EQ(in_state.val, 0x5a, "test_ptr_ret");
-	ASSERT_EQ(attr.retval, exp_retval, "test_ret");
+	ASSERT_EQ(topts.retval, exp_retval, "test_ret");

 	dummy_st_ops__destroy(skel);
 }
@@ -77,10 +75,10 @@ static void test_dummy_init_ptr_arg(void)
 static void test_dummy_multiple_args(void)
 {
 	__u64 args[5] = {0, -100, 0x8a5f, 'c', 0x1234567887654321ULL};
-	struct bpf_prog_test_run_attr attr = {
-		.ctx_size_in = sizeof(args),
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
 		.ctx_in = args,
-	};
+		.ctx_size_in = sizeof(args),
+	);
 	struct dummy_st_ops *skel;
 	int fd, err;
 	size_t i;
@@ -91,8 +89,7 @@ static void test_dummy_multiple_args(void)
 		return;

 	fd = bpf_program__fd(skel->progs.test_2);
-	attr.prog_fd = fd;
-	err = bpf_prog_test_run_xattr(&attr);
+	err = bpf_prog_test_run_opts(fd, &topts);
 	ASSERT_OK(err, "test_run");
 	for (i = 0; i < ARRAY_SIZE(args); i++) {
 		snprintf(name, sizeof(name), "arg %zu", i);
diff --git a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c
index dfafd62df50b..0bcf8e503c5f 100644
--- a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c
+++ b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c
@@ -13,30 +13,30 @@
 #endif

 #define CHECK_FLOW_KEYS(desc, got, expected)				\
-	CHECK_ATTR(memcmp(&got, &expected, sizeof(got)) != 0,		\
-	      desc,							\
-	      "nhoff=%u/%u "						\
-	      "thoff=%u/%u "						\
-	      "addr_proto=0x%x/0x%x "					\
-	      "is_frag=%u/%u "						\
-	      "is_first_frag=%u/%u "					\
-	      "is_encap=%u/%u "						\
-	      "ip_proto=0x%x/0x%x "					\
-	      "n_proto=0x%x/0x%x "					\
-	      "flow_label=0x%x/0x%x "					\
-	      "sport=%u/%u "						\
-	      "dport=%u/%u\n",						\
-	      got.nhoff, expected.nhoff,				\
-	      got.thoff, expected.thoff,				\
-	      got.addr_proto, expected.addr_proto,			\
-	      got.is_frag, expected.is_frag,				\
-	      got.is_first_frag, expected.is_first_frag,		\
-	      got.is_encap, expected.is_encap,				\
-	      got.ip_proto, expected.ip_proto,				\
-	      got.n_proto, expected.n_proto,				\
-	      got.flow_label, expected.flow_label,			\
-	      got.sport, expected.sport,				\
-	      got.dport, expected.dport)
+	CHECK_OPTS(memcmp(&got, &expected, sizeof(got)) != 0,		\
+			   desc,							\
+			   "nhoff=%u/%u "						\
+			   "thoff=%u/%u "						\
+			   "addr_proto=0x%x/0x%x "					\
+			   "is_frag=%u/%u "						\
+			   "is_first_frag=%u/%u "					\
+			   "is_encap=%u/%u "						\
+			   "ip_proto=0x%x/0x%x "					\
+			   "n_proto=0x%x/0x%x "					\
+			   "flow_label=0x%x/0x%x "					\
+			   "sport=%u/%u "						\
+			   "dport=%u/%u\n",						\
+			   got.nhoff, expected.nhoff,				\
+			   got.thoff, expected.thoff,				\
+			   got.addr_proto, expected.addr_proto,			\
+			   got.is_frag, expected.is_frag,				\
+			   got.is_first_frag, expected.is_first_frag,		\
+			   got.is_encap, expected.is_encap,				\
+			   got.ip_proto, expected.ip_proto,				\
+			   got.n_proto, expected.n_proto,				\
+			   got.flow_label, expected.flow_label,			\
+			   got.sport, expected.sport,				\
+			   got.dport, expected.dport)

 struct ipv4_pkt {
 	struct ethhdr eth;
@@ -487,7 +487,7 @@ static void run_tests_skb_less(int tap_fd, struct bpf_map *keys)
 		/* Keep in sync with 'flags' from eth_get_headlen. */
 		__u32 eth_get_headlen_flags =
 			BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG;
-		struct bpf_prog_test_run_attr tattr = {};
+		LIBBPF_OPTS(bpf_test_run_opts, topts);
 		struct bpf_flow_keys flow_keys = {};
 		__u32 key = (__u32)(tests[i].keys.sport) << 16 |
 			    tests[i].keys.dport;
@@ -503,13 +503,13 @@ static void run_tests_skb_less(int tap_fd, struct bpf_map *keys)
 		CHECK(err < 0, "tx_tap", "err %d errno %d\n", err, errno);

 		err = bpf_map_lookup_elem(keys_fd, &key, &flow_keys);
-		CHECK_ATTR(err, tests[i].name, "bpf_map_lookup_elem %d\n", err);
+		CHECK_OPTS(err, tests[i].name, "bpf_map_lookup_elem %d\n", err);

-		CHECK_ATTR(err, tests[i].name, "skb-less err %d\n", err);
+		CHECK_OPTS(err, tests[i].name, "skb-less err %d\n", err);
 		CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);

 		err = bpf_map_delete_elem(keys_fd, &key);
-		CHECK_ATTR(err, tests[i].name, "bpf_map_delete_elem %d\n", err);
+		CHECK_OPTS(err, tests[i].name, "bpf_map_delete_elem %d\n", err);
 	}
 }

@@ -573,27 +573,26 @@ void test_flow_dissector(void)

 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
 		struct bpf_flow_keys flow_keys;
-		struct bpf_prog_test_run_attr tattr = {
-			.prog_fd = prog_fd,
+		LIBBPF_OPTS(bpf_test_run_opts, topts,
 			.data_in = &tests[i].pkt,
 			.data_size_in = sizeof(tests[i].pkt),
 			.data_out = &flow_keys,
-		};
+		);
 		static struct bpf_flow_keys ctx = {};

 		if (tests[i].flags) {
-			tattr.ctx_in = &ctx;
-			tattr.ctx_size_in = sizeof(ctx);
+			topts.ctx_in = &ctx;
+			topts.ctx_size_in = sizeof(ctx);
 			ctx.flags = tests[i].flags;
 		}

-		err = bpf_prog_test_run_xattr(&tattr);
-		CHECK_ATTR(tattr.data_size_out != sizeof(flow_keys) ||
-			   err || tattr.retval != 1,
+		err = bpf_prog_test_run_opts(prog_fd, &topts);
+		CHECK_OPTS(topts.data_size_out != sizeof(flow_keys) ||
+			   err || topts.retval != 1,
 			   tests[i].name,
 			   "err %d errno %d retval %d duration %d size %u/%zu\n",
-			   err, errno, tattr.retval, tattr.duration,
-			   tattr.data_size_out, sizeof(flow_keys));
+			   err, errno, topts.retval, topts.duration,
+			   topts.data_size_out, sizeof(flow_keys));
 		CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);
 	}

diff --git a/tools/testing/selftests/bpf/prog_tests/kfree_skb.c b/tools/testing/selftests/bpf/prog_tests/kfree_skb.c
index ce10d2fc3a6c..7e50d6147e08 100644
--- a/tools/testing/selftests/bpf/prog_tests/kfree_skb.c
+++ b/tools/testing/selftests/bpf/prog_tests/kfree_skb.c
@@ -53,24 +53,24 @@ static void on_sample(void *ctx, int cpu, void *data, __u32 size)
 void serial_test_kfree_skb(void)
 {
 	struct __sk_buff skb = {};
-	struct bpf_prog_test_run_attr tattr = {
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
 		.data_in = &pkt_v6,
 		.data_size_in = sizeof(pkt_v6),
 		.ctx_in = &skb,
 		.ctx_size_in = sizeof(skb),
-	};
+	);
 	struct kfree_skb *skel = NULL;
 	struct bpf_link *link;
 	struct bpf_object *obj;
 	struct perf_buffer *pb = NULL;
-	int err;
+	int err, prog_fd;
 	bool passed = false;
 	__u32 duration = 0;
 	const int zero = 0;
 	bool test_ok[2];

 	err = bpf_prog_test_load("./test_pkt_access.o", BPF_PROG_TYPE_SCHED_CLS,
-			    &obj, &tattr.prog_fd);
+				 &obj, &prog_fd);
 	if (CHECK(err, "prog_load sched cls", "err %d errno %d\n", err, errno))
 		return;

@@ -100,11 +100,11 @@ void serial_test_kfree_skb(void)
 		goto close_prog;

 	memcpy(skb.cb, &cb, sizeof(cb));
-	err = bpf_prog_test_run_xattr(&tattr);
-	duration = tattr.duration;
-	CHECK(err || tattr.retval, "ipv6",
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	duration = topts.duration;
+	CHECK(err || topts.retval, "ipv6",
 	      "err %d errno %d retval %d duration %d\n",
-	      err, errno, tattr.retval, duration);
+	      err, errno, topts.retval, duration);

 	/* read perf buffer */
 	err = perf_buffer__poll(pb, 100);
diff --git a/tools/testing/selftests/bpf/prog_tests/prog_run_xattr.c b/tools/testing/selftests/bpf/prog_tests/prog_run_xattr.c
index 89fc98faf19e..53c75fa7acac 100644
--- a/tools/testing/selftests/bpf/prog_tests/prog_run_xattr.c
+++ b/tools/testing/selftests/bpf/prog_tests/prog_run_xattr.c
@@ -20,6 +20,9 @@ static void check_run_cnt(int prog_fd, __u64 run_cnt)
 	      "incorrect number of repetitions, want %llu have %llu\n", run_cnt, info.run_cnt);
 }

+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
 void test_prog_run_xattr(void)
 {
 	struct test_pkt_access *skel;
@@ -81,3 +84,5 @@ void test_prog_run_xattr(void)
 	if (stats_fd >= 0)
 		close(stats_fd);
 }
+
+#pragma GCC diagnostic pop
diff --git a/tools/testing/selftests/bpf/prog_tests/raw_tp_test_run.c b/tools/testing/selftests/bpf/prog_tests/raw_tp_test_run.c
index 41720a62c4fa..8ba2681c9ffa 100644
--- a/tools/testing/selftests/bpf/prog_tests/raw_tp_test_run.c
+++ b/tools/testing/selftests/bpf/prog_tests/raw_tp_test_run.c
@@ -5,89 +5,84 @@
 #include "bpf/libbpf_internal.h"
 #include "test_raw_tp_test_run.skel.h"

-static int duration;
-
 void test_raw_tp_test_run(void)
 {
-	struct bpf_prog_test_run_attr test_attr = {};
 	int comm_fd = -1, err, nr_online, i, prog_fd;
 	__u64 args[2] = {0x1234ULL, 0x5678ULL};
 	int expected_retval = 0x1234 + 0x5678;
 	struct test_raw_tp_test_run *skel;
 	char buf[] = "new_name";
 	bool *online = NULL;
-	DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts,
-			    .ctx_in = args,
-			    .ctx_size_in = sizeof(args),
-			    .flags = BPF_F_TEST_RUN_ON_CPU,
-		);
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
+		.ctx_in = args,
+		.ctx_size_in = sizeof(args),
+	);

 	err = parse_cpu_mask_file("/sys/devices/system/cpu/online", &online,
 				  &nr_online);
-	if (CHECK(err, "parse_cpu_mask_file", "err %d\n", err))
+	if (CHECK_OPTS(err, "parse_cpu_mask_file", "err %d\n", err))
 		return;

 	skel = test_raw_tp_test_run__open_and_load();
-	if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
+	if (CHECK_OPTS(!skel, "skel_open", "failed to open skeleton\n"))
 		goto cleanup;

 	err = test_raw_tp_test_run__attach(skel);
-	if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
+	if (CHECK_OPTS(err, "skel_attach", "skeleton attach failed: %d\n", err))
 		goto cleanup;

 	comm_fd = open("/proc/self/comm", O_WRONLY|O_TRUNC);
-	if (CHECK(comm_fd < 0, "open /proc/self/comm", "err %d\n", errno))
+	if (CHECK_OPTS(comm_fd < 0, "open /proc/self/comm", "err %d\n", errno))
 		goto cleanup;

 	err = write(comm_fd, buf, sizeof(buf));
-	CHECK(err < 0, "task rename", "err %d", errno);
+	CHECK_OPTS(err < 0, "task rename", "err %d", errno);

-	CHECK(skel->bss->count == 0, "check_count", "didn't increase\n");
-	CHECK(skel->data->on_cpu != 0xffffffff, "check_on_cpu", "got wrong value\n");
+	CHECK_OPTS(skel->bss->count == 0, "check_count", "didn't increase\n");
+	CHECK_OPTS(skel->data->on_cpu != 0xffffffff, "check_on_cpu",
+		   "got wrong value\n");

 	prog_fd = bpf_program__fd(skel->progs.rename);
-	test_attr.prog_fd = prog_fd;
-	test_attr.ctx_in = args;
-	test_attr.ctx_size_in = sizeof(__u64);
+	topts.ctx_in = args;
+	topts.ctx_size_in = sizeof(__u64);

-	err = bpf_prog_test_run_xattr(&test_attr);
-	CHECK(err == 0, "test_run", "should fail for too small ctx\n");
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err == 0, "test_run", "should fail for too small ctx\n");

-	test_attr.ctx_size_in = sizeof(args);
-	err = bpf_prog_test_run_xattr(&test_attr);
-	CHECK(err < 0, "test_run", "err %d\n", errno);
-	CHECK(test_attr.retval != expected_retval, "check_retval",
-	      "expect 0x%x, got 0x%x\n", expected_retval, test_attr.retval);
+	topts.ctx_size_in = sizeof(args);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err < 0, "test_run", "err %d\n", errno);
+	CHECK_OPTS(topts.retval != expected_retval, "check_retval",
+		   "expect 0x%x, got 0x%x\n", expected_retval, topts.retval);

 	for (i = 0; i < nr_online; i++) {
 		if (!online[i])
 			continue;

-		opts.cpu = i;
-		opts.retval = 0;
-		err = bpf_prog_test_run_opts(prog_fd, &opts);
-		CHECK(err < 0, "test_run_opts", "err %d\n", errno);
-		CHECK(skel->data->on_cpu != i, "check_on_cpu",
-		      "expect %d got %d\n", i, skel->data->on_cpu);
-		CHECK(opts.retval != expected_retval,
-		      "check_retval", "expect 0x%x, got 0x%x\n",
-		      expected_retval, opts.retval);
+		topts.flags = BPF_F_TEST_RUN_ON_CPU;
+		topts.cpu = i;
+		topts.retval = 0;
+		err = bpf_prog_test_run_opts(prog_fd, &topts);
+		CHECK_OPTS(err < 0, "test_run_opts", "err %d\n", errno);
+		CHECK_OPTS(skel->data->on_cpu != i, "check_on_cpu",
+			   "expect %d got %d\n", i, skel->data->on_cpu);
+		CHECK_OPTS(topts.retval != expected_retval, "check_retval",
+			   "expect 0x%x, got 0x%x\n", expected_retval,
+			   topts.retval);
 	}

 	/* invalid cpu ID should fail with ENXIO */
-	opts.cpu = 0xffffffff;
-	err = bpf_prog_test_run_opts(prog_fd, &opts);
-	CHECK(err >= 0 || errno != ENXIO,
-	      "test_run_opts_fail",
-	      "should failed with ENXIO\n");
+	topts.cpu = 0xffffffff;
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err >= 0 || errno != ENXIO, "test_run_opts_fail",
+		   "should failed with ENXIO\n");

 	/* non-zero cpu w/o BPF_F_TEST_RUN_ON_CPU should fail with EINVAL */
-	opts.cpu = 1;
-	opts.flags = 0;
-	err = bpf_prog_test_run_opts(prog_fd, &opts);
-	CHECK(err >= 0 || errno != EINVAL,
-	      "test_run_opts_fail",
-	      "should failed with EINVAL\n");
+	topts.cpu = 1;
+	topts.flags = 0;
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err >= 0 || errno != EINVAL, "test_run_opts_fail",
+		   "should failed with EINVAL\n");

 cleanup:
 	close(comm_fd);
diff --git a/tools/testing/selftests/bpf/prog_tests/skb_ctx.c b/tools/testing/selftests/bpf/prog_tests/skb_ctx.c
index b5319ba2ee27..b6fba0b93733 100644
--- a/tools/testing/selftests/bpf/prog_tests/skb_ctx.c
+++ b/tools/testing/selftests/bpf/prog_tests/skb_ctx.c
@@ -20,97 +20,82 @@ void test_skb_ctx(void)
 		.gso_size = 10,
 		.hwtstamp = 11,
 	};
-	struct bpf_prog_test_run_attr tattr = {
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
 		.data_in = &pkt_v4,
 		.data_size_in = sizeof(pkt_v4),
 		.ctx_in = &skb,
 		.ctx_size_in = sizeof(skb),
 		.ctx_out = &skb,
 		.ctx_size_out = sizeof(skb),
-	};
+	);
 	struct bpf_object *obj;
-	int err;
-	int i;
+	int err, prog_fd, i;

-	err = bpf_prog_test_load("./test_skb_ctx.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
-			    &tattr.prog_fd);
-	if (CHECK_ATTR(err, "load", "err %d errno %d\n", err, errno))
+	err = bpf_prog_test_load("./test_skb_ctx.o", BPF_PROG_TYPE_SCHED_CLS,
+				 &obj, &prog_fd);
+	if (CHECK_OPTS(err, "load", "err %d errno %d\n", err, errno))
 		return;

 	/* ctx_in != NULL, ctx_size_in == 0 */

-	tattr.ctx_size_in = 0;
-	err = bpf_prog_test_run_xattr(&tattr);
-	CHECK_ATTR(err == 0, "ctx_size_in", "err %d errno %d\n", err, errno);
-	tattr.ctx_size_in = sizeof(skb);
+	topts.ctx_size_in = 0;
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err == 0, "ctx_size_in", "err %d errno %d\n", err, errno);
+	topts.ctx_size_in = sizeof(skb);

 	/* ctx_out != NULL, ctx_size_out == 0 */

-	tattr.ctx_size_out = 0;
-	err = bpf_prog_test_run_xattr(&tattr);
-	CHECK_ATTR(err == 0, "ctx_size_out", "err %d errno %d\n", err, errno);
-	tattr.ctx_size_out = sizeof(skb);
+	topts.ctx_size_out = 0;
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err == 0, "ctx_size_out", "err %d errno %d\n", err, errno);
+	topts.ctx_size_out = sizeof(skb);

 	/* non-zero [len, tc_index] fields should be rejected*/

 	skb.len = 1;
-	err = bpf_prog_test_run_xattr(&tattr);
-	CHECK_ATTR(err == 0, "len", "err %d errno %d\n", err, errno);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err == 0, "len", "err %d errno %d\n", err, errno);
 	skb.len = 0;

 	skb.tc_index = 1;
-	err = bpf_prog_test_run_xattr(&tattr);
-	CHECK_ATTR(err == 0, "tc_index", "err %d errno %d\n", err, errno);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err == 0, "tc_index", "err %d errno %d\n", err, errno);
 	skb.tc_index = 0;

 	/* non-zero [hash, sk] fields should be rejected */

 	skb.hash = 1;
-	err = bpf_prog_test_run_xattr(&tattr);
-	CHECK_ATTR(err == 0, "hash", "err %d errno %d\n", err, errno);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err == 0, "hash", "err %d errno %d\n", err, errno);
 	skb.hash = 0;

 	skb.sk = (struct bpf_sock *)1;
-	err = bpf_prog_test_run_xattr(&tattr);
-	CHECK_ATTR(err == 0, "sk", "err %d errno %d\n", err, errno);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err == 0, "sk", "err %d errno %d\n", err, errno);
 	skb.sk = 0;

-	err = bpf_prog_test_run_xattr(&tattr);
-	CHECK_ATTR(err != 0 || tattr.retval,
-		   "run",
-		   "err %d errno %d retval %d\n",
-		   err, errno, tattr.retval);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err != 0 || topts.retval, "run",
+		   "err %d errno %d retval %d\n", err, errno, topts.retval);

-	CHECK_ATTR(tattr.ctx_size_out != sizeof(skb),
-		   "ctx_size_out",
-		   "incorrect output size, want %zu have %u\n",
-		   sizeof(skb), tattr.ctx_size_out);
+	CHECK_OPTS(topts.ctx_size_out != sizeof(skb), "ctx_size_out",
+		   "incorrect output size, want %zu have %u\n", sizeof(skb),
+		   topts.ctx_size_out);

 	for (i = 0; i < 5; i++)
-		CHECK_ATTR(skb.cb[i] != i + 2,
-			   "ctx_out_cb",
-			   "skb->cb[i] == %d, expected %d\n",
-			   skb.cb[i], i + 2);
-	CHECK_ATTR(skb.priority != 7,
-		   "ctx_out_priority",
-		   "skb->priority == %d, expected %d\n",
-		   skb.priority, 7);
-	CHECK_ATTR(skb.ifindex != 1,
-		   "ctx_out_ifindex",
-		   "skb->ifindex == %d, expected %d\n",
-		   skb.ifindex, 1);
-	CHECK_ATTR(skb.ingress_ifindex != 11,
-		   "ctx_out_ingress_ifindex",
+		CHECK_OPTS(skb.cb[i] != i + 2, "ctx_out_cb",
+			   "skb->cb[i] == %d, expected %d\n", skb.cb[i], i + 2);
+	CHECK_OPTS(skb.priority != 7, "ctx_out_priority",
+		   "skb->priority == %d, expected %d\n", skb.priority, 7);
+	CHECK_OPTS(skb.ifindex != 1, "ctx_out_ifindex",
+		   "skb->ifindex == %d, expected %d\n", skb.ifindex, 1);
+	CHECK_OPTS(skb.ingress_ifindex != 11, "ctx_out_ingress_ifindex",
 		   "skb->ingress_ifindex == %d, expected %d\n",
 		   skb.ingress_ifindex, 11);
-	CHECK_ATTR(skb.tstamp != 8,
-		   "ctx_out_tstamp",
-		   "skb->tstamp == %lld, expected %d\n",
-		   skb.tstamp, 8);
-	CHECK_ATTR(skb.mark != 10,
-		   "ctx_out_mark",
-		   "skb->mark == %u, expected %d\n",
-		   skb.mark, 10);
+	CHECK_OPTS(skb.tstamp != 8, "ctx_out_tstamp",
+		   "skb->tstamp == %lld, expected %d\n", skb.tstamp, 8);
+	CHECK_OPTS(skb.mark != 10, "ctx_out_mark",
+		   "skb->mark == %u, expected %d\n", skb.mark, 10);

 	bpf_object__close(obj);
 }
diff --git a/tools/testing/selftests/bpf/prog_tests/skb_helpers.c b/tools/testing/selftests/bpf/prog_tests/skb_helpers.c
index 6f802a1c0800..d7516180925a 100644
--- a/tools/testing/selftests/bpf/prog_tests/skb_helpers.c
+++ b/tools/testing/selftests/bpf/prog_tests/skb_helpers.c
@@ -9,22 +9,22 @@ void test_skb_helpers(void)
 		.gso_segs = 8,
 		.gso_size = 10,
 	};
-	struct bpf_prog_test_run_attr tattr = {
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
 		.data_in = &pkt_v4,
 		.data_size_in = sizeof(pkt_v4),
 		.ctx_in = &skb,
 		.ctx_size_in = sizeof(skb),
 		.ctx_out = &skb,
 		.ctx_size_out = sizeof(skb),
-	};
+	);
 	struct bpf_object *obj;
-	int err;
+	int err, prog_fd;

-	err = bpf_prog_test_load("./test_skb_helpers.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
-			    &tattr.prog_fd);
-	if (CHECK_ATTR(err, "load", "err %d errno %d\n", err, errno))
+	err = bpf_prog_test_load("./test_skb_helpers.o",
+				 BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
+	if (CHECK_OPTS(err, "load", "err %d errno %d\n", err, errno))
 		return;
-	err = bpf_prog_test_run_xattr(&tattr);
-	CHECK_ATTR(err, "len", "err %d errno %d\n", err, errno);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	CHECK_OPTS(err, "len", "err %d errno %d\n", err, errno);
 	bpf_object__close(obj);
 }
diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
index b97a8f236b3a..546ad5a6455e 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
@@ -140,12 +140,16 @@ static void test_skmsg_helpers(enum bpf_map_type map_type)

 static void test_sockmap_update(enum bpf_map_type map_type)
 {
-	struct bpf_prog_test_run_attr tattr;
 	int err, prog, src, duration = 0;
 	struct test_sockmap_update *skel;
 	struct bpf_map *dst_map;
 	const __u32 zero = 0;
 	char dummy[14] = {0};
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
+		.data_in = dummy,
+		.data_size_in = sizeof(dummy),
+		.repeat = 1,
+	);
 	__s64 sk;

 	sk = connected_socket_v4();
@@ -167,16 +171,9 @@ static void test_sockmap_update(enum bpf_map_type map_type)
 	if (CHECK(err, "update_elem(src)", "errno=%u\n", errno))
 		goto out;

-	tattr = (struct bpf_prog_test_run_attr){
-		.prog_fd = prog,
-		.repeat = 1,
-		.data_in = dummy,
-		.data_size_in = sizeof(dummy),
-	};
-
-	err = bpf_prog_test_run_xattr(&tattr);
-	if (CHECK_ATTR(err || !tattr.retval, "bpf_prog_test_run",
-		       "errno=%u retval=%u\n", errno, tattr.retval))
+	err = bpf_prog_test_run_opts(prog, &topts);
+	if (CHECK_OPTS(err || !topts.retval, "bpf_prog_test_run",
+		       "errno=%u retval=%u\n", errno, topts.retval))
 		goto out;

 	compare_cookies(skel->maps.src, dst_map);
diff --git a/tools/testing/selftests/bpf/prog_tests/syscall.c b/tools/testing/selftests/bpf/prog_tests/syscall.c
index 81e997a69f7a..542c9b2a860a 100644
--- a/tools/testing/selftests/bpf/prog_tests/syscall.c
+++ b/tools/testing/selftests/bpf/prog_tests/syscall.c
@@ -20,22 +20,22 @@ void test_syscall(void)
 		.log_buf = (uintptr_t) verifier_log,
 		.log_size = sizeof(verifier_log),
 	};
-	struct bpf_prog_test_run_attr tattr = {
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
 		.ctx_in = &ctx,
 		.ctx_size_in = sizeof(ctx),
-	};
+	);
 	struct syscall *skel = NULL;
 	__u64 key = 12, value = 0;
-	int err;
+	int err, prog_fd;

 	skel = syscall__open_and_load();
 	if (!ASSERT_OK_PTR(skel, "skel_load"))
 		goto cleanup;

-	tattr.prog_fd = bpf_program__fd(skel->progs.bpf_prog);
-	err = bpf_prog_test_run_xattr(&tattr);
+	prog_fd = bpf_program__fd(skel->progs.bpf_prog);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
 	ASSERT_EQ(err, 0, "err");
-	ASSERT_EQ(tattr.retval, 1, "retval");
+	ASSERT_EQ(topts.retval, 1, "retval");
 	ASSERT_GT(ctx.map_fd, 0, "ctx.map_fd");
 	ASSERT_GT(ctx.prog_fd, 0, "ctx.prog_fd");
 	ASSERT_OK(memcmp(verifier_log, "processed", sizeof("processed") - 1),
diff --git a/tools/testing/selftests/bpf/prog_tests/test_profiler.c b/tools/testing/selftests/bpf/prog_tests/test_profiler.c
index 4ca275101ee0..67e32df1212f 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_profiler.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_profiler.c
@@ -8,19 +8,19 @@

 static int sanity_run(struct bpf_program *prog)
 {
-	struct bpf_prog_test_run_attr test_attr = {};
 	__u64 args[] = {1, 2, 3};
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
+		.ctx_in = args,
+		.ctx_size_in = sizeof(args),
+	);
 	__u32 duration = 0;
 	int err, prog_fd;

 	prog_fd = bpf_program__fd(prog);
-	test_attr.prog_fd = prog_fd;
-	test_attr.ctx_in = args;
-	test_attr.ctx_size_in = sizeof(args);
-	err = bpf_prog_test_run_xattr(&test_attr);
-	if (CHECK(err || test_attr.retval, "test_run",
-		  "err %d errno %d retval %d duration %d\n",
-		  err, errno, test_attr.retval, duration))
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	if (CHECK(err || topts.retval, "test_run",
+		  "err %d errno %d retval %d duration %d\n", err, errno,
+		  topts.retval, duration))
 		return -1;
 	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 bb1b833318d3..f638cbf983e7 100644
--- a/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c
+++ b/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c
@@ -78,30 +78,30 @@ static void test_xdp_adjust_tail_grow2(void)
 	int tailroom = 320; /* SKB_DATA_ALIGN(sizeof(struct skb_shared_info))*/;
 	struct bpf_object *obj;
 	int err, cnt, i;
-	int max_grow;
+	int max_grow, prog_fd;

-	struct bpf_prog_test_run_attr tattr = {
-		.repeat		= 1,
+	LIBBPF_OPTS(bpf_test_run_opts, topts,
 		.data_in	= &buf,
 		.data_out	= &buf,
 		.data_size_in	= 0, /* Per test */
 		.data_size_out	= 0, /* Per test */
-	};
+		.repeat		= 1,
+	);

-	err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &tattr.prog_fd);
+	err = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
 	if (ASSERT_OK(err, "test_xdp_adjust_tail_grow"))
 		return;

 	/* Test case-64 */
 	memset(buf, 1, sizeof(buf));
-	tattr.data_size_in  =  64; /* Determine test case via pkt size */
-	tattr.data_size_out = 128; /* Limit copy_size */
+	topts.data_size_in  =  64; /* Determine test case via pkt size */
+	topts.data_size_out = 128; /* Limit copy_size */
 	/* Kernel side alloc packet memory area that is zero init */
-	err = bpf_prog_test_run_xattr(&tattr);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);

 	ASSERT_EQ(errno, ENOSPC, "case-64 errno"); /* Due limit copy_size in bpf_test_finish */
-	ASSERT_EQ(tattr.retval, XDP_TX, "case-64 retval");
-	ASSERT_EQ(tattr.data_size_out, 192, "case-64 data_size_out"); /* Expected grow size */
+	ASSERT_EQ(topts.retval, XDP_TX, "case-64 retval");
+	ASSERT_EQ(topts.data_size_out, 192, "case-64 data_size_out"); /* Expected grow size */

 	/* Extra checks for data contents */
 	ASSERT_EQ(buf[0], 1, "case-64-data buf[0]"); /*  0-63  memset to 1 */
@@ -113,22 +113,22 @@ static void test_xdp_adjust_tail_grow2(void)

 	/* Test case-128 */
 	memset(buf, 2, sizeof(buf));
-	tattr.data_size_in  = 128; /* Determine test case via pkt size */
-	tattr.data_size_out = sizeof(buf);   /* Copy everything */
-	err = bpf_prog_test_run_xattr(&tattr);
+	topts.data_size_in  = 128; /* Determine test case via pkt size */
+	topts.data_size_out = sizeof(buf);   /* Copy everything */
+	err = bpf_prog_test_run_opts(prog_fd, &topts);

 	max_grow = 4096 - XDP_PACKET_HEADROOM -	tailroom; /* 3520 */
 	ASSERT_OK(err, "case-128");
-	ASSERT_EQ(tattr.retval, XDP_TX, "case-128 retval");
-	ASSERT_EQ(tattr.data_size_out, max_grow, "case-128 data_size_out"); /* Expect max grow */
+	ASSERT_EQ(topts.retval, XDP_TX, "case-128 retval");
+	ASSERT_EQ(topts.data_size_out, max_grow, "case-128 data_size_out"); /* Expect max grow */

 	/* Extra checks for data content: Count grow size, will contain zeros */
 	for (i = 0, cnt = 0; i < sizeof(buf); i++) {
 		if (buf[i] == 0)
 			cnt++;
 	}
-	ASSERT_EQ(cnt, max_grow - tattr.data_size_in, "case-128-data cnt"); /* Grow increase */
-	ASSERT_EQ(tattr.data_size_out, max_grow, "case-128-data data_size_out"); /* Total grow */
+	ASSERT_EQ(cnt, max_grow - topts.data_size_in, "case-128-data cnt"); /* Grow increase */
+	ASSERT_EQ(topts.data_size_out, max_grow, "case-128-data data_size_out"); /* Total grow */

 	bpf_object__close(obj);
 }
