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
|
// SPDX-License-Identifier: GPL-2.0-only
#include <sys/socket.h>
#include <unistd.h>
#include <bpf/btf.h>
#include <test_progs.h>
#include "bpftool_helpers.h"
#define PIN_PATH "/sys/fs/bpf/test_bpftool_map_dump_sk_storage"
#define QUEUE_PIN_PATH "/sys/fs/bpf/test_bpftool_map_dump_queue"
#define JSON_ERROR "{\"error\":\"can't dump sk_storage map"
/* An empty socket storage map with an int value. */
static int create_sk_storage_map(void)
{
LIBBPF_OPTS(bpf_map_create_opts, opts,
.map_flags = BPF_F_NO_PREALLOC);
struct btf *btf;
int int_id, fd = -1;
btf = btf__new_empty();
if (!ASSERT_OK_PTR(btf, "btf__new_empty"))
return -1;
int_id = btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
if (!ASSERT_GT(int_id, 0, "btf__add_int"))
goto out;
if (!ASSERT_OK(btf__load_into_kernel(btf), "btf__load_into_kernel"))
goto out;
opts.btf_fd = btf__fd(btf);
opts.btf_key_type_id = int_id;
opts.btf_value_type_id = int_id;
fd = bpf_map_create(BPF_MAP_TYPE_SK_STORAGE, "sk_storage", sizeof(int),
sizeof(int), 0, &opts);
ASSERT_OK_FD(fd, "bpf_map_create");
out:
btf__free(btf);
return fd;
}
static void test_sk_storage(void)
{
int map_fd, sk_fd = -1, value = 42, ret;
char output[1024] = {};
map_fd = create_sk_storage_map();
if (map_fd < 0)
return;
sk_fd = socket(AF_INET, SOCK_STREAM, 0);
if (!ASSERT_OK_FD(sk_fd, "socket"))
goto out;
if (!ASSERT_OK(bpf_map_update_elem(map_fd, &sk_fd, &value, BPF_NOEXIST),
"add socket storage"))
goto out;
if (!ASSERT_OK(bpf_obj_pin(map_fd, PIN_PATH), "pin map"))
goto out;
/*
* Socket storage can't be iterated, so the dump must fail with an
* error and nothing else, rather than print an empty map that holds
* an element. The buffer is cleared before each run so that a run
* that fails to start can't match stale or uninitialised output.
*/
ret = get_bpftool_command_output("-j map dump pinned " PIN_PATH,
output, sizeof(output));
ASSERT_NEQ(ret, 0, "json dump fails");
ASSERT_STRNEQ(output, JSON_ERROR, strlen(JSON_ERROR),
"json dump is only the error");
memset(output, 0, sizeof(output));
ret = get_bpftool_command_output("map dump pinned " PIN_PATH,
output, sizeof(output));
ASSERT_NEQ(ret, 0, "plain dump fails");
ASSERT_NULL(strchr(output, '['), "plain dump prints no elements");
memset(output, 0, sizeof(output));
get_bpftool_command_output("map dump pinned " PIN_PATH " 2>&1 >/dev/null",
output, sizeof(output));
ASSERT_HAS_SUBSTR(output,
"can't dump sk_storage map: Operation not supported",
"plain dump explains why on stderr");
out:
unlink(PIN_PATH);
if (sk_fd >= 0)
close(sk_fd);
close(map_fd);
}
/*
* A queue map has no BTF, so its plain dump prints an element count
* rather than JSON. A dump that ignored the error would print "Found 0
* elements" for a queue that holds one.
*/
static void test_queue(void)
{
char output[1024] = {};
int map_fd, value = 42, ret;
map_fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, "queue", 0, sizeof(int), 1,
NULL);
if (!ASSERT_OK_FD(map_fd, "bpf_map_create"))
return;
if (!ASSERT_OK(bpf_map_update_elem(map_fd, NULL, &value, BPF_ANY),
"push to queue"))
goto out;
if (!ASSERT_OK(bpf_obj_pin(map_fd, QUEUE_PIN_PATH), "pin map"))
goto out;
ret = get_bpftool_command_output("map dump pinned " QUEUE_PIN_PATH,
output, sizeof(output));
ASSERT_NEQ(ret, 0, "plain dump fails");
ASSERT_NULL(strstr(output, "Found"), "plain dump prints no count");
memset(output, 0, sizeof(output));
get_bpftool_command_output("map dump pinned " QUEUE_PIN_PATH " 2>&1 >/dev/null",
output, sizeof(output));
ASSERT_HAS_SUBSTR(output, "can't dump queue map",
"plain dump explains why on stderr");
out:
unlink(QUEUE_PIN_PATH);
close(map_fd);
}
void test_bpftool_map_dump(void)
{
if (test__start_subtest("sk_storage"))
test_sk_storage();
if (test__start_subtest("queue"))
test_queue();
}
|