| // SPDX-License-Identifier: GPL-2.0-only |
| |
| /* |
| * Copyright 2020 Google LLC. |
| */ |
| |
| #include <test_progs.h> |
| #include <cgroup_helpers.h> |
| #include <network_helpers.h> |
| |
| #include "metadata_unused.skel.h" |
| #include "metadata_used.skel.h" |
| |
| static int duration; |
| |
| static int prog_holds_map(int prog_fd, int map_fd) |
| { |
| struct bpf_prog_info prog_info = {}; |
| struct bpf_map_info map_info = {}; |
| __u32 prog_info_len; |
| __u32 map_info_len; |
| __u32 *map_ids; |
| int nr_maps; |
| int ret; |
| int i; |
| |
| map_info_len = sizeof(map_info); |
| ret = bpf_map_get_info_by_fd(map_fd, &map_info, &map_info_len); |
| if (ret) |
| return -errno; |
| |
| prog_info_len = sizeof(prog_info); |
| ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); |
| if (ret) |
| return -errno; |
| |
| map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32)); |
| if (!map_ids) |
| return -ENOMEM; |
| |
| nr_maps = prog_info.nr_map_ids; |
| memset(&prog_info, 0, sizeof(prog_info)); |
| prog_info.nr_map_ids = nr_maps; |
| prog_info.map_ids = ptr_to_u64(map_ids); |
| prog_info_len = sizeof(prog_info); |
| |
| ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); |
| if (ret) { |
| ret = -errno; |
| goto free_map_ids; |
| } |
| |
| ret = -ENOENT; |
| for (i = 0; i < prog_info.nr_map_ids; i++) { |
| if (map_ids[i] == map_info.id) { |
| ret = 0; |
| break; |
| } |
| } |
| |
| free_map_ids: |
| free(map_ids); |
| return ret; |
| } |
| |
| static void test_metadata_unused(void) |
| { |
| struct metadata_unused *obj; |
| int err; |
| |
| obj = metadata_unused__open_and_load(); |
| if (CHECK(!obj, "skel-load", "errno %d", errno)) |
| return; |
| |
| err = prog_holds_map(bpf_program__fd(obj->progs.prog), |
| bpf_map__fd(obj->maps.rodata)); |
| if (CHECK(err, "prog-holds-rodata", "errno: %d", err)) |
| return; |
| |
| /* Assert that we can access the metadata in skel and the values are |
| * what we expect. |
| */ |
| if (CHECK(strncmp(obj->rodata->bpf_metadata_a, "foo", |
| sizeof(obj->rodata->bpf_metadata_a)), |
| "bpf_metadata_a", "expected \"foo\", value differ")) |
| goto close_bpf_object; |
| if (CHECK(obj->rodata->bpf_metadata_b != 1, "bpf_metadata_b", |
| "expected 1, got %d", obj->rodata->bpf_metadata_b)) |
| goto close_bpf_object; |
| |
| /* Assert that binding metadata map to prog again succeeds. */ |
| err = bpf_prog_bind_map(bpf_program__fd(obj->progs.prog), |
| bpf_map__fd(obj->maps.rodata), NULL); |
| CHECK(err, "rebind_map", "errno %d, expected 0", errno); |
| |
| close_bpf_object: |
| metadata_unused__destroy(obj); |
| } |
| |
| static void test_metadata_used(void) |
| { |
| struct metadata_used *obj; |
| int err; |
| |
| obj = metadata_used__open_and_load(); |
| if (CHECK(!obj, "skel-load", "errno %d", errno)) |
| return; |
| |
| err = prog_holds_map(bpf_program__fd(obj->progs.prog), |
| bpf_map__fd(obj->maps.rodata)); |
| if (CHECK(err, "prog-holds-rodata", "errno: %d", err)) |
| return; |
| |
| /* Assert that we can access the metadata in skel and the values are |
| * what we expect. |
| */ |
| if (CHECK(strncmp(obj->rodata->bpf_metadata_a, "bar", |
| sizeof(obj->rodata->bpf_metadata_a)), |
| "metadata_a", "expected \"bar\", value differ")) |
| goto close_bpf_object; |
| if (CHECK(obj->rodata->bpf_metadata_b != 2, "metadata_b", |
| "expected 2, got %d", obj->rodata->bpf_metadata_b)) |
| goto close_bpf_object; |
| |
| /* Assert that binding metadata map to prog again succeeds. */ |
| err = bpf_prog_bind_map(bpf_program__fd(obj->progs.prog), |
| bpf_map__fd(obj->maps.rodata), NULL); |
| CHECK(err, "rebind_map", "errno %d, expected 0", errno); |
| |
| close_bpf_object: |
| metadata_used__destroy(obj); |
| } |
| |
| void test_metadata(void) |
| { |
| if (test__start_subtest("unused")) |
| test_metadata_unused(); |
| |
| if (test__start_subtest("used")) |
| test_metadata_used(); |
| } |