mirror of https://gitee.com/openkylin/linux.git
selftests: Add test for multiple attachments of freplace program
This adds a selftest for attaching an freplace program to multiple targets simultaneously. Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Andrii Nakryiko <andriin@fb.com> Link: https://lore.kernel.org/bpf/160138355497.48470.17568077161540217107.stgit@toke.dk
This commit is contained in:
parent
a535909142
commit
f6429476c2
|
@ -2,36 +2,79 @@
|
|||
/* Copyright (c) 2019 Facebook */
|
||||
#include <test_progs.h>
|
||||
#include <network_helpers.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
static void test_fexit_bpf2bpf_common(const char *obj_file,
|
||||
const char *target_obj_file,
|
||||
int prog_cnt,
|
||||
const char **prog_name,
|
||||
bool run_prog)
|
||||
bool run_prog,
|
||||
test_cb cb)
|
||||
{
|
||||
struct bpf_object *obj = NULL, *pkt_obj;
|
||||
int err, pkt_fd, i;
|
||||
struct bpf_link **link = NULL;
|
||||
struct bpf_object *obj = NULL, *tgt_obj;
|
||||
struct bpf_program **prog = NULL;
|
||||
struct bpf_link **link = NULL;
|
||||
__u32 duration = 0, retval;
|
||||
struct bpf_map *data_map;
|
||||
const int zero = 0;
|
||||
__u64 *result = NULL;
|
||||
int err, tgt_fd, i;
|
||||
|
||||
err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC,
|
||||
&pkt_obj, &pkt_fd);
|
||||
&tgt_obj, &tgt_fd);
|
||||
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,
|
||||
.attach_prog_fd = tgt_fd,
|
||||
);
|
||||
|
||||
link = calloc(sizeof(struct bpf_link *), prog_cnt);
|
||||
prog = calloc(sizeof(struct bpf_program *), prog_cnt);
|
||||
result = malloc((prog_cnt + 32 /* spare */) * sizeof(__u64));
|
||||
if (CHECK(!link || !prog || !result, "alloc_memory",
|
||||
"failed to alloc memory"))
|
||||
if (CHECK(!link || !prog, "alloc_memory", "failed to alloc memory"))
|
||||
goto close_prog;
|
||||
|
||||
obj = bpf_object__open_file(obj_file, &opts);
|
||||
|
@ -53,27 +96,22 @@ static void test_fexit_bpf2bpf_common(const char *obj_file,
|
|||
goto close_prog;
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
err = cb(obj);
|
||||
if (err)
|
||||
goto close_prog;
|
||||
}
|
||||
|
||||
if (!run_prog)
|
||||
goto close_prog;
|
||||
|
||||
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),
|
||||
err = bpf_prog_test_run(tgt_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);
|
||||
|
||||
err = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result);
|
||||
if (CHECK(err, "get_result",
|
||||
"failed to get output data: %d\n", err))
|
||||
goto close_prog;
|
||||
|
||||
for (i = 0; i < prog_cnt; i++)
|
||||
if (CHECK(result[i] != 1, "result", "fexit_bpf2bpf failed err %llu\n",
|
||||
result[i]))
|
||||
if (check_data_map(obj, prog_cnt, false))
|
||||
goto close_prog;
|
||||
|
||||
close_prog:
|
||||
|
@ -82,10 +120,9 @@ static void test_fexit_bpf2bpf_common(const char *obj_file,
|
|||
bpf_link__destroy(link[i]);
|
||||
if (!IS_ERR_OR_NULL(obj))
|
||||
bpf_object__close(obj);
|
||||
bpf_object__close(pkt_obj);
|
||||
bpf_object__close(tgt_obj);
|
||||
free(link);
|
||||
free(prog);
|
||||
free(result);
|
||||
}
|
||||
|
||||
static void test_target_no_callees(void)
|
||||
|
@ -96,7 +133,7 @@ static void test_target_no_callees(void)
|
|||
test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o",
|
||||
"./test_pkt_md_access.o",
|
||||
ARRAY_SIZE(prog_name),
|
||||
prog_name, true);
|
||||
prog_name, true, NULL);
|
||||
}
|
||||
|
||||
static void test_target_yes_callees(void)
|
||||
|
@ -110,7 +147,7 @@ static void test_target_yes_callees(void)
|
|||
test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
|
||||
"./test_pkt_access.o",
|
||||
ARRAY_SIZE(prog_name),
|
||||
prog_name, true);
|
||||
prog_name, true, NULL);
|
||||
}
|
||||
|
||||
static void test_func_replace(void)
|
||||
|
@ -128,7 +165,7 @@ static void test_func_replace(void)
|
|||
test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
|
||||
"./test_pkt_access.o",
|
||||
ARRAY_SIZE(prog_name),
|
||||
prog_name, true);
|
||||
prog_name, true, NULL);
|
||||
}
|
||||
|
||||
static void test_func_replace_verify(void)
|
||||
|
@ -139,7 +176,60 @@ static void test_func_replace_verify(void)
|
|||
test_fexit_bpf2bpf_common("./freplace_connect4.o",
|
||||
"./connect4_prog.o",
|
||||
ARRAY_SIZE(prog_name),
|
||||
prog_name, false);
|
||||
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);
|
||||
}
|
||||
|
||||
static void test_func_sockmap_update(void)
|
||||
|
@ -150,7 +240,7 @@ static void test_func_sockmap_update(void)
|
|||
test_fexit_bpf2bpf_common("./freplace_cls_redirect.o",
|
||||
"./test_cls_redirect.o",
|
||||
ARRAY_SIZE(prog_name),
|
||||
prog_name, false);
|
||||
prog_name, false, NULL);
|
||||
}
|
||||
|
||||
static void test_obj_load_failure_common(const char *obj_file,
|
||||
|
@ -222,4 +312,6 @@ void test_fexit_bpf2bpf(void)
|
|||
test_func_replace_return_code();
|
||||
if (test__start_subtest("func_map_prog_compatibility"))
|
||||
test_func_map_prog_compatibility();
|
||||
if (test__start_subtest("func_replace_multi"))
|
||||
test_func_replace_multi();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
|
||||
volatile __u64 test_get_constant = 0;
|
||||
SEC("freplace/get_constant")
|
||||
int new_get_constant(long val)
|
||||
{
|
||||
if (val != 123)
|
||||
return 0;
|
||||
test_get_constant = 1;
|
||||
return test_get_constant; /* original get_constant() returns val - 122 */
|
||||
}
|
||||
char _license[] SEC("license") = "GPL";
|
Loading…
Reference in New Issue