1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include "missed_kprobe.skel.h"
4 #include "missed_kprobe_recursion.skel.h"
5 #include "missed_tp_recursion.skel.h"
6
7 /*
8 * Putting kprobe on bpf_fentry_test1 that calls bpf_kfunc_common_test
9 * kfunc, which has also kprobe on. The latter won't get triggered due
10 * to kprobe recursion check and kprobe missed counter is incremented.
11 */
test_missed_perf_kprobe(void)12 static void test_missed_perf_kprobe(void)
13 {
14 LIBBPF_OPTS(bpf_test_run_opts, topts);
15 struct bpf_link_info info = {};
16 struct missed_kprobe *skel;
17 __u32 len = sizeof(info);
18 int err, prog_fd;
19
20 skel = missed_kprobe__open_and_load();
21 if (!ASSERT_OK_PTR(skel, "missed_kprobe__open_and_load"))
22 goto cleanup;
23
24 err = missed_kprobe__attach(skel);
25 if (!ASSERT_OK(err, "missed_kprobe__attach"))
26 goto cleanup;
27
28 prog_fd = bpf_program__fd(skel->progs.trigger);
29 err = bpf_prog_test_run_opts(prog_fd, &topts);
30 ASSERT_OK(err, "test_run");
31 ASSERT_EQ(topts.retval, 0, "test_run");
32
33 err = bpf_link_get_info_by_fd(bpf_link__fd(skel->links.test2), &info, &len);
34 if (!ASSERT_OK(err, "bpf_link_get_info_by_fd"))
35 goto cleanup;
36
37 ASSERT_EQ(info.type, BPF_LINK_TYPE_PERF_EVENT, "info.type");
38 ASSERT_EQ(info.perf_event.type, BPF_PERF_EVENT_KPROBE, "info.perf_event.type");
39 ASSERT_EQ(info.perf_event.kprobe.missed, 1, "info.perf_event.kprobe.missed");
40
41 cleanup:
42 missed_kprobe__destroy(skel);
43 }
44
get_missed_count(int fd)45 static __u64 get_missed_count(int fd)
46 {
47 struct bpf_prog_info info = {};
48 __u32 len = sizeof(info);
49 int err;
50
51 err = bpf_prog_get_info_by_fd(fd, &info, &len);
52 if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd"))
53 return (__u64) -1;
54 return info.recursion_misses;
55 }
56
57 /*
58 * Putting kprobe.multi on bpf_fentry_test1 that calls bpf_kfunc_common_test
59 * kfunc which has 3 perf event kprobes and 1 kprobe.multi attached.
60 *
61 * Because fprobe (kprobe.multi attach layear) does not have strict recursion
62 * check the kprobe's bpf_prog_active check is hit for test2-5.
63 */
test_missed_kprobe_recursion(void)64 static void test_missed_kprobe_recursion(void)
65 {
66 LIBBPF_OPTS(bpf_test_run_opts, topts);
67 struct missed_kprobe_recursion *skel;
68 int err, prog_fd;
69
70 skel = missed_kprobe_recursion__open_and_load();
71 if (!ASSERT_OK_PTR(skel, "missed_kprobe_recursion__open_and_load"))
72 goto cleanup;
73
74 err = missed_kprobe_recursion__attach(skel);
75 if (!ASSERT_OK(err, "missed_kprobe_recursion__attach"))
76 goto cleanup;
77
78 prog_fd = bpf_program__fd(skel->progs.trigger);
79 err = bpf_prog_test_run_opts(prog_fd, &topts);
80 ASSERT_OK(err, "test_run");
81 ASSERT_EQ(topts.retval, 0, "test_run");
82
83 ASSERT_EQ(get_missed_count(bpf_program__fd(skel->progs.test1)), 0, "test1_recursion_misses");
84 ASSERT_GE(get_missed_count(bpf_program__fd(skel->progs.test2)), 1, "test2_recursion_misses");
85 ASSERT_GE(get_missed_count(bpf_program__fd(skel->progs.test3)), 1, "test3_recursion_misses");
86 ASSERT_GE(get_missed_count(bpf_program__fd(skel->progs.test4)), 1, "test4_recursion_misses");
87 ASSERT_GE(get_missed_count(bpf_program__fd(skel->progs.test5)), 1, "test5_recursion_misses");
88 ASSERT_EQ(get_missed_count(bpf_program__fd(skel->progs.test6)), 1, "test6_recursion_misses");
89
90 cleanup:
91 missed_kprobe_recursion__destroy(skel);
92 }
93
94 /*
95 * Putting kprobe on bpf_fentry_test1 that calls bpf_printk and invokes
96 * bpf_trace_printk tracepoint. The bpf_trace_printk tracepoint has test[234]
97 * programs attached to it.
98 *
99 * Because kprobe execution goes through bpf_prog_active check, programs
100 * attached to the tracepoint will fail the recursion check and increment
101 * the recursion_misses stats.
102 */
test_missed_tp_recursion(void)103 static void test_missed_tp_recursion(void)
104 {
105 LIBBPF_OPTS(bpf_test_run_opts, topts);
106 struct missed_tp_recursion *skel;
107 int err, prog_fd;
108
109 skel = missed_tp_recursion__open_and_load();
110 if (!ASSERT_OK_PTR(skel, "missed_tp_recursion__open_and_load"))
111 goto cleanup;
112
113 err = missed_tp_recursion__attach(skel);
114 if (!ASSERT_OK(err, "missed_tp_recursion__attach"))
115 goto cleanup;
116
117 prog_fd = bpf_program__fd(skel->progs.trigger);
118 err = bpf_prog_test_run_opts(prog_fd, &topts);
119 ASSERT_OK(err, "test_run");
120 ASSERT_EQ(topts.retval, 0, "test_run");
121
122 ASSERT_EQ(get_missed_count(bpf_program__fd(skel->progs.test1)), 0, "test1_recursion_misses");
123 ASSERT_EQ(get_missed_count(bpf_program__fd(skel->progs.test2)), 1, "test2_recursion_misses");
124 ASSERT_EQ(get_missed_count(bpf_program__fd(skel->progs.test3)), 1, "test3_recursion_misses");
125 ASSERT_EQ(get_missed_count(bpf_program__fd(skel->progs.test4)), 1, "test4_recursion_misses");
126
127 cleanup:
128 missed_tp_recursion__destroy(skel);
129 }
130
test_missed(void)131 void test_missed(void)
132 {
133 if (test__start_subtest("perf_kprobe"))
134 test_missed_perf_kprobe();
135 if (test__start_subtest("kprobe_recursion"))
136 test_missed_kprobe_recursion();
137 if (test__start_subtest("tp_recursion"))
138 test_missed_tp_recursion();
139 }
140