Closed FelixMcFelix closed 2 years ago
Some notes from looking into this. I had a look at sockex3_kern.c to see how this should be compiling. Tailcalls are in section socket/0
(i.e., main_prog with parse_eth_proto inlined):
$ llvm-objdump --section=socket/0 sockex3_kern.o --disassemble
sockex3_kern.o: file format elf64-bpf
Disassembly of section socket/0:
0000000000000000 <main_prog>:
0: bf 16 00 00 00 00 00 00 r6 = r1
1: 28 00 00 00 0c 00 00 00 r0 = *(u16 *)skb[12]
2: b7 01 00 00 0e 00 00 00 r1 = 14
3: 63 16 30 00 00 00 00 00 *(u32 *)(r6 + 48) = r1
4: b7 03 00 00 01 00 00 00 r3 = 1
5: 67 00 00 00 20 00 00 00 r0 <<= 32
6: 77 00 00 00 20 00 00 00 r0 >>= 32
7: 65 00 06 00 46 88 00 00 if r0 s> 34886 goto +6 <LBB4_4>
8: 15 00 0d 00 00 08 00 00 if r0 == 2048 goto +13 <LBB4_7>
9: 15 00 0d 00 00 81 00 00 if r0 == 33024 goto +13 <LBB4_9>
10: 15 00 01 00 dd 86 00 00 if r0 == 34525 goto +1 <LBB4_8>
11: 05 00 0f 00 00 00 00 00 goto +15 <LBB4_10>
0000000000000060 <LBB4_8>:
12: b7 03 00 00 04 00 00 00 r3 = 4
13: 05 00 09 00 00 00 00 00 goto +9 <LBB4_9>
0000000000000070 <LBB4_4>:
14: bf 01 00 00 00 00 00 00 r1 = r0
15: 07 01 00 00 b9 77 ff ff r1 += -34887
16: b7 02 00 00 02 00 00 00 r2 = 2
17: 2d 12 02 00 00 00 00 00 if r2 > r1 goto +2 <LBB4_6>
18: 15 00 04 00 a8 88 00 00 if r0 == 34984 goto +4 <LBB4_9>
19: 05 00 07 00 00 00 00 00 goto +7 <LBB4_10>
00000000000000a0 <LBB4_6>:
20: b7 03 00 00 02 00 00 00 r3 = 2
21: 05 00 01 00 00 00 00 00 goto +1 <LBB4_9>
00000000000000b0 <LBB4_7>:
22: b7 03 00 00 03 00 00 00 r3 = 3
00000000000000b8 <LBB4_9>:
23: bf 61 00 00 00 00 00 00 r1 = r6
24: 18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r2 = 0 ll
26: 85 00 00 00 0c 00 00 00 call 12
00000000000000d8 <LBB4_10>:
27: b7 00 00 00 00 00 00 00 r0 = 0
28: 95 00 00 00 00 00 00 00 exit
Here, the compiler seems to deliberately preserve ctx
in R6 rather than recomputing it relative to R10 (=FP). An equivalent C program to the above (i.e., using XDP instead) also recognises that R1 already suffices, rather than recomputing it:
Disassembly of section socket/0:
0000000000000000 <main_prog>:
0: 18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r2 = 0 ll
2: b7 03 00 00 00 00 00 00 r3 = 0
3: 85 00 00 00 0c 00 00 00 call 12
4: b7 00 00 00 00 00 00 00 r0 = 0
5: 95 00 00 00 00 00 00 00 exit
I'll try and poke around to see if there's a way to make the redbpf compiler behave itself here.
I realised that the solution is to extract the inner parameter:
let tail_call_succ = unsafe {progs_map.tail_call(ctx.ctx, out as u32)};
Hopefully this helps someone in future!
I'm trying to get XDP tail calls working through redbpf binaries, but they seem to be failing at the verification stage. A simple example below (double braces are used due to string interpolation on the source files elsewhere):
Fails to load with the following output:
I've tried this with packet processing functions of various complexity, but the verifier consistently fails to realise that
fp-<offset>
has typectx
-- even though this is obviously and always the case according to the comment in line 0. I'm unsure if this is due to the types in line 2 (i.e. fp-8 vs fp-8_w) -- is there a way to coerce the compiler to do the right thing here? I've tried to temporarily coerce the pointer to a u32 in case it expected it to have type _w, but this was rightfully rejected. Any ideas?cargo-bpf revision: c0b04010bd78ab1b1837346828a4ae63d5759369 LLVM version: 13.0.1 rustc version: 1.59 kernel: 5.18.5-arch1-1