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>
|
2020-09-29 12:45:54 +00:00
|
|
|
#include <bpf/btf.h>
|
|
|
|
|
|
|
|
typedef int (*test_cb)(struct bpf_object *obj);
|
|
|
|
|
|
|
|
static int check_data_map(struct bpf_object *obj, int prog_cnt, bool reset)
|
|
|
|
{
|
|
|
|
struct bpf_map *data_map = NULL, *map;
|
|
|
|
__u64 *result = NULL;
|
|
|
|
const int zero = 0;
|
|
|
|
__u32 duration = 0;
|
|
|
|
int ret = -1, i;
|
|
|
|
|
|
|
|
result = malloc((prog_cnt + 32 /* spare */) * sizeof(__u64));
|
|
|
|
if (CHECK(!result, "alloc_memory", "failed to alloc memory"))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
bpf_object__for_each_map(map, obj)
|
|
|
|
if (bpf_map__is_internal(map)) {
|
|
|
|
data_map = map;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (CHECK(!data_map, "find_data_map", "data map not found\n"))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
ret = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result);
|
|
|
|
if (CHECK(ret, "get_result",
|
|
|
|
"failed to get output data: %d\n", ret))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
for (i = 0; i < prog_cnt; i++) {
|
|
|
|
if (CHECK(result[i] != 1, "result",
|
|
|
|
"fexit_bpf2bpf result[%d] failed err %llu\n",
|
|
|
|
i, result[i]))
|
|
|
|
goto out;
|
|
|
|
result[i] = 0;
|
|
|
|
}
|
|
|
|
if (reset) {
|
|
|
|
ret = bpf_map_update_elem(bpf_map__fd(data_map), &zero, result, 0);
|
|
|
|
if (CHECK(ret, "reset_result", "failed to reset result\n"))
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
out:
|
|
|
|
free(result);
|
|
|
|
return ret;
|
|
|
|
}
|
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,
|
2020-09-29 12:45:54 +00:00
|
|
|
bool run_prog,
|
|
|
|
test_cb cb)
|
2019-11-14 18:57:20 +00:00
|
|
|
{
|
2020-09-29 12:45:54 +00:00
|
|
|
struct bpf_object *obj = NULL, *tgt_obj;
|
2019-12-05 01:06:07 +00:00
|
|
|
struct bpf_program **prog = NULL;
|
2020-09-29 12:45:54 +00:00
|
|
|
struct bpf_link **link = 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;
|
2020-09-29 12:45:54 +00:00
|
|
|
int err, tgt_fd, i;
|
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,
|
2020-09-29 12:45:54 +00:00
|
|
|
&tgt_obj, &tgt_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,
|
2020-09-29 12:45:54 +00:00
|
|
|
.attach_prog_fd = tgt_fd,
|
2019-11-14 18:57:20 +00:00
|
|
|
);
|
|
|
|
|
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-09-29 12:45:54 +00:00
|
|
|
if (CHECK(!link || !prog, "alloc_memory", "failed to alloc memory"))
|
2019-12-05 01:06:07 +00:00
|
|
|
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
|
|
|
|
2020-09-29 12:45:54 +00:00
|
|
|
if (cb) {
|
|
|
|
err = cb(obj);
|
|
|
|
if (err)
|
|
|
|
goto close_prog;
|
|
|
|
}
|
2020-04-24 13:34:28 +00:00
|
|
|
|
2020-09-29 12:45:54 +00:00
|
|
|
if (!run_prog)
|
2019-11-14 18:57:20 +00:00
|
|
|
goto close_prog;
|
|
|
|
|
2020-09-29 12:45:54 +00:00
|
|
|
err = bpf_prog_test_run(tgt_fd, 1, &pkt_v6, sizeof(pkt_v6),
|
2019-11-14 18:57:20 +00:00
|
|
|
NULL, NULL, &retval, &duration);
|
|
|
|
CHECK(err || retval, "ipv6",
|
|
|
|
"err %d errno %d retval %d duration %d\n",
|
|
|
|
err, errno, retval, duration);
|
|
|
|
|
2020-09-29 12:45:54 +00:00
|
|
|
if (check_data_map(obj, prog_cnt, false))
|
2019-11-14 18:57:20 +00:00
|
|
|
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);
|
2020-09-29 12:45:54 +00:00
|
|
|
bpf_object__close(tgt_obj);
|
2019-12-05 01:06:07 +00:00
|
|
|
free(link);
|
|
|
|
free(prog);
|
|
|
|
}
|
|
|
|
|
|
|
|
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-09-29 12:45:54 +00:00
|
|
|
prog_name, true, NULL);
|
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-09-29 12:45:54 +00:00
|
|
|
prog_name, true, NULL);
|
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-09-29 12:45:54 +00:00
|
|
|
prog_name, true, NULL);
|
2020-04-24 13:34:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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),
|
2020-09-29 12:45:54 +00:00
|
|
|
prog_name, false, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int test_second_attach(struct bpf_object *obj)
|
|
|
|
{
|
|
|
|
const char *prog_name = "freplace/get_constant";
|
|
|
|
const char *tgt_name = prog_name + 9; /* cut off freplace/ */
|
|
|
|
const char *tgt_obj_file = "./test_pkt_access.o";
|
|
|
|
struct bpf_program *prog = NULL;
|
|
|
|
struct bpf_object *tgt_obj;
|
|
|
|
__u32 duration = 0, retval;
|
|
|
|
struct bpf_link *link;
|
|
|
|
int err = 0, tgt_fd;
|
|
|
|
|
|
|
|
prog = bpf_object__find_program_by_title(obj, prog_name);
|
|
|
|
if (CHECK(!prog, "find_prog", "prog %s not found\n", prog_name))
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
err = bpf_prog_load(tgt_obj_file, BPF_PROG_TYPE_UNSPEC,
|
|
|
|
&tgt_obj, &tgt_fd);
|
|
|
|
if (CHECK(err, "second_prog_load", "file %s err %d errno %d\n",
|
|
|
|
tgt_obj_file, err, errno))
|
|
|
|
return err;
|
|
|
|
|
|
|
|
link = bpf_program__attach_freplace(prog, tgt_fd, tgt_name);
|
|
|
|
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))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
err = bpf_prog_test_run(tgt_fd, 1, &pkt_v6, sizeof(pkt_v6),
|
|
|
|
NULL, NULL, &retval, &duration);
|
|
|
|
if (CHECK(err || retval, "ipv6",
|
|
|
|
"err %d errno %d retval %d duration %d\n",
|
|
|
|
err, errno, retval, duration))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
err = check_data_map(obj, 1, true);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
out:
|
|
|
|
bpf_link__destroy(link);
|
|
|
|
bpf_object__close(tgt_obj);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_func_replace_multi(void)
|
|
|
|
{
|
|
|
|
const char *prog_name[] = {
|
|
|
|
"freplace/get_constant",
|
|
|
|
};
|
|
|
|
test_fexit_bpf2bpf_common("./freplace_get_constant.o",
|
|
|
|
"./test_pkt_access.o",
|
|
|
|
ARRAY_SIZE(prog_name),
|
|
|
|
prog_name, true, test_second_attach);
|
2020-01-21 00:53:48 +00:00
|
|
|
}
|
|
|
|
|
2020-09-29 12:45:57 +00:00
|
|
|
static void test_fmod_ret_freplace(void)
|
|
|
|
{
|
|
|
|
struct bpf_object *freplace_obj = NULL, *pkt_obj, *fmod_obj = NULL;
|
|
|
|
const char *freplace_name = "./freplace_get_constant.o";
|
|
|
|
const char *fmod_ret_name = "./fmod_ret_freplace.o";
|
|
|
|
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
|
|
|
|
const char *tgt_name = "./test_pkt_access.o";
|
|
|
|
struct bpf_link *freplace_link = NULL;
|
|
|
|
struct bpf_program *prog;
|
|
|
|
__u32 duration = 0;
|
|
|
|
int err, pkt_fd;
|
|
|
|
|
|
|
|
err = bpf_prog_load(tgt_name, 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",
|
|
|
|
tgt_name, err, errno))
|
|
|
|
return;
|
|
|
|
opts.attach_prog_fd = pkt_fd;
|
|
|
|
|
|
|
|
freplace_obj = bpf_object__open_file(freplace_name, &opts);
|
|
|
|
if (CHECK(IS_ERR_OR_NULL(freplace_obj), "freplace_obj_open",
|
|
|
|
"failed to open %s: %ld\n", freplace_name,
|
|
|
|
PTR_ERR(freplace_obj)))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
err = bpf_object__load(freplace_obj);
|
|
|
|
if (CHECK(err, "freplace_obj_load", "err %d\n", err))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
prog = bpf_program__next(NULL, freplace_obj);
|
|
|
|
freplace_link = bpf_program__attach_trace(prog);
|
|
|
|
if (CHECK(IS_ERR(freplace_link), "freplace_attach_trace", "failed to link\n"))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
opts.attach_prog_fd = bpf_program__fd(prog);
|
|
|
|
fmod_obj = bpf_object__open_file(fmod_ret_name, &opts);
|
|
|
|
if (CHECK(IS_ERR_OR_NULL(fmod_obj), "fmod_obj_open",
|
|
|
|
"failed to open %s: %ld\n", fmod_ret_name,
|
|
|
|
PTR_ERR(fmod_obj)))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
err = bpf_object__load(fmod_obj);
|
|
|
|
if (CHECK(!err, "fmod_obj_load", "loading fmod_ret should fail\n"))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
out:
|
|
|
|
bpf_link__destroy(freplace_link);
|
|
|
|
bpf_object__close(freplace_obj);
|
|
|
|
bpf_object__close(fmod_obj);
|
|
|
|
bpf_object__close(pkt_obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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),
|
2020-09-29 12:45:54 +00:00
|
|
|
prog_name, false, NULL);
|
2020-08-25 23:20:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2020-09-03 20:35:39 +00:00
|
|
|
if (test__start_subtest("target_no_callees"))
|
|
|
|
test_target_no_callees();
|
|
|
|
if (test__start_subtest("target_yes_callees"))
|
|
|
|
test_target_yes_callees();
|
|
|
|
if (test__start_subtest("func_replace"))
|
|
|
|
test_func_replace();
|
|
|
|
if (test__start_subtest("func_replace_verify"))
|
|
|
|
test_func_replace_verify();
|
|
|
|
if (test__start_subtest("func_sockmap_update"))
|
|
|
|
test_func_sockmap_update();
|
|
|
|
if (test__start_subtest("func_replace_return_code"))
|
|
|
|
test_func_replace_return_code();
|
|
|
|
if (test__start_subtest("func_map_prog_compatibility"))
|
|
|
|
test_func_map_prog_compatibility();
|
2020-09-29 12:45:54 +00:00
|
|
|
if (test__start_subtest("func_replace_multi"))
|
|
|
|
test_func_replace_multi();
|
2020-09-29 12:45:57 +00:00
|
|
|
if (test__start_subtest("fmod_ret_freplace"))
|
|
|
|
test_fmod_ret_freplace();
|
2019-11-14 18:57:20 +00:00
|
|
|
}
|