2019-11-14 18:57:20 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/* Copyright (c) 2019 Facebook */
|
|
|
|
#include <test_progs.h>
|
2020-05-08 17:46:09 +00:00
|
|
|
#include <network_helpers.h>
|
2019-11-14 18:57:20 +00:00
|
|
|
|
2019-12-05 01:06:07 +00:00
|
|
|
static void test_fexit_bpf2bpf_common(const char *obj_file,
|
|
|
|
const char *target_obj_file,
|
|
|
|
int prog_cnt,
|
2020-04-24 13:34:28 +00:00
|
|
|
const char **prog_name,
|
|
|
|
bool run_prog)
|
2019-11-14 18:57:20 +00:00
|
|
|
{
|
|
|
|
struct bpf_object *obj = NULL, *pkt_obj;
|
|
|
|
int err, pkt_fd, i;
|
2019-12-05 01:06:07 +00:00
|
|
|
struct bpf_link **link = NULL;
|
|
|
|
struct bpf_program **prog = NULL;
|
selftests/bpf: Initialize duration variable before using
The 'duration' variable is referenced in the CHECK() macro, and there are
some uses of the macro before 'duration' is set. The clang compiler
(validly) complains about this.
Sample error:
.../selftests/bpf/prog_tests/fexit_test.c:23:6: warning: variable 'duration' is uninitialized when used here [-Wuninitialized]
if (CHECK(err, "prog_load sched cls", "err %d errno %d\n", err, errno))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../selftests/bpf/test_progs.h:134:25: note: expanded from macro 'CHECK'
if (CHECK(err, "prog_load sched cls", "err %d errno %d\n", err, errno))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_CHECK(condition, tag, duration, format)
^~~~~~~~
Signed-off-by: John Sperbeck <jsperbeck@google.com>
Signed-off-by: Stanislav Fomichev <sdf@google.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Link: https://lore.kernel.org/bpf/20200123235144.93610-1-sdf@google.com
2020-01-23 23:51:44 +00:00
|
|
|
__u32 duration = 0, retval;
|
2019-11-14 18:57:20 +00:00
|
|
|
struct bpf_map *data_map;
|
|
|
|
const int zero = 0;
|
2020-08-13 20:49:38 +00:00
|
|
|
__u64 *result = NULL;
|
2019-11-14 18:57:20 +00:00
|
|
|
|
2019-12-05 01:06:07 +00:00
|
|
|
err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC,
|
2019-11-14 18:57:20 +00:00
|
|
|
&pkt_obj, &pkt_fd);
|
2020-04-24 13:34:28 +00:00
|
|
|
if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",
|
|
|
|
target_obj_file, err, errno))
|
2019-11-14 18:57:20 +00:00
|
|
|
return;
|
|
|
|
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
|
|
|
|
.attach_prog_fd = pkt_fd,
|
|
|
|
);
|
|
|
|
|
2019-12-05 01:06:07 +00:00
|
|
|
link = calloc(sizeof(struct bpf_link *), prog_cnt);
|
|
|
|
prog = calloc(sizeof(struct bpf_program *), prog_cnt);
|
2020-08-13 20:49:38 +00:00
|
|
|
result = malloc((prog_cnt + 32 /* spare */) * sizeof(__u64));
|
2019-12-05 01:06:07 +00:00
|
|
|
if (CHECK(!link || !prog || !result, "alloc_memory",
|
|
|
|
"failed to alloc memory"))
|
|
|
|
goto close_prog;
|
|
|
|
|
|
|
|
obj = bpf_object__open_file(obj_file, &opts);
|
2019-11-14 18:57:20 +00:00
|
|
|
if (CHECK(IS_ERR_OR_NULL(obj), "obj_open",
|
2020-04-24 13:34:28 +00:00
|
|
|
"failed to open %s: %ld\n", obj_file,
|
2019-11-14 18:57:20 +00:00
|
|
|
PTR_ERR(obj)))
|
|
|
|
goto close_prog;
|
|
|
|
|
|
|
|
err = bpf_object__load(obj);
|
|
|
|
if (CHECK(err, "obj_load", "err %d\n", err))
|
|
|
|
goto close_prog;
|
|
|
|
|
2019-12-05 01:06:07 +00:00
|
|
|
for (i = 0; i < prog_cnt; i++) {
|
2019-11-14 18:57:20 +00:00
|
|
|
prog[i] = bpf_object__find_program_by_title(obj, prog_name[i]);
|
|
|
|
if (CHECK(!prog[i], "find_prog", "prog %s not found\n", prog_name[i]))
|
|
|
|
goto close_prog;
|
|
|
|
link[i] = bpf_program__attach_trace(prog[i]);
|
|
|
|
if (CHECK(IS_ERR(link[i]), "attach_trace", "failed to link\n"))
|
|
|
|
goto close_prog;
|
|
|
|
}
|
2020-04-24 13:34:28 +00:00
|
|
|
|
|
|
|
if (!run_prog)
|
|
|
|
goto close_prog;
|
|
|
|
|
2019-11-14 18:57:20 +00:00
|
|
|
data_map = bpf_object__find_map_by_name(obj, "fexit_bp.bss");
|
|
|
|
if (CHECK(!data_map, "find_data_map", "data map not found\n"))
|
|
|
|
goto close_prog;
|
|
|
|
|
|
|
|
err = bpf_prog_test_run(pkt_fd, 1, &pkt_v6, sizeof(pkt_v6),
|
|
|
|
NULL, NULL, &retval, &duration);
|
|
|
|
CHECK(err || retval, "ipv6",
|
|
|
|
"err %d errno %d retval %d duration %d\n",
|
|
|
|
err, errno, retval, duration);
|
|
|
|
|
2019-12-05 01:06:07 +00:00
|
|
|
err = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result);
|
2019-11-14 18:57:20 +00:00
|
|
|
if (CHECK(err, "get_result",
|
|
|
|
"failed to get output data: %d\n", err))
|
|
|
|
goto close_prog;
|
|
|
|
|
2019-12-05 01:06:07 +00:00
|
|
|
for (i = 0; i < prog_cnt; i++)
|
2020-08-13 20:49:38 +00:00
|
|
|
if (CHECK(result[i] != 1, "result", "fexit_bpf2bpf failed err %llu\n",
|
2019-11-14 18:57:20 +00:00
|
|
|
result[i]))
|
|
|
|
goto close_prog;
|
|
|
|
|
|
|
|
close_prog:
|
2019-12-05 01:06:07 +00:00
|
|
|
for (i = 0; i < prog_cnt; i++)
|
2019-11-14 18:57:20 +00:00
|
|
|
if (!IS_ERR_OR_NULL(link[i]))
|
|
|
|
bpf_link__destroy(link[i]);
|
|
|
|
if (!IS_ERR_OR_NULL(obj))
|
|
|
|
bpf_object__close(obj);
|
|
|
|
bpf_object__close(pkt_obj);
|
2019-12-05 01:06:07 +00:00
|
|
|
free(link);
|
|
|
|
free(prog);
|
|
|
|
free(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_target_no_callees(void)
|
|
|
|
{
|
|
|
|
const char *prog_name[] = {
|
|
|
|
"fexit/test_pkt_md_access",
|
|
|
|
};
|
|
|
|
test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o",
|
|
|
|
"./test_pkt_md_access.o",
|
|
|
|
ARRAY_SIZE(prog_name),
|
2020-04-24 13:34:28 +00:00
|
|
|
prog_name, true);
|
2019-12-05 01:06:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_target_yes_callees(void)
|
|
|
|
{
|
|
|
|
const char *prog_name[] = {
|
|
|
|
"fexit/test_pkt_access",
|
|
|
|
"fexit/test_pkt_access_subprog1",
|
|
|
|
"fexit/test_pkt_access_subprog2",
|
2020-01-10 06:41:21 +00:00
|
|
|
"fexit/test_pkt_access_subprog3",
|
2019-12-05 01:06:07 +00:00
|
|
|
};
|
|
|
|
test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
|
|
|
|
"./test_pkt_access.o",
|
|
|
|
ARRAY_SIZE(prog_name),
|
2020-04-24 13:34:28 +00:00
|
|
|
prog_name, true);
|
2019-12-05 01:06:07 +00:00
|
|
|
}
|
|
|
|
|
2020-01-21 00:53:48 +00:00
|
|
|
static void test_func_replace(void)
|
|
|
|
{
|
|
|
|
const char *prog_name[] = {
|
|
|
|
"fexit/test_pkt_access",
|
|
|
|
"fexit/test_pkt_access_subprog1",
|
|
|
|
"fexit/test_pkt_access_subprog2",
|
|
|
|
"fexit/test_pkt_access_subprog3",
|
|
|
|
"freplace/get_skb_len",
|
|
|
|
"freplace/get_skb_ifindex",
|
|
|
|
"freplace/get_constant",
|
2020-08-25 23:20:01 +00:00
|
|
|
"freplace/test_pkt_write_access_subprog",
|
2020-01-21 00:53:48 +00:00
|
|
|
};
|
|
|
|
test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
|
|
|
|
"./test_pkt_access.o",
|
|
|
|
ARRAY_SIZE(prog_name),
|
2020-04-24 13:34:28 +00:00
|
|
|
prog_name, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_func_replace_verify(void)
|
|
|
|
{
|
|
|
|
const char *prog_name[] = {
|
|
|
|
"freplace/do_bind",
|
|
|
|
};
|
|
|
|
test_fexit_bpf2bpf_common("./freplace_connect4.o",
|
|
|
|
"./connect4_prog.o",
|
|
|
|
ARRAY_SIZE(prog_name),
|
|
|
|
prog_name, false);
|
2020-01-21 00:53:48 +00:00
|
|
|
}
|
|
|
|
|
2020-08-25 23:20:03 +00:00
|
|
|
static void test_func_sockmap_update(void)
|
|
|
|
{
|
|
|
|
const char *prog_name[] = {
|
|
|
|
"freplace/cls_redirect",
|
|
|
|
};
|
|
|
|
test_fexit_bpf2bpf_common("./freplace_cls_redirect.o",
|
|
|
|
"./test_cls_redirect.o",
|
|
|
|
ARRAY_SIZE(prog_name),
|
|
|
|
prog_name, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_obj_load_failure_common(const char *obj_file,
|
|
|
|
const char *target_obj_file)
|
|
|
|
|
2020-08-25 23:20:02 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* standalone test that asserts failure to load freplace prog
|
|
|
|
* because of invalid return code.
|
|
|
|
*/
|
|
|
|
struct bpf_object *obj = NULL, *pkt_obj;
|
|
|
|
int err, pkt_fd;
|
|
|
|
__u32 duration = 0;
|
|
|
|
|
|
|
|
err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC,
|
|
|
|
&pkt_obj, &pkt_fd);
|
|
|
|
/* the target prog should load fine */
|
|
|
|
if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",
|
|
|
|
target_obj_file, err, errno))
|
|
|
|
return;
|
|
|
|
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
|
|
|
|
.attach_prog_fd = pkt_fd,
|
|
|
|
);
|
|
|
|
|
|
|
|
obj = bpf_object__open_file(obj_file, &opts);
|
|
|
|
if (CHECK(IS_ERR_OR_NULL(obj), "obj_open",
|
|
|
|
"failed to open %s: %ld\n", obj_file,
|
|
|
|
PTR_ERR(obj)))
|
|
|
|
goto close_prog;
|
|
|
|
|
|
|
|
/* It should fail to load the program */
|
|
|
|
err = bpf_object__load(obj);
|
|
|
|
if (CHECK(!err, "bpf_obj_load should fail", "err %d\n", err))
|
|
|
|
goto close_prog;
|
|
|
|
|
|
|
|
close_prog:
|
|
|
|
if (!IS_ERR_OR_NULL(obj))
|
|
|
|
bpf_object__close(obj);
|
|
|
|
bpf_object__close(pkt_obj);
|
|
|
|
}
|
|
|
|
|
2020-08-25 23:20:03 +00:00
|
|
|
static void test_func_replace_return_code(void)
|
|
|
|
{
|
|
|
|
/* test invalid return code in the replaced program */
|
|
|
|
test_obj_load_failure_common("./freplace_connect_v4_prog.o",
|
|
|
|
"./connect4_prog.o");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_func_map_prog_compatibility(void)
|
|
|
|
{
|
|
|
|
/* test with spin lock map value in the replaced program */
|
|
|
|
test_obj_load_failure_common("./freplace_attach_probe.o",
|
|
|
|
"./test_attach_probe.o");
|
|
|
|
}
|
|
|
|
|
2019-12-05 01:06:07 +00:00
|
|
|
void test_fexit_bpf2bpf(void)
|
|
|
|
{
|
|
|
|
test_target_no_callees();
|
|
|
|
test_target_yes_callees();
|
2020-01-21 00:53:48 +00:00
|
|
|
test_func_replace();
|
2020-04-24 13:34:28 +00:00
|
|
|
test_func_replace_verify();
|
2020-08-25 23:20:03 +00:00
|
|
|
test_func_sockmap_update();
|
2020-08-25 23:20:02 +00:00
|
|
|
test_func_replace_return_code();
|
2020-08-25 23:20:03 +00:00
|
|
|
test_func_map_prog_compatibility();
|
2019-11-14 18:57:20 +00:00
|
|
|
}
|