cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tailcalls.c (23538B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <test_progs.h>
      3#include <network_helpers.h>
      4
      5/* test_tailcall_1 checks basic functionality by patching multiple locations
      6 * in a single program for a single tail call slot with nop->jmp, jmp->nop
      7 * and jmp->jmp rewrites. Also checks for nop->nop.
      8 */
      9static void test_tailcall_1(void)
     10{
     11	int err, map_fd, prog_fd, main_fd, i, j;
     12	struct bpf_map *prog_array;
     13	struct bpf_program *prog;
     14	struct bpf_object *obj;
     15	char prog_name[32];
     16	char buff[128] = {};
     17	LIBBPF_OPTS(bpf_test_run_opts, topts,
     18		.data_in = buff,
     19		.data_size_in = sizeof(buff),
     20		.repeat = 1,
     21	);
     22
     23	err = bpf_prog_test_load("tailcall1.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
     24			    &prog_fd);
     25	if (CHECK_FAIL(err))
     26		return;
     27
     28	prog = bpf_object__find_program_by_name(obj, "entry");
     29	if (CHECK_FAIL(!prog))
     30		goto out;
     31
     32	main_fd = bpf_program__fd(prog);
     33	if (CHECK_FAIL(main_fd < 0))
     34		goto out;
     35
     36	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
     37	if (CHECK_FAIL(!prog_array))
     38		goto out;
     39
     40	map_fd = bpf_map__fd(prog_array);
     41	if (CHECK_FAIL(map_fd < 0))
     42		goto out;
     43
     44	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
     45		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
     46
     47		prog = bpf_object__find_program_by_name(obj, prog_name);
     48		if (CHECK_FAIL(!prog))
     49			goto out;
     50
     51		prog_fd = bpf_program__fd(prog);
     52		if (CHECK_FAIL(prog_fd < 0))
     53			goto out;
     54
     55		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
     56		if (CHECK_FAIL(err))
     57			goto out;
     58	}
     59
     60	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
     61		err = bpf_prog_test_run_opts(main_fd, &topts);
     62		ASSERT_OK(err, "tailcall");
     63		ASSERT_EQ(topts.retval, i, "tailcall retval");
     64
     65		err = bpf_map_delete_elem(map_fd, &i);
     66		if (CHECK_FAIL(err))
     67			goto out;
     68	}
     69
     70	err = bpf_prog_test_run_opts(main_fd, &topts);
     71	ASSERT_OK(err, "tailcall");
     72	ASSERT_EQ(topts.retval, 3, "tailcall retval");
     73
     74	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
     75		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
     76
     77		prog = bpf_object__find_program_by_name(obj, prog_name);
     78		if (CHECK_FAIL(!prog))
     79			goto out;
     80
     81		prog_fd = bpf_program__fd(prog);
     82		if (CHECK_FAIL(prog_fd < 0))
     83			goto out;
     84
     85		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
     86		if (CHECK_FAIL(err))
     87			goto out;
     88	}
     89
     90	err = bpf_prog_test_run_opts(main_fd, &topts);
     91	ASSERT_OK(err, "tailcall");
     92	ASSERT_OK(topts.retval, "tailcall retval");
     93
     94	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
     95		j = bpf_map__max_entries(prog_array) - 1 - i;
     96		snprintf(prog_name, sizeof(prog_name), "classifier_%d", j);
     97
     98		prog = bpf_object__find_program_by_name(obj, prog_name);
     99		if (CHECK_FAIL(!prog))
    100			goto out;
    101
    102		prog_fd = bpf_program__fd(prog);
    103		if (CHECK_FAIL(prog_fd < 0))
    104			goto out;
    105
    106		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
    107		if (CHECK_FAIL(err))
    108			goto out;
    109	}
    110
    111	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    112		j = bpf_map__max_entries(prog_array) - 1 - i;
    113
    114		err = bpf_prog_test_run_opts(main_fd, &topts);
    115		ASSERT_OK(err, "tailcall");
    116		ASSERT_EQ(topts.retval, j, "tailcall retval");
    117
    118		err = bpf_map_delete_elem(map_fd, &i);
    119		if (CHECK_FAIL(err))
    120			goto out;
    121	}
    122
    123	err = bpf_prog_test_run_opts(main_fd, &topts);
    124	ASSERT_OK(err, "tailcall");
    125	ASSERT_EQ(topts.retval, 3, "tailcall retval");
    126
    127	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    128		err = bpf_map_delete_elem(map_fd, &i);
    129		if (CHECK_FAIL(err >= 0 || errno != ENOENT))
    130			goto out;
    131
    132		err = bpf_prog_test_run_opts(main_fd, &topts);
    133		ASSERT_OK(err, "tailcall");
    134		ASSERT_EQ(topts.retval, 3, "tailcall retval");
    135	}
    136
    137out:
    138	bpf_object__close(obj);
    139}
    140
    141/* test_tailcall_2 checks that patching multiple programs for a single
    142 * tail call slot works. It also jumps through several programs and tests
    143 * the tail call limit counter.
    144 */
    145static void test_tailcall_2(void)
    146{
    147	int err, map_fd, prog_fd, main_fd, i;
    148	struct bpf_map *prog_array;
    149	struct bpf_program *prog;
    150	struct bpf_object *obj;
    151	char prog_name[32];
    152	char buff[128] = {};
    153	LIBBPF_OPTS(bpf_test_run_opts, topts,
    154		.data_in = buff,
    155		.data_size_in = sizeof(buff),
    156		.repeat = 1,
    157	);
    158
    159	err = bpf_prog_test_load("tailcall2.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
    160			    &prog_fd);
    161	if (CHECK_FAIL(err))
    162		return;
    163
    164	prog = bpf_object__find_program_by_name(obj, "entry");
    165	if (CHECK_FAIL(!prog))
    166		goto out;
    167
    168	main_fd = bpf_program__fd(prog);
    169	if (CHECK_FAIL(main_fd < 0))
    170		goto out;
    171
    172	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
    173	if (CHECK_FAIL(!prog_array))
    174		goto out;
    175
    176	map_fd = bpf_map__fd(prog_array);
    177	if (CHECK_FAIL(map_fd < 0))
    178		goto out;
    179
    180	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    181		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
    182
    183		prog = bpf_object__find_program_by_name(obj, prog_name);
    184		if (CHECK_FAIL(!prog))
    185			goto out;
    186
    187		prog_fd = bpf_program__fd(prog);
    188		if (CHECK_FAIL(prog_fd < 0))
    189			goto out;
    190
    191		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
    192		if (CHECK_FAIL(err))
    193			goto out;
    194	}
    195
    196	err = bpf_prog_test_run_opts(main_fd, &topts);
    197	ASSERT_OK(err, "tailcall");
    198	ASSERT_EQ(topts.retval, 2, "tailcall retval");
    199
    200	i = 2;
    201	err = bpf_map_delete_elem(map_fd, &i);
    202	if (CHECK_FAIL(err))
    203		goto out;
    204
    205	err = bpf_prog_test_run_opts(main_fd, &topts);
    206	ASSERT_OK(err, "tailcall");
    207	ASSERT_EQ(topts.retval, 1, "tailcall retval");
    208
    209	i = 0;
    210	err = bpf_map_delete_elem(map_fd, &i);
    211	if (CHECK_FAIL(err))
    212		goto out;
    213
    214	err = bpf_prog_test_run_opts(main_fd, &topts);
    215	ASSERT_OK(err, "tailcall");
    216	ASSERT_EQ(topts.retval, 3, "tailcall retval");
    217out:
    218	bpf_object__close(obj);
    219}
    220
    221static void test_tailcall_count(const char *which)
    222{
    223	int err, map_fd, prog_fd, main_fd, data_fd, i, val;
    224	struct bpf_map *prog_array, *data_map;
    225	struct bpf_program *prog;
    226	struct bpf_object *obj;
    227	char buff[128] = {};
    228	LIBBPF_OPTS(bpf_test_run_opts, topts,
    229		.data_in = buff,
    230		.data_size_in = sizeof(buff),
    231		.repeat = 1,
    232	);
    233
    234	err = bpf_prog_test_load(which, BPF_PROG_TYPE_SCHED_CLS, &obj,
    235			    &prog_fd);
    236	if (CHECK_FAIL(err))
    237		return;
    238
    239	prog = bpf_object__find_program_by_name(obj, "entry");
    240	if (CHECK_FAIL(!prog))
    241		goto out;
    242
    243	main_fd = bpf_program__fd(prog);
    244	if (CHECK_FAIL(main_fd < 0))
    245		goto out;
    246
    247	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
    248	if (CHECK_FAIL(!prog_array))
    249		goto out;
    250
    251	map_fd = bpf_map__fd(prog_array);
    252	if (CHECK_FAIL(map_fd < 0))
    253		goto out;
    254
    255	prog = bpf_object__find_program_by_name(obj, "classifier_0");
    256	if (CHECK_FAIL(!prog))
    257		goto out;
    258
    259	prog_fd = bpf_program__fd(prog);
    260	if (CHECK_FAIL(prog_fd < 0))
    261		goto out;
    262
    263	i = 0;
    264	err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
    265	if (CHECK_FAIL(err))
    266		goto out;
    267
    268	err = bpf_prog_test_run_opts(main_fd, &topts);
    269	ASSERT_OK(err, "tailcall");
    270	ASSERT_EQ(topts.retval, 1, "tailcall retval");
    271
    272	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
    273	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
    274		return;
    275
    276	data_fd = bpf_map__fd(data_map);
    277	if (CHECK_FAIL(map_fd < 0))
    278		return;
    279
    280	i = 0;
    281	err = bpf_map_lookup_elem(data_fd, &i, &val);
    282	ASSERT_OK(err, "tailcall count");
    283	ASSERT_EQ(val, 33, "tailcall count");
    284
    285	i = 0;
    286	err = bpf_map_delete_elem(map_fd, &i);
    287	if (CHECK_FAIL(err))
    288		goto out;
    289
    290	err = bpf_prog_test_run_opts(main_fd, &topts);
    291	ASSERT_OK(err, "tailcall");
    292	ASSERT_OK(topts.retval, "tailcall retval");
    293out:
    294	bpf_object__close(obj);
    295}
    296
    297/* test_tailcall_3 checks that the count value of the tail call limit
    298 * enforcement matches with expectations. JIT uses direct jump.
    299 */
    300static void test_tailcall_3(void)
    301{
    302	test_tailcall_count("tailcall3.o");
    303}
    304
    305/* test_tailcall_6 checks that the count value of the tail call limit
    306 * enforcement matches with expectations. JIT uses indirect jump.
    307 */
    308static void test_tailcall_6(void)
    309{
    310	test_tailcall_count("tailcall6.o");
    311}
    312
    313/* test_tailcall_4 checks that the kernel properly selects indirect jump
    314 * for the case where the key is not known. Latter is passed via global
    315 * data to select different targets we can compare return value of.
    316 */
    317static void test_tailcall_4(void)
    318{
    319	int err, map_fd, prog_fd, main_fd, data_fd, i;
    320	struct bpf_map *prog_array, *data_map;
    321	struct bpf_program *prog;
    322	struct bpf_object *obj;
    323	static const int zero = 0;
    324	char buff[128] = {};
    325	char prog_name[32];
    326	LIBBPF_OPTS(bpf_test_run_opts, topts,
    327		.data_in = buff,
    328		.data_size_in = sizeof(buff),
    329		.repeat = 1,
    330	);
    331
    332	err = bpf_prog_test_load("tailcall4.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
    333			    &prog_fd);
    334	if (CHECK_FAIL(err))
    335		return;
    336
    337	prog = bpf_object__find_program_by_name(obj, "entry");
    338	if (CHECK_FAIL(!prog))
    339		goto out;
    340
    341	main_fd = bpf_program__fd(prog);
    342	if (CHECK_FAIL(main_fd < 0))
    343		goto out;
    344
    345	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
    346	if (CHECK_FAIL(!prog_array))
    347		goto out;
    348
    349	map_fd = bpf_map__fd(prog_array);
    350	if (CHECK_FAIL(map_fd < 0))
    351		goto out;
    352
    353	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
    354	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
    355		return;
    356
    357	data_fd = bpf_map__fd(data_map);
    358	if (CHECK_FAIL(map_fd < 0))
    359		return;
    360
    361	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    362		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
    363
    364		prog = bpf_object__find_program_by_name(obj, prog_name);
    365		if (CHECK_FAIL(!prog))
    366			goto out;
    367
    368		prog_fd = bpf_program__fd(prog);
    369		if (CHECK_FAIL(prog_fd < 0))
    370			goto out;
    371
    372		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
    373		if (CHECK_FAIL(err))
    374			goto out;
    375	}
    376
    377	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    378		err = bpf_map_update_elem(data_fd, &zero, &i, BPF_ANY);
    379		if (CHECK_FAIL(err))
    380			goto out;
    381
    382		err = bpf_prog_test_run_opts(main_fd, &topts);
    383		ASSERT_OK(err, "tailcall");
    384		ASSERT_EQ(topts.retval, i, "tailcall retval");
    385	}
    386
    387	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    388		err = bpf_map_update_elem(data_fd, &zero, &i, BPF_ANY);
    389		if (CHECK_FAIL(err))
    390			goto out;
    391
    392		err = bpf_map_delete_elem(map_fd, &i);
    393		if (CHECK_FAIL(err))
    394			goto out;
    395
    396		err = bpf_prog_test_run_opts(main_fd, &topts);
    397		ASSERT_OK(err, "tailcall");
    398		ASSERT_EQ(topts.retval, 3, "tailcall retval");
    399	}
    400out:
    401	bpf_object__close(obj);
    402}
    403
    404/* test_tailcall_5 probes similarly to test_tailcall_4 that the kernel generates
    405 * an indirect jump when the keys are const but different from different branches.
    406 */
    407static void test_tailcall_5(void)
    408{
    409	int err, map_fd, prog_fd, main_fd, data_fd, i, key[] = { 1111, 1234, 5678 };
    410	struct bpf_map *prog_array, *data_map;
    411	struct bpf_program *prog;
    412	struct bpf_object *obj;
    413	static const int zero = 0;
    414	char buff[128] = {};
    415	char prog_name[32];
    416	LIBBPF_OPTS(bpf_test_run_opts, topts,
    417		.data_in = buff,
    418		.data_size_in = sizeof(buff),
    419		.repeat = 1,
    420	);
    421
    422	err = bpf_prog_test_load("tailcall5.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
    423			    &prog_fd);
    424	if (CHECK_FAIL(err))
    425		return;
    426
    427	prog = bpf_object__find_program_by_name(obj, "entry");
    428	if (CHECK_FAIL(!prog))
    429		goto out;
    430
    431	main_fd = bpf_program__fd(prog);
    432	if (CHECK_FAIL(main_fd < 0))
    433		goto out;
    434
    435	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
    436	if (CHECK_FAIL(!prog_array))
    437		goto out;
    438
    439	map_fd = bpf_map__fd(prog_array);
    440	if (CHECK_FAIL(map_fd < 0))
    441		goto out;
    442
    443	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
    444	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
    445		return;
    446
    447	data_fd = bpf_map__fd(data_map);
    448	if (CHECK_FAIL(map_fd < 0))
    449		return;
    450
    451	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    452		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
    453
    454		prog = bpf_object__find_program_by_name(obj, prog_name);
    455		if (CHECK_FAIL(!prog))
    456			goto out;
    457
    458		prog_fd = bpf_program__fd(prog);
    459		if (CHECK_FAIL(prog_fd < 0))
    460			goto out;
    461
    462		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
    463		if (CHECK_FAIL(err))
    464			goto out;
    465	}
    466
    467	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    468		err = bpf_map_update_elem(data_fd, &zero, &key[i], BPF_ANY);
    469		if (CHECK_FAIL(err))
    470			goto out;
    471
    472		err = bpf_prog_test_run_opts(main_fd, &topts);
    473		ASSERT_OK(err, "tailcall");
    474		ASSERT_EQ(topts.retval, i, "tailcall retval");
    475	}
    476
    477	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    478		err = bpf_map_update_elem(data_fd, &zero, &key[i], BPF_ANY);
    479		if (CHECK_FAIL(err))
    480			goto out;
    481
    482		err = bpf_map_delete_elem(map_fd, &i);
    483		if (CHECK_FAIL(err))
    484			goto out;
    485
    486		err = bpf_prog_test_run_opts(main_fd, &topts);
    487		ASSERT_OK(err, "tailcall");
    488		ASSERT_EQ(topts.retval, 3, "tailcall retval");
    489	}
    490out:
    491	bpf_object__close(obj);
    492}
    493
    494/* test_tailcall_bpf2bpf_1 purpose is to make sure that tailcalls are working
    495 * correctly in correlation with BPF subprograms
    496 */
    497static void test_tailcall_bpf2bpf_1(void)
    498{
    499	int err, map_fd, prog_fd, main_fd, i;
    500	struct bpf_map *prog_array;
    501	struct bpf_program *prog;
    502	struct bpf_object *obj;
    503	char prog_name[32];
    504	LIBBPF_OPTS(bpf_test_run_opts, topts,
    505		.data_in = &pkt_v4,
    506		.data_size_in = sizeof(pkt_v4),
    507		.repeat = 1,
    508	);
    509
    510	err = bpf_prog_test_load("tailcall_bpf2bpf1.o", BPF_PROG_TYPE_SCHED_CLS,
    511			    &obj, &prog_fd);
    512	if (CHECK_FAIL(err))
    513		return;
    514
    515	prog = bpf_object__find_program_by_name(obj, "entry");
    516	if (CHECK_FAIL(!prog))
    517		goto out;
    518
    519	main_fd = bpf_program__fd(prog);
    520	if (CHECK_FAIL(main_fd < 0))
    521		goto out;
    522
    523	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
    524	if (CHECK_FAIL(!prog_array))
    525		goto out;
    526
    527	map_fd = bpf_map__fd(prog_array);
    528	if (CHECK_FAIL(map_fd < 0))
    529		goto out;
    530
    531	/* nop -> jmp */
    532	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    533		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
    534
    535		prog = bpf_object__find_program_by_name(obj, prog_name);
    536		if (CHECK_FAIL(!prog))
    537			goto out;
    538
    539		prog_fd = bpf_program__fd(prog);
    540		if (CHECK_FAIL(prog_fd < 0))
    541			goto out;
    542
    543		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
    544		if (CHECK_FAIL(err))
    545			goto out;
    546	}
    547
    548	err = bpf_prog_test_run_opts(main_fd, &topts);
    549	ASSERT_OK(err, "tailcall");
    550	ASSERT_EQ(topts.retval, 1, "tailcall retval");
    551
    552	/* jmp -> nop, call subprog that will do tailcall */
    553	i = 1;
    554	err = bpf_map_delete_elem(map_fd, &i);
    555	if (CHECK_FAIL(err))
    556		goto out;
    557
    558	err = bpf_prog_test_run_opts(main_fd, &topts);
    559	ASSERT_OK(err, "tailcall");
    560	ASSERT_OK(topts.retval, "tailcall retval");
    561
    562	/* make sure that subprog can access ctx and entry prog that
    563	 * called this subprog can properly return
    564	 */
    565	i = 0;
    566	err = bpf_map_delete_elem(map_fd, &i);
    567	if (CHECK_FAIL(err))
    568		goto out;
    569
    570	err = bpf_prog_test_run_opts(main_fd, &topts);
    571	ASSERT_OK(err, "tailcall");
    572	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 2, "tailcall retval");
    573out:
    574	bpf_object__close(obj);
    575}
    576
    577/* test_tailcall_bpf2bpf_2 checks that the count value of the tail call limit
    578 * enforcement matches with expectations when tailcall is preceded with
    579 * bpf2bpf call.
    580 */
    581static void test_tailcall_bpf2bpf_2(void)
    582{
    583	int err, map_fd, prog_fd, main_fd, data_fd, i, val;
    584	struct bpf_map *prog_array, *data_map;
    585	struct bpf_program *prog;
    586	struct bpf_object *obj;
    587	char buff[128] = {};
    588	LIBBPF_OPTS(bpf_test_run_opts, topts,
    589		.data_in = buff,
    590		.data_size_in = sizeof(buff),
    591		.repeat = 1,
    592	);
    593
    594	err = bpf_prog_test_load("tailcall_bpf2bpf2.o", BPF_PROG_TYPE_SCHED_CLS,
    595			    &obj, &prog_fd);
    596	if (CHECK_FAIL(err))
    597		return;
    598
    599	prog = bpf_object__find_program_by_name(obj, "entry");
    600	if (CHECK_FAIL(!prog))
    601		goto out;
    602
    603	main_fd = bpf_program__fd(prog);
    604	if (CHECK_FAIL(main_fd < 0))
    605		goto out;
    606
    607	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
    608	if (CHECK_FAIL(!prog_array))
    609		goto out;
    610
    611	map_fd = bpf_map__fd(prog_array);
    612	if (CHECK_FAIL(map_fd < 0))
    613		goto out;
    614
    615	prog = bpf_object__find_program_by_name(obj, "classifier_0");
    616	if (CHECK_FAIL(!prog))
    617		goto out;
    618
    619	prog_fd = bpf_program__fd(prog);
    620	if (CHECK_FAIL(prog_fd < 0))
    621		goto out;
    622
    623	i = 0;
    624	err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
    625	if (CHECK_FAIL(err))
    626		goto out;
    627
    628	err = bpf_prog_test_run_opts(main_fd, &topts);
    629	ASSERT_OK(err, "tailcall");
    630	ASSERT_EQ(topts.retval, 1, "tailcall retval");
    631
    632	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
    633	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
    634		return;
    635
    636	data_fd = bpf_map__fd(data_map);
    637	if (CHECK_FAIL(map_fd < 0))
    638		return;
    639
    640	i = 0;
    641	err = bpf_map_lookup_elem(data_fd, &i, &val);
    642	ASSERT_OK(err, "tailcall count");
    643	ASSERT_EQ(val, 33, "tailcall count");
    644
    645	i = 0;
    646	err = bpf_map_delete_elem(map_fd, &i);
    647	if (CHECK_FAIL(err))
    648		goto out;
    649
    650	err = bpf_prog_test_run_opts(main_fd, &topts);
    651	ASSERT_OK(err, "tailcall");
    652	ASSERT_OK(topts.retval, "tailcall retval");
    653out:
    654	bpf_object__close(obj);
    655}
    656
    657/* test_tailcall_bpf2bpf_3 checks that non-trivial amount of stack (up to
    658 * 256 bytes) can be used within bpf subprograms that have the tailcalls
    659 * in them
    660 */
    661static void test_tailcall_bpf2bpf_3(void)
    662{
    663	int err, map_fd, prog_fd, main_fd, i;
    664	struct bpf_map *prog_array;
    665	struct bpf_program *prog;
    666	struct bpf_object *obj;
    667	char prog_name[32];
    668	LIBBPF_OPTS(bpf_test_run_opts, topts,
    669		.data_in = &pkt_v4,
    670		.data_size_in = sizeof(pkt_v4),
    671		.repeat = 1,
    672	);
    673
    674	err = bpf_prog_test_load("tailcall_bpf2bpf3.o", BPF_PROG_TYPE_SCHED_CLS,
    675			    &obj, &prog_fd);
    676	if (CHECK_FAIL(err))
    677		return;
    678
    679	prog = bpf_object__find_program_by_name(obj, "entry");
    680	if (CHECK_FAIL(!prog))
    681		goto out;
    682
    683	main_fd = bpf_program__fd(prog);
    684	if (CHECK_FAIL(main_fd < 0))
    685		goto out;
    686
    687	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
    688	if (CHECK_FAIL(!prog_array))
    689		goto out;
    690
    691	map_fd = bpf_map__fd(prog_array);
    692	if (CHECK_FAIL(map_fd < 0))
    693		goto out;
    694
    695	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    696		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
    697
    698		prog = bpf_object__find_program_by_name(obj, prog_name);
    699		if (CHECK_FAIL(!prog))
    700			goto out;
    701
    702		prog_fd = bpf_program__fd(prog);
    703		if (CHECK_FAIL(prog_fd < 0))
    704			goto out;
    705
    706		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
    707		if (CHECK_FAIL(err))
    708			goto out;
    709	}
    710
    711	err = bpf_prog_test_run_opts(main_fd, &topts);
    712	ASSERT_OK(err, "tailcall");
    713	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 3, "tailcall retval");
    714
    715	i = 1;
    716	err = bpf_map_delete_elem(map_fd, &i);
    717	if (CHECK_FAIL(err))
    718		goto out;
    719
    720	err = bpf_prog_test_run_opts(main_fd, &topts);
    721	ASSERT_OK(err, "tailcall");
    722	ASSERT_EQ(topts.retval, sizeof(pkt_v4), "tailcall retval");
    723
    724	i = 0;
    725	err = bpf_map_delete_elem(map_fd, &i);
    726	if (CHECK_FAIL(err))
    727		goto out;
    728
    729	err = bpf_prog_test_run_opts(main_fd, &topts);
    730	ASSERT_OK(err, "tailcall");
    731	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 2, "tailcall retval");
    732out:
    733	bpf_object__close(obj);
    734}
    735
    736#include "tailcall_bpf2bpf4.skel.h"
    737
    738/* test_tailcall_bpf2bpf_4 checks that tailcall counter is correctly preserved
    739 * across tailcalls combined with bpf2bpf calls. for making sure that tailcall
    740 * counter behaves correctly, bpf program will go through following flow:
    741 *
    742 * entry -> entry_subprog -> tailcall0 -> bpf_func0 -> subprog0 ->
    743 * -> tailcall1 -> bpf_func1 -> subprog1 -> tailcall2 -> bpf_func2 ->
    744 * subprog2 [here bump global counter] --------^
    745 *
    746 * We go through first two tailcalls and start counting from the subprog2 where
    747 * the loop begins. At the end of the test make sure that the global counter is
    748 * equal to 31, because tailcall counter includes the first two tailcalls
    749 * whereas global counter is incremented only on loop presented on flow above.
    750 *
    751 * The noise parameter is used to insert bpf_map_update calls into the logic
    752 * to force verifier to patch instructions. This allows us to ensure jump
    753 * logic remains correct with instruction movement.
    754 */
    755static void test_tailcall_bpf2bpf_4(bool noise)
    756{
    757	int err, map_fd, prog_fd, main_fd, data_fd, i;
    758	struct tailcall_bpf2bpf4__bss val;
    759	struct bpf_map *prog_array, *data_map;
    760	struct bpf_program *prog;
    761	struct bpf_object *obj;
    762	char prog_name[32];
    763	LIBBPF_OPTS(bpf_test_run_opts, topts,
    764		.data_in = &pkt_v4,
    765		.data_size_in = sizeof(pkt_v4),
    766		.repeat = 1,
    767	);
    768
    769	err = bpf_prog_test_load("tailcall_bpf2bpf4.o", BPF_PROG_TYPE_SCHED_CLS,
    770			    &obj, &prog_fd);
    771	if (CHECK_FAIL(err))
    772		return;
    773
    774	prog = bpf_object__find_program_by_name(obj, "entry");
    775	if (CHECK_FAIL(!prog))
    776		goto out;
    777
    778	main_fd = bpf_program__fd(prog);
    779	if (CHECK_FAIL(main_fd < 0))
    780		goto out;
    781
    782	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
    783	if (CHECK_FAIL(!prog_array))
    784		goto out;
    785
    786	map_fd = bpf_map__fd(prog_array);
    787	if (CHECK_FAIL(map_fd < 0))
    788		goto out;
    789
    790	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
    791		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
    792
    793		prog = bpf_object__find_program_by_name(obj, prog_name);
    794		if (CHECK_FAIL(!prog))
    795			goto out;
    796
    797		prog_fd = bpf_program__fd(prog);
    798		if (CHECK_FAIL(prog_fd < 0))
    799			goto out;
    800
    801		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
    802		if (CHECK_FAIL(err))
    803			goto out;
    804	}
    805
    806	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
    807	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
    808		return;
    809
    810	data_fd = bpf_map__fd(data_map);
    811	if (CHECK_FAIL(map_fd < 0))
    812		return;
    813
    814	i = 0;
    815	val.noise = noise;
    816	val.count = 0;
    817	err = bpf_map_update_elem(data_fd, &i, &val, BPF_ANY);
    818	if (CHECK_FAIL(err))
    819		goto out;
    820
    821	err = bpf_prog_test_run_opts(main_fd, &topts);
    822	ASSERT_OK(err, "tailcall");
    823	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 3, "tailcall retval");
    824
    825	i = 0;
    826	err = bpf_map_lookup_elem(data_fd, &i, &val);
    827	ASSERT_OK(err, "tailcall count");
    828	ASSERT_EQ(val.count, 31, "tailcall count");
    829
    830out:
    831	bpf_object__close(obj);
    832}
    833
    834#include "tailcall_bpf2bpf6.skel.h"
    835
    836/* Tail call counting works even when there is data on stack which is
    837 * not aligned to 8 bytes.
    838 */
    839static void test_tailcall_bpf2bpf_6(void)
    840{
    841	struct tailcall_bpf2bpf6 *obj;
    842	int err, map_fd, prog_fd, main_fd, data_fd, i, val;
    843	LIBBPF_OPTS(bpf_test_run_opts, topts,
    844		.data_in = &pkt_v4,
    845		.data_size_in = sizeof(pkt_v4),
    846		.repeat = 1,
    847	);
    848
    849	obj = tailcall_bpf2bpf6__open_and_load();
    850	if (!ASSERT_OK_PTR(obj, "open and load"))
    851		return;
    852
    853	main_fd = bpf_program__fd(obj->progs.entry);
    854	if (!ASSERT_GE(main_fd, 0, "entry prog fd"))
    855		goto out;
    856
    857	map_fd = bpf_map__fd(obj->maps.jmp_table);
    858	if (!ASSERT_GE(map_fd, 0, "jmp_table map fd"))
    859		goto out;
    860
    861	prog_fd = bpf_program__fd(obj->progs.classifier_0);
    862	if (!ASSERT_GE(prog_fd, 0, "classifier_0 prog fd"))
    863		goto out;
    864
    865	i = 0;
    866	err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
    867	if (!ASSERT_OK(err, "jmp_table map update"))
    868		goto out;
    869
    870	err = bpf_prog_test_run_opts(main_fd, &topts);
    871	ASSERT_OK(err, "entry prog test run");
    872	ASSERT_EQ(topts.retval, 0, "tailcall retval");
    873
    874	data_fd = bpf_map__fd(obj->maps.bss);
    875	if (!ASSERT_GE(map_fd, 0, "bss map fd"))
    876		goto out;
    877
    878	i = 0;
    879	err = bpf_map_lookup_elem(data_fd, &i, &val);
    880	ASSERT_OK(err, "bss map lookup");
    881	ASSERT_EQ(val, 1, "done flag is set");
    882
    883out:
    884	tailcall_bpf2bpf6__destroy(obj);
    885}
    886
    887void test_tailcalls(void)
    888{
    889	if (test__start_subtest("tailcall_1"))
    890		test_tailcall_1();
    891	if (test__start_subtest("tailcall_2"))
    892		test_tailcall_2();
    893	if (test__start_subtest("tailcall_3"))
    894		test_tailcall_3();
    895	if (test__start_subtest("tailcall_4"))
    896		test_tailcall_4();
    897	if (test__start_subtest("tailcall_5"))
    898		test_tailcall_5();
    899	if (test__start_subtest("tailcall_6"))
    900		test_tailcall_6();
    901	if (test__start_subtest("tailcall_bpf2bpf_1"))
    902		test_tailcall_bpf2bpf_1();
    903	if (test__start_subtest("tailcall_bpf2bpf_2"))
    904		test_tailcall_bpf2bpf_2();
    905	if (test__start_subtest("tailcall_bpf2bpf_3"))
    906		test_tailcall_bpf2bpf_3();
    907	if (test__start_subtest("tailcall_bpf2bpf_4"))
    908		test_tailcall_bpf2bpf_4(false);
    909	if (test__start_subtest("tailcall_bpf2bpf_5"))
    910		test_tailcall_bpf2bpf_4(true);
    911	if (test__start_subtest("tailcall_bpf2bpf_6"))
    912		test_tailcall_bpf2bpf_6();
    913}