Skip to content

Commit

Permalink
selftests/bpf: Add a test for using a cpumap from an freplace-to-XDP …
Browse files Browse the repository at this point in the history
…program

This adds a simple test for inserting an XDP program into a cpumap that is
"owned" by an XDP program that was loaded as PROG_TYPE_EXT (as libxdp
does). Prior to the kernel fix this would fail because the map type
ownership would be set to PROG_TYPE_EXT instead of being resolved to
PROG_TYPE_XDP.

v3:
- Update comment to better explain the cause
- Add Yonghong's ACK

Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
  • Loading branch information
tohojo authored and Kernel Patches Daemon committed Dec 13, 2022
1 parent 578a534 commit a1e2855
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 2 deletions.
57 changes: 57 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c
Expand Up @@ -500,6 +500,61 @@ static void test_fentry_to_cgroup_bpf(void)
bind4_prog__destroy(skel);
}

static void test_func_replace_progmap(void)
{
struct bpf_cpumap_val value = { .qsize = 1 };
struct bpf_object *obj, *tgt_obj = NULL;
struct bpf_program *drop, *redirect;
struct bpf_map *cpumap;
int err, tgt_fd;
__u32 key = 0;

err = bpf_prog_test_open("freplace_progmap.bpf.o", BPF_PROG_TYPE_UNSPEC, &obj);
if (!ASSERT_OK(err, "prog_open"))
return;

err = bpf_prog_test_load("xdp_dummy.bpf.o", BPF_PROG_TYPE_UNSPEC, &tgt_obj, &tgt_fd);
if (!ASSERT_OK(err, "tgt_prog_load"))
goto out;

drop = bpf_object__find_program_by_name(obj, "xdp_drop_prog");
redirect = bpf_object__find_program_by_name(obj, "xdp_cpumap_prog");
cpumap = bpf_object__find_map_by_name(obj, "cpu_map");

if (!ASSERT_OK_PTR(drop, "drop") || !ASSERT_OK_PTR(redirect, "redirect") ||
!ASSERT_OK_PTR(cpumap, "cpumap"))
goto out;

/* Change the 'redirect' program type to be a PROG_TYPE_EXT
* with an XDP target
*/
bpf_program__set_type(redirect, BPF_PROG_TYPE_EXT);
bpf_program__set_expected_attach_type(redirect, 0);
err = bpf_program__set_attach_target(redirect, tgt_fd, "xdp_dummy_prog");
if (!ASSERT_OK(err, "set_attach_target"))
goto out;

err = bpf_object__load(obj);
if (!ASSERT_OK(err, "obj_load"))
goto out;

/* Prior to fixing the kernel, loading the PROG_TYPE_EXT 'redirect'
* program above will cause the map owner type of 'cpumap' to be set to
* PROG_TYPE_EXT. This in turn will cause the bpf_map_update_elem()
* below to fail, because the program we are inserting into the map is
* of PROG_TYPE_XDP. After fixing the kernel, the initial ownership will
* be correctly resolved to the *target* of the PROG_TYPE_EXT program
* (i.e., PROG_TYPE_XDP) and the map update will succeed.
*/
value.bpf_prog.fd = bpf_program__fd(drop);
err = bpf_map_update_elem(bpf_map__fd(cpumap), &key, &value, 0);
ASSERT_OK(err, "map_update");

out:
bpf_object__close(tgt_obj);
bpf_object__close(obj);
}

/* NOTE: affect other tests, must run in serial mode */
void serial_test_fexit_bpf2bpf(void)
{
Expand All @@ -525,4 +580,6 @@ void serial_test_fexit_bpf2bpf(void)
test_func_replace_global_func();
if (test__start_subtest("fentry_to_cgroup_bpf"))
test_fentry_to_cgroup_bpf();
if (test__start_subtest("func_replace_progmap"))
test_func_replace_progmap();
}
24 changes: 24 additions & 0 deletions tools/testing/selftests/bpf/progs/freplace_progmap.c
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct {
__uint(type, BPF_MAP_TYPE_CPUMAP);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(struct bpf_cpumap_val));
__uint(max_entries, 1);
} cpu_map SEC(".maps");

SEC("xdp/cpumap")
int xdp_drop_prog(struct xdp_md *ctx)
{
return XDP_DROP;
}

SEC("xdp")
int xdp_cpumap_prog(struct xdp_md *ctx)
{
return bpf_redirect_map(&cpu_map, 0, XDP_PASS);
}

char _license[] SEC("license") = "GPL";
24 changes: 22 additions & 2 deletions tools/testing/selftests/bpf/testing_helpers.c
Expand Up @@ -174,8 +174,8 @@ __u32 link_info_prog_id(const struct bpf_link *link, struct bpf_link_info *info)

int extra_prog_load_log_flags = 0;

int bpf_prog_test_load(const char *file, enum bpf_prog_type type,
struct bpf_object **pobj, int *prog_fd)
int bpf_prog_test_open(const char *file, enum bpf_prog_type type,
struct bpf_object **pobj)
{
LIBBPF_OPTS(bpf_object_open_opts, opts,
.kernel_log_level = extra_prog_load_log_flags,
Expand All @@ -201,6 +201,26 @@ int bpf_prog_test_load(const char *file, enum bpf_prog_type type,
flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32;
bpf_program__set_flags(prog, flags);

*pobj = obj;
return 0;
err_out:
bpf_object__close(obj);
return err;
}

int bpf_prog_test_load(const char *file, enum bpf_prog_type type,
struct bpf_object **pobj, int *prog_fd)
{
struct bpf_program *prog;
struct bpf_object *obj;
int err;

err = bpf_prog_test_open(file, type, &obj);
if (err)
return err;

prog = bpf_object__next_program(obj, NULL);

err = bpf_object__load(obj);
if (err)
goto err_out;
Expand Down
2 changes: 2 additions & 0 deletions tools/testing/selftests/bpf/testing_helpers.h
Expand Up @@ -6,6 +6,8 @@

int parse_num_list(const char *s, bool **set, int *set_len);
__u32 link_info_prog_id(const struct bpf_link *link, struct bpf_link_info *info);
int bpf_prog_test_open(const char *file, enum bpf_prog_type type,
struct bpf_object **pobj);
int bpf_prog_test_load(const char *file, enum bpf_prog_type type,
struct bpf_object **pobj, int *prog_fd);
int bpf_test_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
Expand Down

0 comments on commit a1e2855

Please sign in to comment.