Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libbpf-tools: modernize all tools to libbpf 1.0 mode #3761

Merged
merged 40 commits into from
Dec 20, 2021

Conversation

anakryiko
Copy link
Contributor

This PR updates all current libbpf tools to "libbpf 1.0" by setting:

libbpf_set_strict_mode(LIBBPF_STRICT_ALL);

This turns on stricter checks in libbpf, such as stricter section names for BPF programs. It also simplifies and unifies error handling. There is no more special non-NULL error pointers returned and no need to use libbpf_get_error() to extract it. Just check for NULL and use errno to fetch error code, if necessary.

One common change was also in perf_buffer__new() API. All tools are updated to libbpf 1.0 variant of that API, which is more extensible and will stay the same when libbpf 1.0 is released.

Additionaly, there are some nice usability improvements:

  • all APIs now either return NULL (for pointer returning) or actual error code directly (not -1). Additionally, errno is always set to the same error as well;
  • multiple BPF programs with the same SEC() are supported;
  • libbpf will determine if kernel needs setrlimit() and will bump it automatically, if necessary.

I've tested all the tools as much as I could. For a few I made sure they start up successfully (but didn't see any output). But for most, I've made sure that output looks sane.

I've also fixed cpufreq tool, as it was broken on my machine. See clamp_umax trick to ensure that Clang won't generate too optimized code that BPF verifier can't understand.

See the following for more details:

SEC("tp_btf/cpu_frequency")
int BPF_PROG(cpu_frequency, unsigned int state, unsigned int cpu_id)
{
if (cpu_id >= MAX_CPU_NR)
return 0;

clamp_umax(cpu_id, MAX_CPU_NR - 1);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't repro this locally. Could you please try:

freqs_mhz[cpu_id & (MAX_CPU_NR - 1)] = state / 1000;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably Clang version differences. Try building recent Clang from sources, maybe? Anding with MAX_CPU_NR - 1 was the first thing I did, it didn't help, unfortunately, which made go with this BPF assembly helper approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yonghong-song FYI, I've tried cpu_id & (MAX_CPU_NR - 1) and did barrier_var(), but it didn't help. Could be some other corner case in Clang. The problem is the usual copying of registers, checking one of them, but then using another for indexing into the array.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am using latest clang, it seems the problem is fixed.

[yhs@devbig309.ftw3 ~/work/bcc/libbpf-tools] sudo bpftool prog dump xlated id 59580
int cpu_frequency(unsigned long long * ctx):
; int BPF_PROG(cpu_frequency, unsigned int state, unsigned int cpu_id)
   0: (79) r2 = *(u64 *)(r1 +8)
   1: (bf) r3 = r2
   2: (67) r3 <<= 32
   3: (77) r3 >>= 32
; if (cpu_id >= MAX_CPU_NR)
   4: (25) if r3 > 0x7f goto pc+13
; int BPF_PROG(cpu_frequency, unsigned int state, unsigned int cpu_id)
   5: (79) r1 = *(u64 *)(r1 +0)
; clamp_umax(cpu_id, MAX_CPU_NR - 1);
   6: (b5) if r2 <= 0x7f goto pc+1
   7: (b7) r2 = 127
; freqs_mhz[cpu_id] = state / 1000;
   8: (67) r2 <<= 32
   9: (77) r2 >>= 32
  10: (67) r2 <<= 2
  11: (18) r3 = map[id:31804][0]+0
  13: (0f) r3 += r2
; int BPF_PROG(cpu_frequency, unsigned int state, unsigned int cpu_id)
  14: (67) r1 <<= 32
  15: (77) r1 >>= 32
; freqs_mhz[cpu_id] = state / 1000;
  16: (37) r1 /= 1000
; freqs_mhz[cpu_id] = state / 1000;
  17: (63) *(u32 *)(r3 +0) = r1
; int BPF_PROG(cpu_frequency, unsigned int state, unsigned int cpu_id)
  18: (b7) r0 = 0
  19: (95) exit

So this probably an old clang issue. Could you do a double check?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anakryiko I just pushed a commit to sync with latest libbpf. You can rebase on top of the latest master branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yonghong-song, you are right, I had Clang from Nov 19th and it wasn't new enough. Pulling the very latest and rebuilding fixes the issue.

I think leaving clamp_umax() is still good and will make libbpf-tools buildable by wider variety of Clang versions, but let me know if you think I should drop that patch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, my bad, I haven't updated master properly to undo my fix. Re-doing everything, made sure I have latest Clang built. I have BCC state right before my patches, built everything and ran cpufreq. It is still broken.

$ clang --version
clang version 14.0.0 (https://github.com/llvm/llvm-project.git de904900600f11a65cdf44023061600b668e9df5)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/andriin/bin

$ sudo ./cpufreq
libbpf: prog 'cpu_frequency': BPF program load failed: Permission denied
libbpf: prog 'cpu_frequency': -- BEGIN PROG LOAD LOG --
R1 type=ctx expected=fp
; int BPF_PROG(cpu_frequency, unsigned int state, unsigned int cpu_id)
0: (79) r2 = *(u64 *)(r1 +8)
1: (18) r3 = 0xffffff80
; if (cpu_id >= MAX_CPU_NR)
3: (bf) r4 = r2
4: (5f) r4 &= r3
; if (cpu_id >= MAX_CPU_NR)
5: (55) if r4 != 0x0 goto pc+11
 R1=ctx(id=0,off=0,imm=0) R2_w=inv(id=1) R3_w=inv4294967168 R4_w=inv0 R10=fp0
;
6: (67) r2 <<= 32
7: (77) r2 >>= 32
; freqs_mhz[cpu_id] = state / 1000;
8: (67) r2 <<= 2
9: (18) r3 = 0xffffc9000ceaa000
11: (0f) r3 += r2
last_idx 11 first_idx 0
regs=4 stack=0 before 9: (18) r3 = 0xffffc9000ceaa000
regs=4 stack=0 before 8: (67) r2 <<= 2
regs=4 stack=0 before 7: (77) r2 >>= 32
regs=4 stack=0 before 6: (67) r2 <<= 32
regs=4 stack=0 before 5: (55) if r4 != 0x0 goto pc+11
regs=4 stack=0 before 4: (5f) r4 &= r3
regs=4 stack=0 before 3: (bf) r4 = r2
regs=4 stack=0 before 1: (18) r3 = 0xffffff80
regs=4 stack=0 before 0: (79) r2 = *(u64 *)(r1 +8)
; int BPF_PROG(cpu_frequency, unsigned int state, unsigned int cpu_id)
12: (79) r1 = *(u64 *)(r1 +0)
13: (67) r1 <<= 32
14: (77) r1 >>= 32
; freqs_mhz[cpu_id] = state / 1000;
15: (37) r1 /= 1000
; freqs_mhz[cpu_id] = state / 1000;
16: (63) *(u32 *)(r3 +0) = r1
 R1_w=inv(id=0) R2_w=invP(id=0,umax_value=17179869180,var_off=(0x0; 0x3fffffffc),s32_max_value=2147483644,u32_max_value=-4) R3_w=map_value(id=0,off=0,ks=4,vs=720,umax_value=17179869180,var_off=(0x0; 0x3fffffffc),s32_max_value=2147483644,u32_max_value=-4) R4_w=inv0 R10=fp0
R3 unbounded memory access, make sure to bounds check any such access
processed 15 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
-- END PROG LOAD LOG --
libbpf: failed to load program 'cpu_frequency'
libbpf: failed to load object 'cpufreq_bpf'
libbpf: failed to load BPF skeleton 'cpufreq_bpf': -13
failed to open and/or load BPF object

@davemarchevsky
Copy link
Collaborator

aside from ongoing cpufreq convo, rest of changes LGTM

We need up-to-date bpftool to support skeletons with multiple BPF programs per
SEC().

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage
accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Also fix cachestat.bpf.c by adding a BPF assembly trick to ensure that
BPF verifier sees proper value bounds for cpu ID.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Switch to libbpf 1.0 mode and adapt libbpf API usage accordingly.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
libbpf will now automatically decide whether it's necessary, and if yes,
will do it on behalf of the application.

All the subsequet tools should make sure to set:

```
libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
```

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
@anakryiko anakryiko force-pushed the libbpf-tools-modernize branch from bcc27ef to 5d8f5c4 Compare December 20, 2021 21:22
@davemarchevsky davemarchevsky merged commit 629d40a into iovisor:master Dec 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants