1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
// 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]);
}
}
}
|