Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpftool: Add bpf_cookie to link output

Commit 82e6b1eee6a8 ("bpf: Allow to specify user-provided bpf_cookie for
BPF perf links") introduced the concept of user specified bpf_cookie,
which could be accessed by BPF programs using bpf_get_attach_cookie().
For troubleshooting purposes it is convenient to expose bpf_cookie via
bpftool as well, so there is no need to meddle with the target BPF
program itself.

Implemented using the pid iterator BPF program to actually fetch
bpf_cookies, which allows constraining code changes only to bpftool.

$ bpftool link
1: type 7 prog 5
bpf_cookie 123
pids bootstrap(81)

Signed-off-by: Dmitrii Dolgov <9erthalion6@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Yonghong Song <yhs@fb.com>
Acked-by: Quentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/bpf/20220309163112.24141-1-9erthalion6@gmail.com

authored by

Dmitrii Dolgov and committed by
Andrii Nakryiko
cbdaf71f f98d6dd1

+34
+2
tools/bpf/bpftool/main.h
··· 113 113 114 114 struct obj_refs { 115 115 int ref_cnt; 116 + bool has_bpf_cookie; 116 117 struct obj_ref *refs; 118 + __u64 bpf_cookie; 117 119 }; 118 120 119 121 struct btf;
+8
tools/bpf/bpftool/pids.c
··· 78 78 ref->pid = e->pid; 79 79 memcpy(ref->comm, e->comm, sizeof(ref->comm)); 80 80 refs->ref_cnt = 1; 81 + refs->has_bpf_cookie = e->has_bpf_cookie; 82 + refs->bpf_cookie = e->bpf_cookie; 81 83 82 84 err = hashmap__append(map, u32_as_hash_field(e->id), refs); 83 85 if (err) ··· 207 205 if (refs->ref_cnt == 0) 208 206 break; 209 207 208 + if (refs->has_bpf_cookie) 209 + jsonw_lluint_field(json_writer, "bpf_cookie", refs->bpf_cookie); 210 + 210 211 jsonw_name(json_writer, "pids"); 211 212 jsonw_start_array(json_writer); 212 213 for (i = 0; i < refs->ref_cnt; i++) { ··· 238 233 239 234 if (refs->ref_cnt == 0) 240 235 break; 236 + 237 + if (refs->has_bpf_cookie) 238 + printf("\n\tbpf_cookie %llu", (unsigned long long) refs->bpf_cookie); 241 239 242 240 printf("%s", prefix); 243 241 for (i = 0; i < refs->ref_cnt; i++) {
+22
tools/bpf/bpftool/skeleton/pid_iter.bpf.c
··· 38 38 } 39 39 } 40 40 41 + /* could be used only with BPF_LINK_TYPE_PERF_EVENT links */ 42 + static __u64 get_bpf_cookie(struct bpf_link *link) 43 + { 44 + struct bpf_perf_link *perf_link; 45 + struct perf_event *event; 46 + 47 + perf_link = container_of(link, struct bpf_perf_link, link); 48 + event = BPF_CORE_READ(perf_link, perf_file, private_data); 49 + return BPF_CORE_READ(event, bpf_cookie); 50 + } 51 + 41 52 SEC("iter/task_file") 42 53 int iter(struct bpf_iter__task_file *ctx) 43 54 { ··· 80 69 if (file->f_op != fops) 81 70 return 0; 82 71 72 + __builtin_memset(&e, 0, sizeof(e)); 83 73 e.pid = task->tgid; 84 74 e.id = get_obj_id(file->private_data, obj_type); 75 + 76 + if (obj_type == BPF_OBJ_LINK) { 77 + struct bpf_link *link = (struct bpf_link *) file->private_data; 78 + 79 + if (BPF_CORE_READ(link, type) == BPF_LINK_TYPE_PERF_EVENT) { 80 + e.has_bpf_cookie = true; 81 + e.bpf_cookie = get_bpf_cookie(link); 82 + } 83 + } 84 + 85 85 bpf_probe_read_kernel_str(&e.comm, sizeof(e.comm), 86 86 task->group_leader->comm); 87 87 bpf_seq_write(ctx->meta->seq, &e, sizeof(e));
+2
tools/bpf/bpftool/skeleton/pid_iter.h
··· 6 6 struct pid_iter_entry { 7 7 __u32 id; 8 8 int pid; 9 + __u64 bpf_cookie; 10 + bool has_bpf_cookie; 9 11 char comm[16]; 10 12 }; 11 13