145 lines
3.5 KiB
C
145 lines
3.5 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
#include <bpftool_helpers.h>
|
|
#include <test_progs.h>
|
|
#include <linux/bpf.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <stdbool.h>
|
|
|
|
#define BPFFS_DIR "/sys/fs/bpf/test_metadata"
|
|
#define BPFFS_USED BPFFS_DIR "/used"
|
|
#define BPFFS_UNUSED BPFFS_DIR "/unused"
|
|
|
|
#define BPF_FILE_USED "metadata_used.bpf.o"
|
|
#define BPF_FILE_UNUSED "metadata_unused.bpf.o"
|
|
#define METADATA_MAP_NAME "metadata.rodata"
|
|
|
|
#define MAX_BPFTOOL_OUTPUT_LEN (64*1024)
|
|
|
|
#define MAX_TOKENS_TO_CHECK 3
|
|
static char output[MAX_BPFTOOL_OUTPUT_LEN];
|
|
|
|
struct test_desc {
|
|
char *name;
|
|
char *bpf_prog;
|
|
char *bpffs_path;
|
|
char *expected_output[MAX_TOKENS_TO_CHECK];
|
|
char *expected_output_json[MAX_TOKENS_TO_CHECK];
|
|
char *metadata_map_name;
|
|
};
|
|
|
|
static int setup(struct test_desc *test)
|
|
{
|
|
return mkdir(BPFFS_DIR, 0700);
|
|
}
|
|
|
|
static void cleanup(struct test_desc *test)
|
|
{
|
|
unlink(test->bpffs_path);
|
|
rmdir(BPFFS_DIR);
|
|
}
|
|
|
|
static int check_metadata(char *buf, char * const *tokens, int count)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < count && tokens[i]; i++)
|
|
if (!strstr(buf, tokens[i]))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void run_test(struct test_desc *test)
|
|
{
|
|
int ret;
|
|
char cmd[MAX_BPFTOOL_CMD_LEN];
|
|
|
|
ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "prog load %s %s",
|
|
test->bpf_prog, test->bpffs_path);
|
|
if (!ASSERT_GT(ret, 0, "format prog insert command"))
|
|
return;
|
|
ret = run_bpftool_command(cmd);
|
|
if (!ASSERT_OK(ret, "load program"))
|
|
return;
|
|
|
|
/* Check output with default format */
|
|
ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "prog show pinned %s",
|
|
test->bpffs_path);
|
|
if (!ASSERT_GT(ret, 0, "format pinned prog check command"))
|
|
return;
|
|
ret = get_bpftool_command_output(cmd, output,
|
|
MAX_BPFTOOL_OUTPUT_LEN);
|
|
if (ASSERT_OK(ret, "get program info")) {
|
|
ret = check_metadata(output, test->expected_output,
|
|
ARRAY_SIZE(test->expected_output));
|
|
ASSERT_OK(ret, "find metadata");
|
|
}
|
|
|
|
/* Check output with json format */
|
|
ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "prog -j show pinned %s",
|
|
test->bpffs_path);
|
|
if (!ASSERT_GT(ret, 0, "format pinned prog check command in json"))
|
|
return;
|
|
ret = get_bpftool_command_output(cmd, output,
|
|
MAX_BPFTOOL_OUTPUT_LEN);
|
|
if (ASSERT_OK(ret, "get program info in json")) {
|
|
ret = check_metadata(output, test->expected_output_json,
|
|
ARRAY_SIZE(test->expected_output_json));
|
|
ASSERT_OK(ret, "find metadata in json");
|
|
}
|
|
|
|
/* Check that the corresponding map can be found and accessed */
|
|
ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "map show name %s",
|
|
test->metadata_map_name);
|
|
if (!ASSERT_GT(ret, 0, "format map check command"))
|
|
return;
|
|
ASSERT_OK(run_bpftool_command(cmd), "access metadata map");
|
|
}
|
|
|
|
static struct test_desc tests[] = {
|
|
{
|
|
.name = "metadata_unused",
|
|
.bpf_prog = BPF_FILE_UNUSED,
|
|
.bpffs_path = BPFFS_UNUSED,
|
|
.expected_output = {
|
|
"a = \"foo\"",
|
|
"b = 1"
|
|
},
|
|
.expected_output_json = {
|
|
"\"metadata\":{\"a\":\"foo\",\"b\":1}"
|
|
},
|
|
.metadata_map_name = METADATA_MAP_NAME
|
|
},
|
|
{
|
|
.name = "metadata_used",
|
|
.bpf_prog = BPF_FILE_USED,
|
|
.bpffs_path = BPFFS_USED,
|
|
.expected_output = {
|
|
"a = \"bar\"",
|
|
"b = 2"
|
|
},
|
|
.expected_output_json = {
|
|
"\"metadata\":{\"a\":\"bar\",\"b\":2}"
|
|
},
|
|
.metadata_map_name = METADATA_MAP_NAME
|
|
}
|
|
};
|
|
static const int tests_count = ARRAY_SIZE(tests);
|
|
|
|
void test_bpftool_metadata(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < tests_count; i++) {
|
|
if (!test__start_subtest(tests[i].name))
|
|
continue;
|
|
if (ASSERT_OK(setup(&tests[i]), "setup bpffs pin dir")) {
|
|
run_test(&tests[i]);
|
|
cleanup(&tests[i]);
|
|
}
|
|
}
|
|
}
|