208 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2021 Facebook */3 4#include <test_progs.h>5#include <network_helpers.h>6#include "bpf_loop.skel.h"7 8static void check_nr_loops(struct bpf_loop *skel)9{10 struct bpf_link *link;11 12 link = bpf_program__attach(skel->progs.test_prog);13 if (!ASSERT_OK_PTR(link, "link"))14 return;15 16 /* test 0 loops */17 skel->bss->nr_loops = 0;18 19 usleep(1);20 21 ASSERT_EQ(skel->bss->nr_loops_returned, skel->bss->nr_loops,22 "0 loops");23 24 /* test 500 loops */25 skel->bss->nr_loops = 500;26 27 usleep(1);28 29 ASSERT_EQ(skel->bss->nr_loops_returned, skel->bss->nr_loops,30 "500 loops");31 ASSERT_EQ(skel->bss->g_output, (500 * 499) / 2, "g_output");32 33 /* test exceeding the max limit */34 skel->bss->nr_loops = -1;35 36 usleep(1);37 38 ASSERT_EQ(skel->bss->err, -E2BIG, "over max limit");39 40 bpf_link__destroy(link);41}42 43static void check_callback_fn_stop(struct bpf_loop *skel)44{45 struct bpf_link *link;46 47 link = bpf_program__attach(skel->progs.test_prog);48 if (!ASSERT_OK_PTR(link, "link"))49 return;50 51 /* testing that loop is stopped when callback_fn returns 1 */52 skel->bss->nr_loops = 400;53 skel->data->stop_index = 50;54 55 usleep(1);56 57 ASSERT_EQ(skel->bss->nr_loops_returned, skel->data->stop_index + 1,58 "nr_loops_returned");59 ASSERT_EQ(skel->bss->g_output, (50 * 49) / 2,60 "g_output");61 62 bpf_link__destroy(link);63}64 65static void check_null_callback_ctx(struct bpf_loop *skel)66{67 struct bpf_link *link;68 69 /* check that user is able to pass in a null callback_ctx */70 link = bpf_program__attach(skel->progs.prog_null_ctx);71 if (!ASSERT_OK_PTR(link, "link"))72 return;73 74 skel->bss->nr_loops = 10;75 76 usleep(1);77 78 ASSERT_EQ(skel->bss->nr_loops_returned, skel->bss->nr_loops,79 "nr_loops_returned");80 81 bpf_link__destroy(link);82}83 84static void check_invalid_flags(struct bpf_loop *skel)85{86 struct bpf_link *link;87 88 /* check that passing in non-zero flags returns -EINVAL */89 link = bpf_program__attach(skel->progs.prog_invalid_flags);90 if (!ASSERT_OK_PTR(link, "link"))91 return;92 93 usleep(1);94 95 ASSERT_EQ(skel->bss->err, -EINVAL, "err");96 97 bpf_link__destroy(link);98}99 100static void check_nested_calls(struct bpf_loop *skel)101{102 __u32 nr_loops = 100, nested_callback_nr_loops = 4;103 struct bpf_link *link;104 105 /* check that nested calls are supported */106 link = bpf_program__attach(skel->progs.prog_nested_calls);107 if (!ASSERT_OK_PTR(link, "link"))108 return;109 110 skel->bss->nr_loops = nr_loops;111 skel->bss->nested_callback_nr_loops = nested_callback_nr_loops;112 113 usleep(1);114 115 ASSERT_EQ(skel->bss->nr_loops_returned, nr_loops * nested_callback_nr_loops116 * nested_callback_nr_loops, "nr_loops_returned");117 ASSERT_EQ(skel->bss->g_output, (4 * 3) / 2 * nested_callback_nr_loops118 * nr_loops, "g_output");119 120 bpf_link__destroy(link);121}122 123static void check_non_constant_callback(struct bpf_loop *skel)124{125 struct bpf_link *link =126 bpf_program__attach(skel->progs.prog_non_constant_callback);127 128 if (!ASSERT_OK_PTR(link, "link"))129 return;130 131 skel->bss->callback_selector = 0x0F;132 usleep(1);133 ASSERT_EQ(skel->bss->g_output, 0x0F, "g_output #1");134 135 skel->bss->callback_selector = 0xF0;136 usleep(1);137 ASSERT_EQ(skel->bss->g_output, 0xF0, "g_output #2");138 139 bpf_link__destroy(link);140}141 142static void check_stack(struct bpf_loop *skel)143{144 struct bpf_link *link = bpf_program__attach(skel->progs.stack_check);145 const int max_key = 12;146 int key;147 int map_fd;148 149 if (!ASSERT_OK_PTR(link, "link"))150 return;151 152 map_fd = bpf_map__fd(skel->maps.map1);153 154 if (!ASSERT_GE(map_fd, 0, "bpf_map__fd"))155 goto out;156 157 for (key = 1; key <= max_key; ++key) {158 int val = key;159 int err = bpf_map_update_elem(map_fd, &key, &val, BPF_NOEXIST);160 161 if (!ASSERT_OK(err, "bpf_map_update_elem"))162 goto out;163 }164 165 usleep(1);166 167 for (key = 1; key <= max_key; ++key) {168 int val;169 int err = bpf_map_lookup_elem(map_fd, &key, &val);170 171 if (!ASSERT_OK(err, "bpf_map_lookup_elem"))172 goto out;173 if (!ASSERT_EQ(val, key + 1, "bad value in the map"))174 goto out;175 }176 177out:178 bpf_link__destroy(link);179}180 181void test_bpf_loop(void)182{183 struct bpf_loop *skel;184 185 skel = bpf_loop__open_and_load();186 if (!ASSERT_OK_PTR(skel, "bpf_loop__open_and_load"))187 return;188 189 skel->bss->pid = getpid();190 191 if (test__start_subtest("check_nr_loops"))192 check_nr_loops(skel);193 if (test__start_subtest("check_callback_fn_stop"))194 check_callback_fn_stop(skel);195 if (test__start_subtest("check_null_callback_ctx"))196 check_null_callback_ctx(skel);197 if (test__start_subtest("check_invalid_flags"))198 check_invalid_flags(skel);199 if (test__start_subtest("check_nested_calls"))200 check_nested_calls(skel);201 if (test__start_subtest("check_non_constant_callback"))202 check_non_constant_callback(skel);203 if (test__start_subtest("check_stack"))204 check_stack(skel);205 206 bpf_loop__destroy(skel);207}208