Skip to content

Commit 8fcce61

Browse files
fomichevkernel-patches-bot
authored andcommitted
From: YiFei Zhu <[email protected]>
Dump metadata in the 'bpftool prog' list if it's present. For some formatting some BTF code is put directly in the metadata dumping. Sanity checks on the map and the kind of the btf_type to make sure we are actually dumping what we are expecting. A helper jsonw_reset is added to json writer so we can reuse the same json writer without having extraneous commas. Sample output: $ bpftool prog 6: cgroup_skb name prog tag bcf7977d3b93787c gpl [...] btf_id 4 metadata: a = "foo" b = 1 $ bpftool prog --json --pretty [{ "id": 6, [...] "btf_id": 4, "metadata": { "a": "foo", "b": 1 } } ] Cc: YiFei Zhu <[email protected]> Signed-off-by: YiFei Zhu <[email protected]> Signed-off-by: Stanislav Fomichev <[email protected]> --- tools/bpf/bpftool/json_writer.c | 6 + tools/bpf/bpftool/json_writer.h | 3 + tools/bpf/bpftool/prog.c | 222 ++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+)
1 parent a5d169d commit 8fcce61

File tree

3 files changed

+231
-0
lines changed

3 files changed

+231
-0
lines changed

tools/bpf/bpftool/json_writer.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ void jsonw_pretty(json_writer_t *self, bool on)
119119
self->pretty = on;
120120
}
121121

122+
void jsonw_reset(json_writer_t *self)
123+
{
124+
assert(self->depth == 0);
125+
self->sep = '\0';
126+
}
127+
122128
/* Basic blocks */
123129
static void jsonw_begin(json_writer_t *self, int c)
124130
{

tools/bpf/bpftool/json_writer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ void jsonw_destroy(json_writer_t **self_p);
2727
/* Cause output to have pretty whitespace */
2828
void jsonw_pretty(json_writer_t *self, bool on);
2929

30+
/* Reset separator to create new JSON */
31+
void jsonw_reset(json_writer_t *self);
32+
3033
/* Add property name */
3134
void jsonw_name(json_writer_t *self, const char *name);
3235

tools/bpf/bpftool/prog.c

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
#include "main.h"
3030
#include "xlated_dumper.h"
3131

32+
#define BPF_METADATA_PREFIX "bpf_metadata_"
33+
#define BPF_METADATA_PREFIX_LEN strlen(BPF_METADATA_PREFIX)
34+
3235
const char * const prog_type_name[] = {
3336
[BPF_PROG_TYPE_UNSPEC] = "unspec",
3437
[BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter",
@@ -151,6 +154,221 @@ static void show_prog_maps(int fd, __u32 num_maps)
151154
}
152155
}
153156

157+
static int bpf_prog_find_metadata(int prog_fd, int *map_id)
158+
{
159+
struct bpf_prog_info prog_info = {};
160+
struct bpf_map_info map_info;
161+
__u32 prog_info_len;
162+
__u32 map_info_len;
163+
int saved_errno;
164+
__u32 *map_ids;
165+
int nr_maps;
166+
int map_fd;
167+
int ret;
168+
__u32 i;
169+
170+
prog_info_len = sizeof(prog_info);
171+
172+
ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
173+
if (ret)
174+
return ret;
175+
176+
if (!prog_info.nr_map_ids) {
177+
errno = ENOENT;
178+
return -1;
179+
}
180+
181+
map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32));
182+
if (!map_ids) {
183+
errno = ENOMEM;
184+
return -1;
185+
}
186+
187+
nr_maps = prog_info.nr_map_ids;
188+
memset(&prog_info, 0, sizeof(prog_info));
189+
prog_info.nr_map_ids = nr_maps;
190+
prog_info.map_ids = ptr_to_u64(map_ids);
191+
prog_info_len = sizeof(prog_info);
192+
193+
ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
194+
if (ret)
195+
goto free_map_ids;
196+
197+
for (i = 0; i < prog_info.nr_map_ids; i++) {
198+
map_fd = bpf_map_get_fd_by_id(map_ids[i]);
199+
if (map_fd < 0) {
200+
ret = -1;
201+
goto free_map_ids;
202+
}
203+
204+
memset(&map_info, 0, sizeof(map_info));
205+
map_info_len = sizeof(map_info);
206+
ret = bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len);
207+
208+
saved_errno = errno;
209+
close(map_fd);
210+
errno = saved_errno;
211+
if (ret)
212+
goto free_map_ids;
213+
214+
if (map_info.type != BPF_MAP_TYPE_ARRAY)
215+
continue;
216+
if (map_info.key_size != sizeof(int))
217+
continue;
218+
if (map_info.max_entries != 1)
219+
continue;
220+
if (!map_info.btf_value_type_id)
221+
continue;
222+
if (!strstr(map_info.name, ".rodata"))
223+
continue;
224+
225+
*map_id = map_ids[i];
226+
goto free_map_ids;
227+
}
228+
229+
ret = -1;
230+
errno = ENOENT;
231+
232+
free_map_ids:
233+
saved_errno = errno;
234+
free(map_ids);
235+
errno = saved_errno;
236+
return ret;
237+
}
238+
239+
static bool has_metadata_prefix(const char *s)
240+
{
241+
return strstr(s, BPF_METADATA_PREFIX) == s;
242+
}
243+
244+
static void show_prog_metadata(int fd, __u32 num_maps)
245+
{
246+
const struct btf_type *t_datasec, *t_var;
247+
struct bpf_map_info map_info = {};
248+
struct btf_var_secinfo *vsi;
249+
bool printed_header = false;
250+
struct btf *btf = NULL;
251+
unsigned int i, vlen;
252+
__u32 map_info_len;
253+
void *value = NULL;
254+
const char *name;
255+
int map_id = 0;
256+
int key = 0;
257+
int map_fd;
258+
int err;
259+
260+
if (!num_maps)
261+
return;
262+
263+
err = bpf_prog_find_metadata(fd, &map_id);
264+
if (err < 0)
265+
return;
266+
267+
map_fd = bpf_map_get_fd_by_id(map_id);
268+
if (map_fd < 0)
269+
return;
270+
271+
map_info_len = sizeof(map_info);
272+
err = bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len);
273+
if (err)
274+
goto out_close;
275+
276+
value = malloc(map_info.value_size);
277+
if (!value)
278+
goto out_close;
279+
280+
if (bpf_map_lookup_elem(map_fd, &key, value))
281+
goto out_free;
282+
283+
err = btf__get_from_id(map_info.btf_id, &btf);
284+
if (err || !btf)
285+
goto out_free;
286+
287+
t_datasec = btf__type_by_id(btf, map_info.btf_value_type_id);
288+
if (!btf_is_datasec(t_datasec))
289+
goto out_free;
290+
291+
vlen = btf_vlen(t_datasec);
292+
vsi = btf_var_secinfos(t_datasec);
293+
294+
/* We don't proceed to check the kinds of the elements of the DATASEC.
295+
* The verifier enforces them to be BTF_KIND_VAR.
296+
*/
297+
298+
if (json_output) {
299+
struct btf_dumper d = {
300+
.btf = btf,
301+
.jw = json_wtr,
302+
.is_plain_text = false,
303+
};
304+
305+
for (i = 0; i < vlen; i++, vsi++) {
306+
t_var = btf__type_by_id(btf, vsi->type);
307+
name = btf__name_by_offset(btf, t_var->name_off);
308+
309+
if (!has_metadata_prefix(name))
310+
continue;
311+
312+
if (!printed_header) {
313+
jsonw_name(json_wtr, "metadata");
314+
jsonw_start_object(json_wtr);
315+
printed_header = true;
316+
}
317+
318+
jsonw_name(json_wtr, name + BPF_METADATA_PREFIX_LEN);
319+
err = btf_dumper_type(&d, t_var->type, value + vsi->offset);
320+
if (err) {
321+
p_err("btf dump failed: %d", err);
322+
break;
323+
}
324+
}
325+
if (printed_header)
326+
jsonw_end_object(json_wtr);
327+
} else {
328+
json_writer_t *btf_wtr = jsonw_new(stdout);
329+
struct btf_dumper d = {
330+
.btf = btf,
331+
.jw = btf_wtr,
332+
.is_plain_text = true,
333+
};
334+
if (!btf_wtr) {
335+
p_err("jsonw alloc failed");
336+
goto out_free;
337+
}
338+
339+
for (i = 0; i < vlen; i++, vsi++) {
340+
t_var = btf__type_by_id(btf, vsi->type);
341+
name = btf__name_by_offset(btf, t_var->name_off);
342+
343+
if (!has_metadata_prefix(name))
344+
continue;
345+
346+
if (!printed_header) {
347+
printf("\tmetadata:");
348+
printed_header = true;
349+
}
350+
351+
printf("\n\t\t%s = ", name + BPF_METADATA_PREFIX_LEN);
352+
353+
jsonw_reset(btf_wtr);
354+
err = btf_dumper_type(&d, t_var->type, value + vsi->offset);
355+
if (err) {
356+
p_err("btf dump failed: %d", err);
357+
break;
358+
}
359+
}
360+
if (printed_header)
361+
jsonw_destroy(&btf_wtr);
362+
}
363+
364+
out_free:
365+
btf__free(btf);
366+
free(value);
367+
368+
out_close:
369+
close(map_fd);
370+
}
371+
154372
static void print_prog_header_json(struct bpf_prog_info *info)
155373
{
156374
jsonw_uint_field(json_wtr, "id", info->id);
@@ -228,6 +446,8 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
228446

229447
emit_obj_refs_json(&refs_table, info->id, json_wtr);
230448

449+
show_prog_metadata(fd, info->nr_map_ids);
450+
231451
jsonw_end_object(json_wtr);
232452
}
233453

@@ -297,6 +517,8 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
297517
emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
298518

299519
printf("\n");
520+
521+
show_prog_metadata(fd, info->nr_map_ids);
300522
}
301523

302524
static int show_prog(int fd)

0 commit comments

Comments
 (0)