Skip to content

Commit 638a3dd

Browse files
mejediKernel Patches Daemon
authored andcommitted
bpftool: Formatting defined by user:fmt: decl tag
Certain data types get exceptionally unwieldy when formatted by bpftool, e.g. IP6 addresses. Introduce custom formatting in bpftool driven by user:fmt: decl tag. When a type is tagged user:fmt:ip, the value is formatted as IP4 or IP6 address depending on the value size. When a type is tagged user:fmt:be, the value is interpreted as a big-endian integer (2, 4 or 8 bytes). Example: typedef struct in6_addr bpf_in6_addr __attribute__((__btf_decl_tag__("user:fmt:ip"))); bpf_in6_addr in6; $ bpftool map dump name .data [{ "value": { ".data": [{ "in6": "2001:db8:130f::9c0:876a:130b" } ] } } ] versus $ bpftool map dump name .data [{ "value": { ".data": [{ "in6": { "in6_u": { "u6_addr8": [32,1,13,184,19,15,0,0,0,0,9,192,135,106,19,11 ], "u6_addr16": [288,47117,3859,0,0,49161,27271,2835 ], "u6_addr32": [3087860000,3859,3221815296,185821831 ] } } } ] } } ] Signed-off-by: Nick Zavaritsky <[email protected]>
1 parent a98c373 commit 638a3dd

File tree

3 files changed

+124
-14
lines changed

3 files changed

+124
-14
lines changed

tools/bpf/bpftool/btf_dumper.c

Lines changed: 106 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <linux/err.h>
1212
#include <bpf/btf.h>
1313
#include <bpf/bpf.h>
14+
#include <errno.h>
15+
#include <arpa/inet.h>
1416

1517
#include "json_writer.h"
1618
#include "main.h"
@@ -132,18 +134,6 @@ static void btf_dumper_ptr(const struct btf_dumper *d,
132134
jsonw_printf(d->jw, "%lu", value);
133135
}
134136

135-
static int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id,
136-
__u8 bit_offset, const void *data)
137-
{
138-
int actual_type_id;
139-
140-
actual_type_id = btf__resolve_type(d->btf, type_id);
141-
if (actual_type_id < 0)
142-
return actual_type_id;
143-
144-
return btf_dumper_do_type(d, actual_type_id, bit_offset, data);
145-
}
146-
147137
static int btf_dumper_enum(const struct btf_dumper *d,
148138
const struct btf_type *t,
149139
const void *data)
@@ -556,6 +546,36 @@ static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
556546
__u8 bit_offset, const void *data)
557547
{
558548
const struct btf_type *t = btf__type_by_id(d->btf, type_id);
549+
char addr[INET6_ADDRSTRLEN];
550+
551+
if (!t)
552+
return -errno;
553+
554+
switch ((bit_offset == 0 && d->fmt_tags) ? d->fmt_tags[type_id] :
555+
BTF_FMT_DEFAULT) {
556+
case BTF_FMT_BE16:
557+
jsonw_printf(d->jw, "\"%d\"",
558+
be16_to_cpu(*(const __be16 *)data));
559+
return 0;
560+
case BTF_FMT_BE32:
561+
jsonw_printf(d->jw, "\"%u\"",
562+
be32_to_cpu(*(const __be32 *)data));
563+
return 0;
564+
case BTF_FMT_BE64:
565+
jsonw_printf(d->jw, "\"%lu\"",
566+
be64_to_cpu(*(const __be64 *)data));
567+
return 0;
568+
case BTF_FMT_IP4:
569+
jsonw_string(d->jw,
570+
inet_ntop(AF_INET, data, addr, sizeof(addr)));
571+
return 0;
572+
case BTF_FMT_IP6:
573+
jsonw_string(d->jw,
574+
inet_ntop(AF_INET6, data, addr, sizeof(addr)));
575+
return 0;
576+
default:
577+
break;
578+
}
559579

560580
switch (BTF_INFO_KIND(t->info)) {
561581
case BTF_KIND_INT:
@@ -584,7 +604,7 @@ static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
584604
case BTF_KIND_VOLATILE:
585605
case BTF_KIND_CONST:
586606
case BTF_KIND_RESTRICT:
587-
return btf_dumper_modifier(d, type_id, bit_offset, data);
607+
return btf_dumper_do_type(d, t->type, bit_offset, data);
588608
case BTF_KIND_VAR:
589609
return btf_dumper_var(d, type_id, bit_offset, data);
590610
case BTF_KIND_DATASEC:
@@ -595,6 +615,79 @@ static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
595615
}
596616
}
597617

618+
enum btf_fmt_tag *btf_fmt_tags_get(const struct btf *btf)
619+
{
620+
int n = btf__type_cnt(btf);
621+
enum btf_fmt_tag *tags = calloc(n, sizeof(tags[0]));
622+
623+
if (!tags)
624+
return NULL;
625+
626+
for (int i = 1; i < n; i++) {
627+
const struct btf_type *t = btf__type_by_id(btf, i);
628+
const struct btf_decl_tag *tag;
629+
const char *name;
630+
__s64 size;
631+
632+
if (!t)
633+
goto err_free;
634+
if (btf_kind(t) != BTF_KIND_DECL_TAG)
635+
continue;
636+
637+
tag = (const void *)(t + 1);
638+
if (tag->component_idx != -1)
639+
continue;
640+
641+
name = btf__name_by_offset(btf, t->name_off);
642+
if (!name)
643+
goto err_free;
644+
645+
#define BTF_FMT_TAG_PREFIX "user:fmt:"
646+
if (strncmp(name, BTF_FMT_TAG_PREFIX,
647+
sizeof(BTF_FMT_TAG_PREFIX) - 1))
648+
continue;
649+
650+
size = btf__resolve_size(btf, t->type);
651+
if (size < 0)
652+
continue; // could be a forward decl
653+
654+
if (btf_kind(btf__type_by_id(btf, t->type)) == BTF_KIND_VAR)
655+
continue;
656+
657+
name += sizeof(BTF_FMT_TAG_PREFIX) - 1;
658+
if (!strcmp(name, "be")) {
659+
switch (size) {
660+
case 2:
661+
tags[t->type] = BTF_FMT_BE16;
662+
break;
663+
case 4:
664+
tags[t->type] = BTF_FMT_BE32;
665+
break;
666+
case 8:
667+
tags[t->type] = BTF_FMT_BE64;
668+
break;
669+
default:
670+
break;
671+
}
672+
} else if (!strcmp(name, "ip")) {
673+
switch (size) {
674+
case 4:
675+
tags[t->type] = BTF_FMT_IP4;
676+
break;
677+
case 16:
678+
tags[t->type] = BTF_FMT_IP6;
679+
break;
680+
default:
681+
break;
682+
}
683+
}
684+
}
685+
return tags;
686+
err_free:
687+
free(tags);
688+
return NULL;
689+
}
690+
598691
int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
599692
const void *data)
600693
{

tools/bpf/bpftool/main.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,20 @@ unsigned int get_possible_cpus(void);
219219
const char *
220220
ifindex_to_arch(__u32 ifindex, __u64 ns_dev, __u64 ns_ino, const char **opt);
221221

222+
enum btf_fmt_tag {
223+
BTF_FMT_DEFAULT = 0,
224+
BTF_FMT_BE16,
225+
BTF_FMT_BE32,
226+
BTF_FMT_BE64,
227+
BTF_FMT_IP4,
228+
BTF_FMT_IP6,
229+
};
230+
231+
enum btf_fmt_tag *btf_fmt_tags_get(const struct btf *btf);
232+
222233
struct btf_dumper {
223234
const struct btf *btf;
235+
const enum btf_fmt_tag *fmt_tags;
224236
json_writer_t *jw;
225237
bool is_plain_text;
226238
bool prog_id_as_func_ptr;

tools/bpf/bpftool/map.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,7 @@ static int do_show(int argc, char **argv)
744744

745745
static int dump_map_elem(int fd, void *key, void *value,
746746
struct bpf_map_info *map_info, struct btf *btf,
747+
const enum btf_fmt_tag *fmt_tags,
747748
json_writer_t *btf_wtr)
748749
{
749750
if (bpf_map_lookup_elem(fd, key, value)) {
@@ -756,6 +757,7 @@ static int dump_map_elem(int fd, void *key, void *value,
756757
} else if (btf) {
757758
struct btf_dumper d = {
758759
.btf = btf,
760+
.fmt_tags = fmt_tags,
759761
.jw = btf_wtr,
760762
.is_plain_text = true,
761763
};
@@ -829,6 +831,7 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
829831
void *key, *value, *prev_key;
830832
unsigned int num_elems = 0;
831833
struct btf *btf = NULL;
834+
enum btf_fmt_tag *fmt_tags = NULL;
832835
int err;
833836

834837
key = malloc(info->key_size);
@@ -846,6 +849,7 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
846849
if (err) {
847850
goto exit_free;
848851
}
852+
fmt_tags = btf_fmt_tags_get(btf);
849853

850854
if (show_header) {
851855
jsonw_start_object(wtr); /* map object */
@@ -872,7 +876,7 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
872876
err = 0;
873877
break;
874878
}
875-
if (!dump_map_elem(fd, key, value, info, btf, wtr))
879+
if (!dump_map_elem(fd, key, value, info, btf, fmt_tags, wtr))
876880
num_elems++;
877881
prev_key = key;
878882
}
@@ -891,6 +895,7 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
891895
free(value);
892896
close(fd);
893897
free_map_kv_btf(btf);
898+
free(fmt_tags);
894899

895900
return err;
896901
}

0 commit comments

Comments
 (0)