1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 Facebook */
3 #include <test_progs.h>
4 #include <network_helpers.h>
7 typedef int (*test_cb
)(struct bpf_object
*obj
);
9 static int check_data_map(struct bpf_object
*obj
, int prog_cnt
, bool reset
)
11 struct bpf_map
*data_map
= NULL
, *map
;
17 result
= malloc((prog_cnt
+ 32 /* spare */) * sizeof(__u64
));
18 if (CHECK(!result
, "alloc_memory", "failed to alloc memory"))
21 bpf_object__for_each_map(map
, obj
)
22 if (bpf_map__is_internal(map
)) {
26 if (CHECK(!data_map
, "find_data_map", "data map not found\n"))
29 ret
= bpf_map_lookup_elem(bpf_map__fd(data_map
), &zero
, result
);
30 if (CHECK(ret
, "get_result",
31 "failed to get output data: %d\n", ret
))
34 for (i
= 0; i
< prog_cnt
; i
++) {
35 if (CHECK(result
[i
] != 1, "result",
36 "fexit_bpf2bpf result[%d] failed err %llu\n",
42 ret
= bpf_map_update_elem(bpf_map__fd(data_map
), &zero
, result
, 0);
43 if (CHECK(ret
, "reset_result", "failed to reset result\n"))
53 static void test_fexit_bpf2bpf_common(const char *obj_file
,
54 const char *target_obj_file
,
56 const char **prog_name
,
60 struct bpf_object
*obj
= NULL
, *tgt_obj
;
61 struct bpf_program
**prog
= NULL
;
62 struct bpf_link
**link
= NULL
;
63 __u32 duration
= 0, retval
;
66 err
= bpf_prog_load(target_obj_file
, BPF_PROG_TYPE_UNSPEC
,
68 if (CHECK(err
, "tgt_prog_load", "file %s err %d errno %d\n",
69 target_obj_file
, err
, errno
))
71 DECLARE_LIBBPF_OPTS(bpf_object_open_opts
, opts
,
72 .attach_prog_fd
= tgt_fd
,
75 link
= calloc(sizeof(struct bpf_link
*), prog_cnt
);
76 prog
= calloc(sizeof(struct bpf_program
*), prog_cnt
);
77 if (CHECK(!link
|| !prog
, "alloc_memory", "failed to alloc memory"))
80 obj
= bpf_object__open_file(obj_file
, &opts
);
81 if (CHECK(IS_ERR_OR_NULL(obj
), "obj_open",
82 "failed to open %s: %ld\n", obj_file
,
86 err
= bpf_object__load(obj
);
87 if (CHECK(err
, "obj_load", "err %d\n", err
))
90 for (i
= 0; i
< prog_cnt
; i
++) {
91 prog
[i
] = bpf_object__find_program_by_title(obj
, prog_name
[i
]);
92 if (CHECK(!prog
[i
], "find_prog", "prog %s not found\n", prog_name
[i
]))
94 link
[i
] = bpf_program__attach_trace(prog
[i
]);
95 if (CHECK(IS_ERR(link
[i
]), "attach_trace", "failed to link\n"))
108 err
= bpf_prog_test_run(tgt_fd
, 1, &pkt_v6
, sizeof(pkt_v6
),
109 NULL
, NULL
, &retval
, &duration
);
110 CHECK(err
|| retval
, "ipv6",
111 "err %d errno %d retval %d duration %d\n",
112 err
, errno
, retval
, duration
);
114 if (check_data_map(obj
, prog_cnt
, false))
118 for (i
= 0; i
< prog_cnt
; i
++)
119 if (!IS_ERR_OR_NULL(link
[i
]))
120 bpf_link__destroy(link
[i
]);
121 if (!IS_ERR_OR_NULL(obj
))
122 bpf_object__close(obj
);
123 bpf_object__close(tgt_obj
);
128 static void test_target_no_callees(void)
130 const char *prog_name
[] = {
131 "fexit/test_pkt_md_access",
133 test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o",
134 "./test_pkt_md_access.o",
135 ARRAY_SIZE(prog_name
),
136 prog_name
, true, NULL
);
139 static void test_target_yes_callees(void)
141 const char *prog_name
[] = {
142 "fexit/test_pkt_access",
143 "fexit/test_pkt_access_subprog1",
144 "fexit/test_pkt_access_subprog2",
145 "fexit/test_pkt_access_subprog3",
147 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
148 "./test_pkt_access.o",
149 ARRAY_SIZE(prog_name
),
150 prog_name
, true, NULL
);
153 static void test_func_replace(void)
155 const char *prog_name
[] = {
156 "fexit/test_pkt_access",
157 "fexit/test_pkt_access_subprog1",
158 "fexit/test_pkt_access_subprog2",
159 "fexit/test_pkt_access_subprog3",
160 "freplace/get_skb_len",
161 "freplace/get_skb_ifindex",
162 "freplace/get_constant",
163 "freplace/test_pkt_write_access_subprog",
165 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
166 "./test_pkt_access.o",
167 ARRAY_SIZE(prog_name
),
168 prog_name
, true, NULL
);
171 static void test_func_replace_verify(void)
173 const char *prog_name
[] = {
176 test_fexit_bpf2bpf_common("./freplace_connect4.o",
178 ARRAY_SIZE(prog_name
),
179 prog_name
, false, NULL
);
182 static int test_second_attach(struct bpf_object
*obj
)
184 const char *prog_name
= "freplace/get_constant";
185 const char *tgt_name
= prog_name
+ 9; /* cut off freplace/ */
186 const char *tgt_obj_file
= "./test_pkt_access.o";
187 struct bpf_program
*prog
= NULL
;
188 struct bpf_object
*tgt_obj
;
189 __u32 duration
= 0, retval
;
190 struct bpf_link
*link
;
193 prog
= bpf_object__find_program_by_title(obj
, prog_name
);
194 if (CHECK(!prog
, "find_prog", "prog %s not found\n", prog_name
))
197 err
= bpf_prog_load(tgt_obj_file
, BPF_PROG_TYPE_UNSPEC
,
199 if (CHECK(err
, "second_prog_load", "file %s err %d errno %d\n",
200 tgt_obj_file
, err
, errno
))
203 link
= bpf_program__attach_freplace(prog
, tgt_fd
, tgt_name
);
204 if (CHECK(IS_ERR(link
), "second_link", "failed to attach second link prog_fd %d tgt_fd %d\n", bpf_program__fd(prog
), tgt_fd
))
207 err
= bpf_prog_test_run(tgt_fd
, 1, &pkt_v6
, sizeof(pkt_v6
),
208 NULL
, NULL
, &retval
, &duration
);
209 if (CHECK(err
|| retval
, "ipv6",
210 "err %d errno %d retval %d duration %d\n",
211 err
, errno
, retval
, duration
))
214 err
= check_data_map(obj
, 1, true);
219 bpf_link__destroy(link
);
220 bpf_object__close(tgt_obj
);
224 static void test_func_replace_multi(void)
226 const char *prog_name
[] = {
227 "freplace/get_constant",
229 test_fexit_bpf2bpf_common("./freplace_get_constant.o",
230 "./test_pkt_access.o",
231 ARRAY_SIZE(prog_name
),
232 prog_name
, true, test_second_attach
);
235 static void test_fmod_ret_freplace(void)
237 struct bpf_object
*freplace_obj
= NULL
, *pkt_obj
, *fmod_obj
= NULL
;
238 const char *freplace_name
= "./freplace_get_constant.o";
239 const char *fmod_ret_name
= "./fmod_ret_freplace.o";
240 DECLARE_LIBBPF_OPTS(bpf_object_open_opts
, opts
);
241 const char *tgt_name
= "./test_pkt_access.o";
242 struct bpf_link
*freplace_link
= NULL
;
243 struct bpf_program
*prog
;
247 err
= bpf_prog_load(tgt_name
, BPF_PROG_TYPE_UNSPEC
,
249 /* the target prog should load fine */
250 if (CHECK(err
, "tgt_prog_load", "file %s err %d errno %d\n",
251 tgt_name
, err
, errno
))
253 opts
.attach_prog_fd
= pkt_fd
;
255 freplace_obj
= bpf_object__open_file(freplace_name
, &opts
);
256 if (CHECK(IS_ERR_OR_NULL(freplace_obj
), "freplace_obj_open",
257 "failed to open %s: %ld\n", freplace_name
,
258 PTR_ERR(freplace_obj
)))
261 err
= bpf_object__load(freplace_obj
);
262 if (CHECK(err
, "freplace_obj_load", "err %d\n", err
))
265 prog
= bpf_program__next(NULL
, freplace_obj
);
266 freplace_link
= bpf_program__attach_trace(prog
);
267 if (CHECK(IS_ERR(freplace_link
), "freplace_attach_trace", "failed to link\n"))
270 opts
.attach_prog_fd
= bpf_program__fd(prog
);
271 fmod_obj
= bpf_object__open_file(fmod_ret_name
, &opts
);
272 if (CHECK(IS_ERR_OR_NULL(fmod_obj
), "fmod_obj_open",
273 "failed to open %s: %ld\n", fmod_ret_name
,
277 err
= bpf_object__load(fmod_obj
);
278 if (CHECK(!err
, "fmod_obj_load", "loading fmod_ret should fail\n"))
282 bpf_link__destroy(freplace_link
);
283 bpf_object__close(freplace_obj
);
284 bpf_object__close(fmod_obj
);
285 bpf_object__close(pkt_obj
);
289 static void test_func_sockmap_update(void)
291 const char *prog_name
[] = {
292 "freplace/cls_redirect",
294 test_fexit_bpf2bpf_common("./freplace_cls_redirect.o",
295 "./test_cls_redirect.o",
296 ARRAY_SIZE(prog_name
),
297 prog_name
, false, NULL
);
300 static void test_obj_load_failure_common(const char *obj_file
,
301 const char *target_obj_file
)
305 * standalone test that asserts failure to load freplace prog
306 * because of invalid return code.
308 struct bpf_object
*obj
= NULL
, *pkt_obj
;
312 err
= bpf_prog_load(target_obj_file
, BPF_PROG_TYPE_UNSPEC
,
314 /* the target prog should load fine */
315 if (CHECK(err
, "tgt_prog_load", "file %s err %d errno %d\n",
316 target_obj_file
, err
, errno
))
318 DECLARE_LIBBPF_OPTS(bpf_object_open_opts
, opts
,
319 .attach_prog_fd
= pkt_fd
,
322 obj
= bpf_object__open_file(obj_file
, &opts
);
323 if (CHECK(IS_ERR_OR_NULL(obj
), "obj_open",
324 "failed to open %s: %ld\n", obj_file
,
328 /* It should fail to load the program */
329 err
= bpf_object__load(obj
);
330 if (CHECK(!err
, "bpf_obj_load should fail", "err %d\n", err
))
334 if (!IS_ERR_OR_NULL(obj
))
335 bpf_object__close(obj
);
336 bpf_object__close(pkt_obj
);
339 static void test_func_replace_return_code(void)
341 /* test invalid return code in the replaced program */
342 test_obj_load_failure_common("./freplace_connect_v4_prog.o",
343 "./connect4_prog.o");
346 static void test_func_map_prog_compatibility(void)
348 /* test with spin lock map value in the replaced program */
349 test_obj_load_failure_common("./freplace_attach_probe.o",
350 "./test_attach_probe.o");
353 void test_fexit_bpf2bpf(void)
355 if (test__start_subtest("target_no_callees"))
356 test_target_no_callees();
357 if (test__start_subtest("target_yes_callees"))
358 test_target_yes_callees();
359 if (test__start_subtest("func_replace"))
361 if (test__start_subtest("func_replace_verify"))
362 test_func_replace_verify();
363 if (test__start_subtest("func_sockmap_update"))
364 test_func_sockmap_update();
365 if (test__start_subtest("func_replace_return_code"))
366 test_func_replace_return_code();
367 if (test__start_subtest("func_map_prog_compatibility"))
368 test_func_map_prog_compatibility();
369 if (test__start_subtest("func_replace_multi"))
370 test_func_replace_multi();
371 if (test__start_subtest("fmod_ret_freplace"))
372 test_fmod_ret_freplace();